From 02eb48aaf5d1f47d02d9b5eeaa310d1acdc76865 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Mon, 9 Feb 2026 22:45:34 +0000 Subject: [PATCH 01/40] feat: start of work --- Cargo.lock | 469 +++++++++++++++++- packages/rs-dpp/src/lib.rs | 1 + packages/rs-dpp/src/shielded/mod.rs | 8 + packages/rs-dpp/src/state_transition/mod.rs | 98 +++- .../state_transition_types.rs | 3 + .../state_transition/state_transitions/mod.rs | 3 + .../state_transitions/shielded/mod.rs | 3 + .../shielded/shield_transition/mod.rs | 60 +++ ...ate_transition_estimated_fee_validation.rs | 20 + .../state_transition_like.rs | 96 ++++ .../state_transition_validation.rs | 19 + .../shielded/shield_transition/v0/mod.rs | 41 ++ .../v0/state_transition_like.rs | 89 ++++ .../v0/state_transition_validation.rs | 14 + .../shielded/shield_transition/v0/types.rs | 16 + .../shielded/shield_transition/v0/version.rs | 9 + .../shielded/shield_transition/version.rs | 11 + .../shielded_transfer_transition/mod.rs | 60 +++ ...ate_transition_estimated_fee_validation.rs | 16 + .../state_transition_like.rs | 47 ++ .../state_transition_validation.rs | 15 + .../shielded_transfer_transition/v0/mod.rs | 33 ++ .../v0/state_transition_like.rs | 49 ++ .../v0/state_transition_validation.rs | 14 + .../shielded_transfer_transition/v0/types.rs | 16 + .../v0/version.rs | 9 + .../shielded_transfer_transition/version.rs | 11 + .../shielded/unshield_transition/mod.rs | 60 +++ ...ate_transition_estimated_fee_validation.rs | 16 + .../state_transition_like.rs | 47 ++ .../state_transition_validation.rs | 15 + .../shielded/unshield_transition/v0/mod.rs | 36 ++ .../v0/state_transition_like.rs | 49 ++ .../v0/state_transition_validation.rs | 14 + .../shielded/unshield_transition/v0/types.rs | 16 + .../unshield_transition/v0/version.rs | 9 + .../shielded/unshield_transition/version.rs | 11 + .../v0/mod.rs | 106 ++++ .../traits/address_balances_and_nonces.rs | 20 +- .../processor/traits/address_witnesses.rs | 12 +- .../traits/addresses_minimum_balance.rs | 11 +- .../processor/traits/basic_structure.rs | 8 +- .../processor/traits/identity_balance.rs | 7 +- .../traits/identity_based_signature.rs | 15 +- .../processor/traits/identity_nonces.rs | 10 +- .../processor/traits/is_allowed.rs | 25 +- .../processor/traits/state.rs | 16 +- .../state_transition/transformer/mod.rs | 15 + packages/rs-drive/Cargo.toml | 12 +- .../rs-drive/src/drive/initialization/mod.rs | 4 +- .../src/drive/initialization/v3/mod.rs | 137 +++++ packages/rs-drive/src/drive/mod.rs | 3 + packages/rs-drive/src/drive/shielded/mod.rs | 3 + packages/rs-drive/src/drive/shielded/paths.rs | 96 ++++ packages/rs-drive/src/fees/op.rs | 1 + .../prove/prove_state_transition/v0/mod.rs | 7 + .../action_convert_to_operations/mod.rs | 10 + .../shielded/mod.rs | 41 ++ .../src/state_transition_action/mod.rs | 14 + .../state_transition_action/shielded/mod.rs | 6 + .../shielded/shield/mod.rs | 59 +++ .../shielded/shield/transformer.rs | 31 ++ .../shielded/shield/v0/mod.rs | 23 + .../shielded/shield/v0/transformer.rs | 26 + .../shielded/shielded_transfer/mod.rs | 55 ++ .../shielded/shielded_transfer/transformer.rs | 31 ++ .../shielded/shielded_transfer/v0/mod.rs | 21 + .../shielded_transfer/v0/transformer.rs | 25 + .../shielded/unshield/mod.rs | 62 +++ .../shielded/unshield/transformer.rs | 28 ++ .../shielded/unshield/v0/mod.rs | 24 + .../shielded/unshield/v0/transformer.rs | 24 + .../grove_insert_empty_tree/v0/mod.rs | 1 + .../v0/mod.rs | 5 + packages/rs-platform-version/Cargo.toml | 2 +- .../mod.rs | 3 + .../v1.rs | 15 + .../v2.rs | 15 + .../drive_abci_validation_versions/mod.rs | 4 + .../drive_abci_validation_versions/v1.rs | 24 + .../drive_abci_validation_versions/v2.rs | 24 + .../drive_abci_validation_versions/v3.rs | 24 + .../drive_abci_validation_versions/v4.rs | 24 + .../drive_abci_validation_versions/v5.rs | 24 + .../drive_abci_validation_versions/v6.rs | 24 + .../drive_abci_validation_versions/v7.rs | 24 + .../mod.rs | 3 + .../v1.rs | 3 + .../v2.rs | 3 + .../src/version/drive_versions/mod.rs | 1 + .../src/version/drive_versions/v7.rs | 118 +++++ .../feature_initial_protocol_versions.rs | 1 + .../rs-platform-version/src/version/v12.rs | 6 +- 93 files changed, 2792 insertions(+), 47 deletions(-) create mode 100644 packages/rs-dpp/src/shielded/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/state_transition_estimated_fee_validation.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/state_transition_like.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/state_transition_validation.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_like.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/types.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/version.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/version.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/state_transition_estimated_fee_validation.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/state_transition_like.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/state_transition_validation.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_like.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/types.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/version.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/version.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/state_transition_estimated_fee_validation.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/state_transition_like.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/state_transition_validation.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_like.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/types.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/version.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/version.rs create mode 100644 packages/rs-drive/src/drive/initialization/v3/mod.rs create mode 100644 packages/rs-drive/src/drive/shielded/mod.rs create mode 100644 packages/rs-drive/src/drive/shielded/paths.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/shield/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/unshield/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/unshield/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs create mode 100644 packages/rs-platform-version/src/version/drive_versions/v7.rs diff --git a/Cargo.lock b/Cargo.lock index 4f079ee095e..a8d8d37b2d2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,16 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array 0.14.7", +] + [[package]] name = "aes" version = "0.8.4" @@ -569,6 +579,17 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake2b_simd" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79834656f71332577234b50bfc009996f7449e0c056884e6a02492ded0ca2f3" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq 0.4.2", +] + [[package]] name = "blake3" version = "1.8.2" @@ -579,7 +600,7 @@ dependencies = [ "arrayvec", "cc", "cfg-if", - "constant_time_eq", + "constant_time_eq 0.3.1", ] [[package]] @@ -612,6 +633,17 @@ dependencies = [ "serde", ] +[[package]] +name = "bls12_381" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7bc6d6292be3a19e6379786dac800f551e5865a5bb51ebbe3064ab80433f403" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "blsful" version = "3.0.0" @@ -775,6 +807,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + [[package]] name = "cbindgen" version = "0.27.0" @@ -846,6 +887,30 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + [[package]] name = "check-features" version = "3.0.1" @@ -924,6 +989,7 @@ checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", + "zeroize", ] [[package]] @@ -1062,6 +1128,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + [[package]] name = "convert_case" version = "0.10.0" @@ -1097,6 +1169,15 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "core2" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239fa3ae9b63c2dc74bd3fa852d4792b8b305ae64eeede946265b6af62f1fff3" +dependencies = [ + "memchr", +] + [[package]] name = "core2" version = "0.4.0" @@ -2261,6 +2342,20 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fpe" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c4b37de5ae15812a764c958297cfc50f5c010438f60c6ce75d11b802abd404" +dependencies = [ + "cbc", + "cipher", + "libm", + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "fraction" version = "0.15.3" @@ -2427,6 +2522,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "getset" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf0fc11e47561d47397154977bc219f4cf809b2974facc3ccb3b89e2436f912" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "glob" version = "0.3.3" @@ -2465,6 +2572,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", + "memuse", "rand 0.8.5", "rand_core 0.6.4", "rand_xorshift", @@ -2474,12 +2582,13 @@ dependencies = [ [[package]] name = "grovedb" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=33dfd48a1718160cb333fa95424be491785f1897#33dfd48a1718160cb333fa95424be491785f1897" +source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "axum 0.8.8", "bincode", "bincode_derive", "blake3", + "grovedb-commitment-tree", "grovedb-costs", "grovedb-element", "grovedb-merk", @@ -2504,10 +2613,22 @@ dependencies = [ "zip-extensions", ] +[[package]] +name = "grovedb-commitment-tree" +version = "4.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" +dependencies = [ + "incrementalmerkletree", + "orchard", + "pasta_curves", + "shardtree", + "thiserror 2.0.17", +] + [[package]] name = "grovedb-costs" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=33dfd48a1718160cb333fa95424be491785f1897#33dfd48a1718160cb333fa95424be491785f1897" +source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "integer-encoding", "intmap", @@ -2517,7 +2638,7 @@ dependencies = [ [[package]] name = "grovedb-element" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=33dfd48a1718160cb333fa95424be491785f1897#33dfd48a1718160cb333fa95424be491785f1897" +source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "bincode", "bincode_derive", @@ -2532,7 +2653,7 @@ dependencies = [ [[package]] name = "grovedb-epoch-based-storage-flags" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=33dfd48a1718160cb333fa95424be491785f1897#33dfd48a1718160cb333fa95424be491785f1897" +source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "grovedb-costs", "hex", @@ -2544,7 +2665,7 @@ dependencies = [ [[package]] name = "grovedb-merk" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=33dfd48a1718160cb333fa95424be491785f1897#33dfd48a1718160cb333fa95424be491785f1897" +source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "bincode", "bincode_derive", @@ -2569,7 +2690,7 @@ dependencies = [ [[package]] name = "grovedb-path" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=33dfd48a1718160cb333fa95424be491785f1897#33dfd48a1718160cb333fa95424be491785f1897" +source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "hex", ] @@ -2577,7 +2698,7 @@ dependencies = [ [[package]] name = "grovedb-storage" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=33dfd48a1718160cb333fa95424be491785f1897#33dfd48a1718160cb333fa95424be491785f1897" +source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "blake3", "grovedb-costs", @@ -2596,7 +2717,7 @@ dependencies = [ [[package]] name = "grovedb-version" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=33dfd48a1718160cb333fa95424be491785f1897#33dfd48a1718160cb333fa95424be491785f1897" +source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "thiserror 2.0.17", "versioned-feature-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2605,7 +2726,7 @@ dependencies = [ [[package]] name = "grovedb-visualize" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=33dfd48a1718160cb333fa95424be491785f1897#33dfd48a1718160cb333fa95424be491785f1897" +source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "hex", "itertools 0.14.0", @@ -2614,7 +2735,7 @@ dependencies = [ [[package]] name = "grovedbg-types" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=33dfd48a1718160cb333fa95424be491785f1897#33dfd48a1718160cb333fa95424be491785f1897" +source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "serde", "serde_with 3.16.1", @@ -2650,6 +2771,61 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "halo2_gadgets" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45824ce0dd12e91ec0c68ebae2a7ed8ae19b70946624c849add59f1d1a62a143" +dependencies = [ + "arrayvec", + "bitvec", + "ff", + "group", + "halo2_poseidon", + "halo2_proofs", + "lazy_static", + "pasta_curves", + "rand 0.8.5", + "sinsemilla", + "subtle", + "uint", +] + +[[package]] +name = "halo2_legacy_pdqsort" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47716fe1ae67969c5e0b2ef826f32db8c3be72be325e1aa3c1951d06b5575ec5" + +[[package]] +name = "halo2_poseidon" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa3da60b81f02f9b33ebc6252d766f843291fb4d2247a07ae73d20b791fc56f" +dependencies = [ + "bitvec", + "ff", + "group", + "pasta_curves", +] + +[[package]] +name = "halo2_proofs" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05713f117155643ce10975e0bee44a274bcda2f4bb5ef29a999ad67c1fa8d4d3" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "halo2_legacy_pdqsort", + "indexmap 1.9.3", + "maybe-rayon", + "pasta_curves", + "rand_core 0.6.4", + "tracing", +] + [[package]] name = "hash32" version = "0.3.1" @@ -3143,6 +3319,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "incrementalmerkletree" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30821f91f0fa8660edca547918dc59812893b497d07c1144f326f07fdd94aba9" +dependencies = [ + "either", +] + [[package]] name = "indexmap" version = "1.9.3" @@ -3382,6 +3567,20 @@ dependencies = [ "uuid", ] +[[package]] +name = "jubjub" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8499f7a74008aafbecb2a2e608a3e13e4dd3e84df198b604451efe93f2de6e61" +dependencies = [ + "bitvec", + "bls12_381", + "ff", + "group", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "keccak" version = "0.1.5" @@ -3467,6 +3666,9 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin 0.9.8", +] [[package]] name = "lazycell" @@ -3496,6 +3698,12 @@ dependencies = [ "windows-link", ] +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + [[package]] name = "librocksdb-sys" version = "0.18.0+10.7.5" @@ -3629,12 +3837,28 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + [[package]] name = "memchr" version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +[[package]] +name = "memuse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d97bbf43eb4f088f8ca469930cde17fa036207c9a5e02ccc5107c4e8b17c964" + [[package]] name = "merlin" version = "3.0.0" @@ -3860,6 +4084,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "nonempty" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "549e471b99ccaf2f89101bec68f4d244457d5a95a9c3d0672e9564124397741d" + [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -4045,6 +4275,12 @@ version = "11.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + [[package]] name = "openssl" version = "0.10.75" @@ -4095,6 +4331,42 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "orchard" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c01cd4ea711aab5f263f2b7aa6966687a2d6c7df4f78eb1b97a66a7a4e78e3b" +dependencies = [ + "aes", + "bitvec", + "blake2b_simd", + "core2 0.3.3", + "ff", + "fpe", + "getset", + "group", + "halo2_gadgets", + "halo2_poseidon", + "halo2_proofs", + "hex", + "incrementalmerkletree", + "lazy_static", + "memuse", + "nonempty", + "pasta_curves", + "rand 0.8.5", + "rand_core 0.6.4", + "reddsa", + "serde", + "sinsemilla", + "subtle", + "tracing", + "visibility", + "zcash_note_encryption", + "zcash_spec", + "zip32", +] + [[package]] name = "pairing" version = "0.23.0" @@ -4142,6 +4414,21 @@ dependencies = [ "regex", ] +[[package]] +name = "pasta_curves" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "lazy_static", + "rand 0.8.5", + "static_assertions", + "subtle", +] + [[package]] name = "paste" version = "1.0.15" @@ -4370,6 +4657,17 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + [[package]] name = "portable-atomic" version = "1.13.0" @@ -4474,6 +4772,28 @@ dependencies = [ "toml_edit 0.23.10+spec-1.0.0", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "proc-macro2" version = "1.0.104" @@ -4853,6 +5173,24 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "reddsa" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78a5191930e84973293aa5f532b513404460cd2216c1cfb76d08748c15b40b02" +dependencies = [ + "blake2b_simd", + "byteorder", + "group", + "hex", + "jubjub", + "pasta_curves", + "rand_core 0.6.4", + "serde", + "thiserror 1.0.69", + "zeroize", +] + [[package]] name = "redox_syscall" version = "0.5.18" @@ -5836,6 +6174,18 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shardtree" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "637e95dcd06bc1bb3f86ed9db1e1832a70125f32daae071ef37dcb7701b7d4fe" +dependencies = [ + "bitflags 2.10.0", + "either", + "incrementalmerkletree", + "tracing", +] + [[package]] name = "shlex" version = "1.3.0" @@ -5884,6 +6234,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "sinsemilla" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d268ae0ea06faafe1662e9967cd4f9022014f5eeb798e0c302c876df8b7af9c" +dependencies = [ + "group", + "pasta_curves", + "subtle", +] + [[package]] name = "siphasher" version = "1.0.1" @@ -5928,6 +6289,12 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "spin" version = "0.10.0" @@ -5959,6 +6326,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "std-shims" version = "0.1.5" @@ -5967,7 +6340,7 @@ checksum = "227c4f8561598188d0df96dbe749824576174bba278b5b6bb2eacff1066067d0" dependencies = [ "hashbrown 0.16.1", "rustversion", - "spin", + "spin 0.10.0", ] [[package]] @@ -6925,13 +7298,25 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + [[package]] name = "uint-zigzag" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abbf77aed65cb885a8ba07138c365879be3d9a93dce82bf6cc50feca9138ec15" dependencies = [ - "core2", + "core2 0.4.0", ] [[package]] @@ -6967,6 +7352,16 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + [[package]] name = "untrusted" version = "0.9.0" @@ -7091,6 +7486,17 @@ version = "0.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1" +[[package]] +name = "visibility" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "vsss-rs" version = "5.1.0" @@ -7848,6 +8254,28 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zcash_note_encryption" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77efec759c3798b6e4d829fcc762070d9b229b0f13338c40bf993b7b609c2272" +dependencies = [ + "chacha20", + "chacha20poly1305", + "cipher", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "zcash_spec" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded3f58b93486aa79b85acba1001f5298f27a46489859934954d262533ee2915" +dependencies = [ + "blake2b_simd", +] + [[package]] name = "zerocopy" version = "0.8.31" @@ -7974,7 +8402,7 @@ checksum = "eb2a05c7c36fde6c09b08576c9f7fb4cda705990f73b58fe011abf7dfb24168b" dependencies = [ "aes", "arbitrary", - "constant_time_eq", + "constant_time_eq 0.3.1", "crc32fast", "flate2", "getrandom 0.3.4", @@ -8012,6 +8440,19 @@ dependencies = [ "zip 6.0.0", ] +[[package]] +name = "zip32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b64bf5186a8916f7a48f2a98ef599bf9c099e2458b36b819e393db1c0e768c4b" +dependencies = [ + "bech32 0.11.1", + "blake2b_simd", + "memuse", + "subtle", + "zcash_spec", +] + [[package]] name = "zlib-rs" version = "0.5.5" diff --git a/packages/rs-dpp/src/lib.rs b/packages/rs-dpp/src/lib.rs index d160ad35b99..e73fb05c251 100644 --- a/packages/rs-dpp/src/lib.rs +++ b/packages/rs-dpp/src/lib.rs @@ -73,6 +73,7 @@ pub mod core_types; pub mod address_funds; pub mod group; +pub mod shielded; pub mod withdrawal; pub use async_trait; diff --git a/packages/rs-dpp/src/shielded/mod.rs b/packages/rs-dpp/src/shielded/mod.rs new file mode 100644 index 00000000000..cbf5881ef7e --- /dev/null +++ b/packages/rs-dpp/src/shielded/mod.rs @@ -0,0 +1,8 @@ +use bincode::{Decode, Encode}; + +/// Parameters for a shielded pool, stored as an Item in the pool's subtree +#[derive(Debug, Clone, Encode, Decode, Default, PartialEq)] +pub struct ShieldedPoolParams { + /// Counter for commitment tree checkpoint IDs (monotonically increasing) + pub checkpoint_id_counter: u64, +} diff --git a/packages/rs-dpp/src/state_transition/mod.rs b/packages/rs-dpp/src/state_transition/mod.rs index 8f41b601ded..e437d6b3766 100644 --- a/packages/rs-dpp/src/state_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/mod.rs @@ -136,8 +136,15 @@ use crate::state_transition::identity_update_transition::{ }; use crate::state_transition::masternode_vote_transition::MasternodeVoteTransition; use crate::state_transition::masternode_vote_transition::MasternodeVoteTransitionSignable; +use crate::state_transition::shield_transition::{ShieldTransition, ShieldTransitionSignable}; +use crate::state_transition::shielded_transfer_transition::{ + ShieldedTransferTransition, ShieldedTransferTransitionSignable, +}; #[cfg(feature = "state-transition-signing")] use crate::state_transition::state_transitions::document::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; +use crate::state_transition::unshield_transition::{ + UnshieldTransition, UnshieldTransitionSignable, +}; use state_transitions::document::batch_transition::batched_transition::token_transition::TokenTransition; pub use state_transitions::*; @@ -162,6 +169,9 @@ macro_rules! call_method { StateTransition::AddressFundsTransfer(st) => st.$method($args), StateTransition::AddressFundingFromAssetLock(st) => st.$method($args), StateTransition::AddressCreditWithdrawal(st) => st.$method($args), + StateTransition::Shield(st) => st.$method($args), + StateTransition::ShieldedTransfer(st) => st.$method($args), + StateTransition::Unshield(st) => st.$method($args), } }; ($state_transition:expr, $method:ident ) => { @@ -181,6 +191,9 @@ macro_rules! call_method { StateTransition::AddressFundsTransfer(st) => st.$method(), StateTransition::AddressFundingFromAssetLock(st) => st.$method(), StateTransition::AddressCreditWithdrawal(st) => st.$method(), + StateTransition::Shield(st) => st.$method(), + StateTransition::ShieldedTransfer(st) => st.$method(), + StateTransition::Unshield(st) => st.$method(), } }; } @@ -203,6 +216,9 @@ macro_rules! call_getter_method_identity_signed { StateTransition::AddressFundsTransfer(_) => None, StateTransition::AddressFundingFromAssetLock(_) => None, StateTransition::AddressCreditWithdrawal(_) => None, + StateTransition::Shield(_) => None, + StateTransition::ShieldedTransfer(_) => None, + StateTransition::Unshield(_) => None, } }; ($state_transition:expr, $method:ident ) => { @@ -222,6 +238,9 @@ macro_rules! call_getter_method_identity_signed { StateTransition::AddressFundsTransfer(_) => None, StateTransition::AddressFundingFromAssetLock(_) => None, StateTransition::AddressCreditWithdrawal(_) => None, + StateTransition::Shield(_) => None, + StateTransition::ShieldedTransfer(_) => None, + StateTransition::Unshield(_) => None, } }; } @@ -244,6 +263,9 @@ macro_rules! call_method_identity_signed { StateTransition::AddressFundsTransfer(_) => {} StateTransition::AddressFundingFromAssetLock(_) => {} StateTransition::AddressCreditWithdrawal(_) => {} + StateTransition::Shield(_) => {} + StateTransition::ShieldedTransfer(_) => {} + StateTransition::Unshield(_) => {} } }; ($state_transition:expr, $method:ident ) => { @@ -263,6 +285,9 @@ macro_rules! call_method_identity_signed { StateTransition::AddressFundsTransfer(_) => {} StateTransition::AddressFundingFromAssetLock(_) => {} StateTransition::AddressCreditWithdrawal(_) => {} + StateTransition::Shield(_) => {} + StateTransition::ShieldedTransfer(_) => {} + StateTransition::Unshield(_) => {} } }; } @@ -300,6 +325,15 @@ macro_rules! call_errorable_method_identity_signed { StateTransition::AddressCreditWithdrawal(_) => Err(ProtocolError::CorruptedCodeExecution( "address credit withdrawal can not be called for identity signing".to_string(), )), + StateTransition::Shield(_) => Err(ProtocolError::CorruptedCodeExecution( + "shield transition can not be called for identity signing".to_string(), + )), + StateTransition::ShieldedTransfer(_) => Err(ProtocolError::CorruptedCodeExecution( + "shielded transfer transition can not be called for identity signing".to_string(), + )), + StateTransition::Unshield(_) => Err(ProtocolError::CorruptedCodeExecution( + "unshield transition can not be called for identity signing".to_string(), + )), } }; ($state_transition:expr, $method:ident) => { @@ -333,6 +367,15 @@ macro_rules! call_errorable_method_identity_signed { StateTransition::AddressCreditWithdrawal(_) => Err(ProtocolError::CorruptedCodeExecution( "address credit withdrawal can not be called for identity signing".to_string(), )), + StateTransition::Shield(_) => Err(ProtocolError::CorruptedCodeExecution( + "shield transition can not be called for identity signing".to_string(), + )), + StateTransition::ShieldedTransfer(_) => Err(ProtocolError::CorruptedCodeExecution( + "shielded transfer transition can not be called for identity signing".to_string(), + )), + StateTransition::Unshield(_) => Err(ProtocolError::CorruptedCodeExecution( + "unshield transition can not be called for identity signing".to_string(), + )), } }; } @@ -371,6 +414,9 @@ pub enum StateTransition { AddressFundsTransfer(AddressFundsTransferTransition), AddressFundingFromAssetLock(AddressFundingFromAssetLockTransition), AddressCreditWithdrawal(AddressCreditWithdrawalTransition), + Shield(ShieldTransition), + ShieldedTransfer(ShieldedTransferTransition), + Unshield(UnshieldTransition), } impl OptionallyAssetLockProved for StateTransition { @@ -453,13 +499,20 @@ impl StateTransition { | StateTransition::AddressFundsTransfer(_) | StateTransition::AddressFundingFromAssetLock(_) | StateTransition::AddressCreditWithdrawal(_) => 11..=LATEST_VERSION, + StateTransition::Shield(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => 12..=LATEST_VERSION, } } pub fn is_identity_signed(&self) -> bool { !matches!( self, - StateTransition::IdentityCreate(_) | StateTransition::IdentityTopUp(_) + StateTransition::IdentityCreate(_) + | StateTransition::IdentityTopUp(_) + | StateTransition::Shield(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) ) } @@ -556,6 +609,9 @@ impl StateTransition { Self::AddressFundsTransfer(_) => "AddressFundsTransfer".to_string(), Self::AddressFundingFromAssetLock(_) => "AddressFundingFromAssetLock".to_string(), Self::AddressCreditWithdrawal(_) => "AddressCreditWithdrawal".to_string(), + Self::Shield(_) => "Shield".to_string(), + Self::ShieldedTransfer(_) => "ShieldedTransfer".to_string(), + Self::Unshield(_) => "Unshield".to_string(), } } @@ -577,6 +633,9 @@ impl StateTransition { StateTransition::AddressFundsTransfer(_) => None, StateTransition::AddressFundingFromAssetLock(st) => Some(st.signature()), StateTransition::AddressCreditWithdrawal(_) => None, + StateTransition::Shield(_) => None, + StateTransition::ShieldedTransfer(_) => None, + StateTransition::Unshield(_) => None, } } @@ -587,6 +646,9 @@ impl StateTransition { StateTransition::IdentityTopUpFromAddresses(st) => st.inputs().len() as u16, StateTransition::AddressFundsTransfer(st) => st.inputs().len() as u16, StateTransition::AddressCreditWithdrawal(st) => st.inputs().len() as u16, + StateTransition::Shield(st) => st.inputs().len() as u16, + StateTransition::ShieldedTransfer(_) => 0, + StateTransition::Unshield(_) => 0, _ => 1, } } @@ -655,6 +717,9 @@ impl StateTransition { StateTransition::AddressFundsTransfer(_) => None, StateTransition::AddressFundingFromAssetLock(_) => None, StateTransition::AddressCreditWithdrawal(_) => None, + StateTransition::Shield(_) => None, + StateTransition::ShieldedTransfer(_) => None, + StateTransition::Unshield(_) => None, } } @@ -676,6 +741,9 @@ impl StateTransition { StateTransition::AddressFundsTransfer(st) => Some(st.inputs()), StateTransition::AddressFundingFromAssetLock(st) => Some(st.inputs()), StateTransition::AddressCreditWithdrawal(st) => Some(st.inputs()), + StateTransition::Shield(st) => Some(st.inputs()), + StateTransition::ShieldedTransfer(_) => None, + StateTransition::Unshield(_) => None, } } @@ -734,7 +802,10 @@ impl StateTransition { } StateTransition::IdentityCreateFromAddresses(_) | StateTransition::IdentityTopUpFromAddresses(_) - | StateTransition::AddressFundsTransfer(_) => false, + | StateTransition::AddressFundsTransfer(_) + | StateTransition::Shield(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => false, StateTransition::AddressFundingFromAssetLock(st) => { st.set_signature(signature); true @@ -891,6 +962,22 @@ impl StateTransition { .to_string(), )) } + StateTransition::Shield(_) => { + return Err(ProtocolError::CorruptedCodeExecution( + "shield transition can not be called for identity signing".to_string(), + )) + } + StateTransition::ShieldedTransfer(_) => { + return Err(ProtocolError::CorruptedCodeExecution( + "shielded transfer transition can not be called for identity signing" + .to_string(), + )) + } + StateTransition::Unshield(_) => { + return Err(ProtocolError::CorruptedCodeExecution( + "unshield transition can not be called for identity signing".to_string(), + )) + } } let data = self.signable_bytes()?; self.set_signature(signer.sign(identity_public_key, data.as_slice())?); @@ -1228,6 +1315,13 @@ impl StateTransitionStructureValidation for StateTransition { StateTransition::AddressCreditWithdrawal(transition) => { transition.validate_structure(platform_version) } + StateTransition::Shield(transition) => transition.validate_structure(platform_version), + StateTransition::ShieldedTransfer(transition) => { + transition.validate_structure(platform_version) + } + StateTransition::Unshield(transition) => { + transition.validate_structure(platform_version) + } } } } diff --git a/packages/rs-dpp/src/state_transition/state_transition_types.rs b/packages/rs-dpp/src/state_transition/state_transition_types.rs index f8ffaba25d7..ac7e6d2073d 100644 --- a/packages/rs-dpp/src/state_transition/state_transition_types.rs +++ b/packages/rs-dpp/src/state_transition/state_transition_types.rs @@ -35,6 +35,9 @@ pub enum StateTransitionType { AddressFundsTransfer = 12, AddressFundingFromAssetLock = 13, AddressCreditWithdrawal = 14, + Shield = 15, + ShieldedTransfer = 16, + Unshield = 17, } impl std::fmt::Display for StateTransitionType { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/mod.rs index cc748f9bb4d..1ee962d0587 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/mod.rs @@ -9,3 +9,6 @@ pub use address_funds::*; pub use contract::*; pub use document::*; pub use identity::*; + +pub mod shielded; +pub use shielded::*; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/mod.rs new file mode 100644 index 00000000000..1c036289134 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/mod.rs @@ -0,0 +1,3 @@ +pub mod shield_transition; +pub mod shielded_transfer_transition; +pub mod unshield_transition; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/mod.rs new file mode 100644 index 00000000000..4e4d20d66e5 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/mod.rs @@ -0,0 +1,60 @@ +mod state_transition_estimated_fee_validation; +mod state_transition_like; +mod state_transition_validation; +pub mod v0; +mod version; + +use crate::state_transition::shield_transition::v0::ShieldTransitionV0; +use crate::state_transition::shield_transition::v0::ShieldTransitionV0Signable; +use crate::state_transition::StateTransitionFieldTypes; + +use crate::identity::state_transition::OptionallyAssetLockProved; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use derive_more::From; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize, PlatformSignable}; +use platform_versioning::PlatformVersioned; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +#[derive( + Debug, + Clone, + Encode, + Decode, + PlatformDeserialize, + PlatformSerialize, + PlatformSignable, + PlatformVersioned, + From, + PartialEq, +)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(tag = "$version") +)] +#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version +#[platform_version_path_bounds( + "dpp.state_transition_serialization_versions.shield_state_transition" +)] +pub enum ShieldTransition { + #[cfg_attr(feature = "state-transition-serde-conversion", serde(rename = "0"))] + V0(ShieldTransitionV0), +} + +impl OptionallyAssetLockProved for ShieldTransition {} + +impl StateTransitionFieldTypes for ShieldTransition { + fn signature_property_paths() -> Vec<&'static str> { + vec![] + } + + fn identifiers_property_paths() -> Vec<&'static str> { + vec![] + } + + fn binary_property_paths() -> Vec<&'static str> { + vec![] + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/state_transition_estimated_fee_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/state_transition_estimated_fee_validation.rs new file mode 100644 index 00000000000..d8a5d6ce98b --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/state_transition_estimated_fee_validation.rs @@ -0,0 +1,20 @@ +use crate::fee::Credits; +use crate::state_transition::shield_transition::ShieldTransition; +use crate::state_transition::{ + StateTransitionEstimatedFeeValidation, StateTransitionWitnessSigned, +}; +use crate::ProtocolError; +use platform_version::version::PlatformVersion; + +impl StateTransitionEstimatedFeeValidation for ShieldTransition { + fn calculate_min_required_fee( + &self, + platform_version: &PlatformVersion, + ) -> Result { + let min_fees = &platform_version.fee_version.state_transition_min_fees; + let input_count = self.inputs().len(); + Ok(min_fees + .address_funds_transfer_input_cost + .saturating_mul(input_count as u64)) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/state_transition_like.rs new file mode 100644 index 00000000000..089ae4b2749 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/state_transition_like.rs @@ -0,0 +1,96 @@ +use crate::address_funds::AddressWitness; +use crate::prelude::UserFeeIncrease; +use crate::state_transition::shield_transition::ShieldTransition; +use crate::state_transition::{ + StateTransitionLike, StateTransitionType, StateTransitionWitnessSigned, +}; +use crate::version::FeatureVersion; +use platform_value::Identifier; + +impl StateTransitionLike for ShieldTransition { + /// Returns ID of the created contract + fn modified_data_ids(&self) -> Vec { + match self { + ShieldTransition::V0(transition) => transition.modified_data_ids(), + } + } + + fn state_transition_protocol_version(&self) -> FeatureVersion { + match self { + ShieldTransition::V0(_) => 0, + } + } + /// returns the type of State Transition + fn state_transition_type(&self) -> StateTransitionType { + match self { + ShieldTransition::V0(transition) => transition.state_transition_type(), + } + } + + /// returns the fee multiplier + fn user_fee_increase(&self) -> UserFeeIncrease { + match self { + ShieldTransition::V0(transition) => transition.user_fee_increase(), + } + } + /// set a fee multiplier + fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { + match self { + ShieldTransition::V0(transition) => transition.set_user_fee_increase(user_fee_increase), + } + } + + fn unique_identifiers(&self) -> Vec { + match self { + ShieldTransition::V0(transition) => transition.unique_identifiers(), + } + } +} + +impl StateTransitionWitnessSigned for ShieldTransition { + fn inputs( + &self, + ) -> &std::collections::BTreeMap< + crate::address_funds::PlatformAddress, + (crate::prelude::AddressNonce, crate::fee::Credits), + > { + match self { + ShieldTransition::V0(transition) => transition.inputs(), + } + } + + fn inputs_mut( + &mut self, + ) -> &mut std::collections::BTreeMap< + crate::address_funds::PlatformAddress, + (crate::prelude::AddressNonce, crate::fee::Credits), + > { + match self { + ShieldTransition::V0(transition) => transition.inputs_mut(), + } + } + + fn set_inputs( + &mut self, + inputs: std::collections::BTreeMap< + crate::address_funds::PlatformAddress, + (crate::prelude::AddressNonce, crate::fee::Credits), + >, + ) { + match self { + ShieldTransition::V0(transition) => transition.set_inputs(inputs), + } + } + + fn witnesses(&self) -> &Vec { + match self { + ShieldTransition::V0(transition) => transition.witnesses(), + } + } + + fn set_witnesses(&mut self, witnesses: Vec) { + match self { + ShieldTransition::V0(transition) => transition.set_witnesses(witnesses), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/state_transition_validation.rs new file mode 100644 index 00000000000..71d92296f55 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/state_transition_validation.rs @@ -0,0 +1,19 @@ +use crate::state_transition::shield_transition::ShieldTransition; +use crate::state_transition::{ + StateTransitionStructureValidation, StateTransitionWitnessValidation, +}; +use crate::validation::SimpleConsensusValidationResult; +use platform_version::version::PlatformVersion; + +impl StateTransitionStructureValidation for ShieldTransition { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> SimpleConsensusValidationResult { + match self { + ShieldTransition::V0(v0) => v0.validate_structure(platform_version), + } + } +} + +impl StateTransitionWitnessValidation for ShieldTransition {} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs new file mode 100644 index 00000000000..3e82a6919db --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs @@ -0,0 +1,41 @@ +mod state_transition_like; +mod state_transition_validation; +mod types; +mod version; + +use std::collections::BTreeMap; + +use crate::address_funds::{AddressFundsFeeStrategy, AddressWitness, PlatformAddress}; +use crate::fee::Credits; +use crate::prelude::{AddressNonce, UserFeeIncrease}; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize, PlatformSignable}; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +#[derive( + Debug, + Clone, + Encode, + Decode, + PlatformSerialize, + PlatformDeserialize, + PlatformSignable, + PartialEq, +)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +#[platform_serialize(unversioned)] +#[derive(Default)] +pub struct ShieldTransitionV0 { + pub inputs: BTreeMap, + pub orchard_bundle: Vec, + pub fee_strategy: AddressFundsFeeStrategy, + pub user_fee_increase: UserFeeIncrease, + #[platform_signable(exclude_from_sig_hash)] + pub input_witnesses: Vec, +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_like.rs new file mode 100644 index 00000000000..e41278acbdc --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_like.rs @@ -0,0 +1,89 @@ +use crate::address_funds::AddressWitness; +use crate::prelude::UserFeeIncrease; +use crate::state_transition::shield_transition::v0::ShieldTransitionV0; +use crate::state_transition::shield_transition::ShieldTransition; +use crate::{ + prelude::Identifier, + state_transition::{StateTransitionLike, StateTransitionType}, +}; + +use crate::state_transition::StateTransitionType::Shield; +use crate::state_transition::{StateTransition, StateTransitionWitnessSigned}; +use crate::version::FeatureVersion; + +impl From for StateTransition { + fn from(value: ShieldTransitionV0) -> Self { + let shield_transition: ShieldTransition = value.into(); + shield_transition.into() + } +} + +impl StateTransitionLike for ShieldTransitionV0 { + fn state_transition_protocol_version(&self) -> FeatureVersion { + 0 + } + + /// returns the type of State Transition + fn state_transition_type(&self) -> StateTransitionType { + Shield + } + + /// Returns ID of the created contract + fn modified_data_ids(&self) -> Vec { + vec![] + } + + /// State transitions with the same inputs should not be allowed to overlap + fn unique_identifiers(&self) -> Vec { + self.inputs + .iter() + .map(|(key, (nonce, _))| key.base64_string_with_nonce(*nonce)) + .collect() + } + + fn user_fee_increase(&self) -> UserFeeIncrease { + self.user_fee_increase + } + + fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { + self.user_fee_increase = user_fee_increase + } +} + +impl StateTransitionWitnessSigned for ShieldTransitionV0 { + fn inputs( + &self, + ) -> &std::collections::BTreeMap< + crate::address_funds::PlatformAddress, + (crate::prelude::AddressNonce, crate::fee::Credits), + > { + &self.inputs + } + + fn inputs_mut( + &mut self, + ) -> &mut std::collections::BTreeMap< + crate::address_funds::PlatformAddress, + (crate::prelude::AddressNonce, crate::fee::Credits), + > { + &mut self.inputs + } + + fn set_inputs( + &mut self, + inputs: std::collections::BTreeMap< + crate::address_funds::PlatformAddress, + (crate::prelude::AddressNonce, crate::fee::Credits), + >, + ) { + self.inputs = inputs; + } + + fn witnesses(&self) -> &Vec { + &self.input_witnesses + } + + fn set_witnesses(&mut self, witnesses: Vec) { + self.input_witnesses = witnesses; + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs new file mode 100644 index 00000000000..f5f82472ae9 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs @@ -0,0 +1,14 @@ +use crate::state_transition::shield_transition::v0::ShieldTransitionV0; +use crate::state_transition::StateTransitionStructureValidation; +use crate::validation::SimpleConsensusValidationResult; +use platform_version::version::PlatformVersion; + +impl StateTransitionStructureValidation for ShieldTransitionV0 { + fn validate_structure( + &self, + _platform_version: &PlatformVersion, + ) -> SimpleConsensusValidationResult { + // TODO: Add proper structure validation for shield transition + SimpleConsensusValidationResult::new() + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/types.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/types.rs new file mode 100644 index 00000000000..ed94df14858 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/types.rs @@ -0,0 +1,16 @@ +use crate::state_transition::shield_transition::v0::ShieldTransitionV0; +use crate::state_transition::StateTransitionFieldTypes; + +impl StateTransitionFieldTypes for ShieldTransitionV0 { + fn signature_property_paths() -> Vec<&'static str> { + vec![] + } + + fn identifiers_property_paths() -> Vec<&'static str> { + vec![] + } + + fn binary_property_paths() -> Vec<&'static str> { + vec![] + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/version.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/version.rs new file mode 100644 index 00000000000..27429523509 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/version.rs @@ -0,0 +1,9 @@ +use crate::state_transition::shield_transition::v0::ShieldTransitionV0; +use crate::state_transition::FeatureVersioned; +use crate::version::FeatureVersion; + +impl FeatureVersioned for ShieldTransitionV0 { + fn feature_version(&self) -> FeatureVersion { + 0 + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/version.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/version.rs new file mode 100644 index 00000000000..8f5de0b6b7a --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/version.rs @@ -0,0 +1,11 @@ +use crate::state_transition::shield_transition::ShieldTransition; +use crate::state_transition::FeatureVersioned; +use crate::version::FeatureVersion; + +impl FeatureVersioned for ShieldTransition { + fn feature_version(&self) -> FeatureVersion { + match self { + ShieldTransition::V0(v0) => v0.feature_version(), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/mod.rs new file mode 100644 index 00000000000..1d9b49c383e --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/mod.rs @@ -0,0 +1,60 @@ +mod state_transition_estimated_fee_validation; +mod state_transition_like; +mod state_transition_validation; +pub mod v0; +mod version; + +use crate::state_transition::shielded_transfer_transition::v0::ShieldedTransferTransitionV0; +use crate::state_transition::shielded_transfer_transition::v0::ShieldedTransferTransitionV0Signable; +use crate::state_transition::StateTransitionFieldTypes; + +use crate::identity::state_transition::OptionallyAssetLockProved; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use derive_more::From; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize, PlatformSignable}; +use platform_versioning::PlatformVersioned; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +#[derive( + Debug, + Clone, + Encode, + Decode, + PlatformDeserialize, + PlatformSerialize, + PlatformSignable, + PlatformVersioned, + From, + PartialEq, +)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(tag = "$version") +)] +#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version +#[platform_version_path_bounds( + "dpp.state_transition_serialization_versions.shielded_transfer_state_transition" +)] +pub enum ShieldedTransferTransition { + #[cfg_attr(feature = "state-transition-serde-conversion", serde(rename = "0"))] + V0(ShieldedTransferTransitionV0), +} + +impl OptionallyAssetLockProved for ShieldedTransferTransition {} + +impl StateTransitionFieldTypes for ShieldedTransferTransition { + fn signature_property_paths() -> Vec<&'static str> { + vec![] + } + + fn identifiers_property_paths() -> Vec<&'static str> { + vec![] + } + + fn binary_property_paths() -> Vec<&'static str> { + vec![] + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/state_transition_estimated_fee_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/state_transition_estimated_fee_validation.rs new file mode 100644 index 00000000000..d956aa98757 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/state_transition_estimated_fee_validation.rs @@ -0,0 +1,16 @@ +use crate::fee::Credits; +use crate::state_transition::shielded_transfer_transition::ShieldedTransferTransition; +use crate::state_transition::StateTransitionEstimatedFeeValidation; +use crate::ProtocolError; +use platform_version::version::PlatformVersion; + +impl StateTransitionEstimatedFeeValidation for ShieldedTransferTransition { + fn calculate_min_required_fee( + &self, + _platform_version: &PlatformVersion, + ) -> Result { + // Fee for shielded transfers is paid from value balance in the orchard bundle + // Minimum fee is 0 as the actual fee is extracted from the bundle during validation + Ok(0) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/state_transition_like.rs new file mode 100644 index 00000000000..be107d7b6d9 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/state_transition_like.rs @@ -0,0 +1,47 @@ +use crate::prelude::UserFeeIncrease; +use crate::state_transition::shielded_transfer_transition::ShieldedTransferTransition; +use crate::state_transition::{StateTransitionLike, StateTransitionType}; +use crate::version::FeatureVersion; +use platform_value::Identifier; + +impl StateTransitionLike for ShieldedTransferTransition { + /// Returns ID of the created contract + fn modified_data_ids(&self) -> Vec { + match self { + ShieldedTransferTransition::V0(transition) => transition.modified_data_ids(), + } + } + + fn state_transition_protocol_version(&self) -> FeatureVersion { + match self { + ShieldedTransferTransition::V0(_) => 0, + } + } + /// returns the type of State Transition + fn state_transition_type(&self) -> StateTransitionType { + match self { + ShieldedTransferTransition::V0(transition) => transition.state_transition_type(), + } + } + + /// returns the fee multiplier + fn user_fee_increase(&self) -> UserFeeIncrease { + match self { + ShieldedTransferTransition::V0(transition) => transition.user_fee_increase(), + } + } + /// set a fee multiplier + fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { + match self { + ShieldedTransferTransition::V0(transition) => { + transition.set_user_fee_increase(user_fee_increase) + } + } + } + + fn unique_identifiers(&self) -> Vec { + match self { + ShieldedTransferTransition::V0(transition) => transition.unique_identifiers(), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/state_transition_validation.rs new file mode 100644 index 00000000000..9d3bbbe6ee3 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/state_transition_validation.rs @@ -0,0 +1,15 @@ +use crate::state_transition::shielded_transfer_transition::ShieldedTransferTransition; +use crate::state_transition::StateTransitionStructureValidation; +use crate::validation::SimpleConsensusValidationResult; +use platform_version::version::PlatformVersion; + +impl StateTransitionStructureValidation for ShieldedTransferTransition { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> SimpleConsensusValidationResult { + match self { + ShieldedTransferTransition::V0(v0) => v0.validate_structure(platform_version), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs new file mode 100644 index 00000000000..5c1ab56b259 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs @@ -0,0 +1,33 @@ +mod state_transition_like; +mod state_transition_validation; +mod types; +mod version; + +use crate::prelude::UserFeeIncrease; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize, PlatformSignable}; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +#[derive( + Debug, + Clone, + Encode, + Decode, + PlatformSerialize, + PlatformDeserialize, + PlatformSignable, + PartialEq, +)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +#[platform_serialize(unversioned)] +#[derive(Default)] +pub struct ShieldedTransferTransitionV0 { + pub orchard_bundle: Vec, + pub user_fee_increase: UserFeeIncrease, +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_like.rs new file mode 100644 index 00000000000..12efcc4ae81 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_like.rs @@ -0,0 +1,49 @@ +use crate::prelude::UserFeeIncrease; +use crate::state_transition::shielded_transfer_transition::v0::ShieldedTransferTransitionV0; +use crate::state_transition::shielded_transfer_transition::ShieldedTransferTransition; +use crate::{ + prelude::Identifier, + state_transition::{StateTransitionLike, StateTransitionType}, +}; + +use crate::state_transition::StateTransition; +use crate::state_transition::StateTransitionType::ShieldedTransfer; +use crate::version::FeatureVersion; + +impl From for StateTransition { + fn from(value: ShieldedTransferTransitionV0) -> Self { + let transition: ShieldedTransferTransition = value.into(); + transition.into() + } +} + +impl StateTransitionLike for ShieldedTransferTransitionV0 { + fn state_transition_protocol_version(&self) -> FeatureVersion { + 0 + } + + /// returns the type of State Transition + fn state_transition_type(&self) -> StateTransitionType { + ShieldedTransfer + } + + /// Returns ID of the created contract + fn modified_data_ids(&self) -> Vec { + vec![] + } + + /// For ZK-only transitions, uniqueness comes from nullifiers in the bundle, + /// but at the DPP level we use the hash of the orchard bundle as a unique identifier. + fn unique_identifiers(&self) -> Vec { + use crate::util::hash::hash_single; + vec![hex::encode(hash_single(&self.orchard_bundle))] + } + + fn user_fee_increase(&self) -> UserFeeIncrease { + self.user_fee_increase + } + + fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { + self.user_fee_increase = user_fee_increase + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs new file mode 100644 index 00000000000..d9d398e4da6 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs @@ -0,0 +1,14 @@ +use crate::state_transition::shielded_transfer_transition::v0::ShieldedTransferTransitionV0; +use crate::state_transition::StateTransitionStructureValidation; +use crate::validation::SimpleConsensusValidationResult; +use platform_version::version::PlatformVersion; + +impl StateTransitionStructureValidation for ShieldedTransferTransitionV0 { + fn validate_structure( + &self, + _platform_version: &PlatformVersion, + ) -> SimpleConsensusValidationResult { + // TODO: Add proper structure validation for shielded transfer transition + SimpleConsensusValidationResult::new() + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/types.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/types.rs new file mode 100644 index 00000000000..9c3dc80f9d2 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/types.rs @@ -0,0 +1,16 @@ +use crate::state_transition::shielded_transfer_transition::v0::ShieldedTransferTransitionV0; +use crate::state_transition::StateTransitionFieldTypes; + +impl StateTransitionFieldTypes for ShieldedTransferTransitionV0 { + fn signature_property_paths() -> Vec<&'static str> { + vec![] + } + + fn identifiers_property_paths() -> Vec<&'static str> { + vec![] + } + + fn binary_property_paths() -> Vec<&'static str> { + vec![] + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/version.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/version.rs new file mode 100644 index 00000000000..fb6f180b029 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/version.rs @@ -0,0 +1,9 @@ +use crate::state_transition::shielded_transfer_transition::v0::ShieldedTransferTransitionV0; +use crate::state_transition::FeatureVersioned; +use crate::version::FeatureVersion; + +impl FeatureVersioned for ShieldedTransferTransitionV0 { + fn feature_version(&self) -> FeatureVersion { + 0 + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/version.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/version.rs new file mode 100644 index 00000000000..0688f51e27d --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/version.rs @@ -0,0 +1,11 @@ +use crate::state_transition::shielded_transfer_transition::ShieldedTransferTransition; +use crate::state_transition::FeatureVersioned; +use crate::version::FeatureVersion; + +impl FeatureVersioned for ShieldedTransferTransition { + fn feature_version(&self) -> FeatureVersion { + match self { + ShieldedTransferTransition::V0(v0) => v0.feature_version(), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/mod.rs new file mode 100644 index 00000000000..d584db46972 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/mod.rs @@ -0,0 +1,60 @@ +mod state_transition_estimated_fee_validation; +mod state_transition_like; +mod state_transition_validation; +pub mod v0; +mod version; + +use crate::state_transition::unshield_transition::v0::UnshieldTransitionV0; +use crate::state_transition::unshield_transition::v0::UnshieldTransitionV0Signable; +use crate::state_transition::StateTransitionFieldTypes; + +use crate::identity::state_transition::OptionallyAssetLockProved; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use derive_more::From; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize, PlatformSignable}; +use platform_versioning::PlatformVersioned; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +#[derive( + Debug, + Clone, + Encode, + Decode, + PlatformDeserialize, + PlatformSerialize, + PlatformSignable, + PlatformVersioned, + From, + PartialEq, +)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(tag = "$version") +)] +#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version +#[platform_version_path_bounds( + "dpp.state_transition_serialization_versions.unshield_state_transition" +)] +pub enum UnshieldTransition { + #[cfg_attr(feature = "state-transition-serde-conversion", serde(rename = "0"))] + V0(UnshieldTransitionV0), +} + +impl OptionallyAssetLockProved for UnshieldTransition {} + +impl StateTransitionFieldTypes for UnshieldTransition { + fn signature_property_paths() -> Vec<&'static str> { + vec![] + } + + fn identifiers_property_paths() -> Vec<&'static str> { + vec![] + } + + fn binary_property_paths() -> Vec<&'static str> { + vec![] + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/state_transition_estimated_fee_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/state_transition_estimated_fee_validation.rs new file mode 100644 index 00000000000..4f1d94063e7 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/state_transition_estimated_fee_validation.rs @@ -0,0 +1,16 @@ +use crate::fee::Credits; +use crate::state_transition::unshield_transition::UnshieldTransition; +use crate::state_transition::StateTransitionEstimatedFeeValidation; +use crate::ProtocolError; +use platform_version::version::PlatformVersion; + +impl StateTransitionEstimatedFeeValidation for UnshieldTransition { + fn calculate_min_required_fee( + &self, + _platform_version: &PlatformVersion, + ) -> Result { + // Fee for unshield is paid from value balance in the orchard bundle + // Minimum fee is 0 as the actual fee is extracted from the bundle during validation + Ok(0) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/state_transition_like.rs new file mode 100644 index 00000000000..67b3c5fb3f6 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/state_transition_like.rs @@ -0,0 +1,47 @@ +use crate::prelude::UserFeeIncrease; +use crate::state_transition::unshield_transition::UnshieldTransition; +use crate::state_transition::{StateTransitionLike, StateTransitionType}; +use crate::version::FeatureVersion; +use platform_value::Identifier; + +impl StateTransitionLike for UnshieldTransition { + /// Returns ID of the created contract + fn modified_data_ids(&self) -> Vec { + match self { + UnshieldTransition::V0(transition) => transition.modified_data_ids(), + } + } + + fn state_transition_protocol_version(&self) -> FeatureVersion { + match self { + UnshieldTransition::V0(_) => 0, + } + } + /// returns the type of State Transition + fn state_transition_type(&self) -> StateTransitionType { + match self { + UnshieldTransition::V0(transition) => transition.state_transition_type(), + } + } + + /// returns the fee multiplier + fn user_fee_increase(&self) -> UserFeeIncrease { + match self { + UnshieldTransition::V0(transition) => transition.user_fee_increase(), + } + } + /// set a fee multiplier + fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { + match self { + UnshieldTransition::V0(transition) => { + transition.set_user_fee_increase(user_fee_increase) + } + } + } + + fn unique_identifiers(&self) -> Vec { + match self { + UnshieldTransition::V0(transition) => transition.unique_identifiers(), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/state_transition_validation.rs new file mode 100644 index 00000000000..bfc5be90735 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/state_transition_validation.rs @@ -0,0 +1,15 @@ +use crate::state_transition::unshield_transition::UnshieldTransition; +use crate::state_transition::StateTransitionStructureValidation; +use crate::validation::SimpleConsensusValidationResult; +use platform_version::version::PlatformVersion; + +impl StateTransitionStructureValidation for UnshieldTransition { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> SimpleConsensusValidationResult { + match self { + UnshieldTransition::V0(v0) => v0.validate_structure(platform_version), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs new file mode 100644 index 00000000000..172c3668ac9 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs @@ -0,0 +1,36 @@ +mod state_transition_like; +mod state_transition_validation; +mod types; +mod version; + +use crate::address_funds::PlatformAddress; +use crate::prelude::UserFeeIncrease; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize, PlatformSignable}; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +#[derive( + Debug, + Clone, + Encode, + Decode, + PlatformSerialize, + PlatformDeserialize, + PlatformSignable, + PartialEq, +)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +#[platform_serialize(unversioned)] +#[derive(Default)] +pub struct UnshieldTransitionV0 { + pub output_address: PlatformAddress, + pub amount: u64, + pub orchard_bundle: Vec, + pub user_fee_increase: UserFeeIncrease, +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_like.rs new file mode 100644 index 00000000000..3b705e88146 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_like.rs @@ -0,0 +1,49 @@ +use crate::prelude::UserFeeIncrease; +use crate::state_transition::unshield_transition::v0::UnshieldTransitionV0; +use crate::state_transition::unshield_transition::UnshieldTransition; +use crate::{ + prelude::Identifier, + state_transition::{StateTransitionLike, StateTransitionType}, +}; + +use crate::state_transition::StateTransition; +use crate::state_transition::StateTransitionType::Unshield; +use crate::version::FeatureVersion; + +impl From for StateTransition { + fn from(value: UnshieldTransitionV0) -> Self { + let transition: UnshieldTransition = value.into(); + transition.into() + } +} + +impl StateTransitionLike for UnshieldTransitionV0 { + fn state_transition_protocol_version(&self) -> FeatureVersion { + 0 + } + + /// returns the type of State Transition + fn state_transition_type(&self) -> StateTransitionType { + Unshield + } + + /// Returns ID of the created contract + fn modified_data_ids(&self) -> Vec { + vec![] + } + + /// For ZK-only transitions, uniqueness comes from nullifiers in the bundle, + /// but at the DPP level we use the hash of the orchard bundle as a unique identifier. + fn unique_identifiers(&self) -> Vec { + use crate::util::hash::hash_single; + vec![hex::encode(hash_single(&self.orchard_bundle))] + } + + fn user_fee_increase(&self) -> UserFeeIncrease { + self.user_fee_increase + } + + fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { + self.user_fee_increase = user_fee_increase + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs new file mode 100644 index 00000000000..533c29ff947 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs @@ -0,0 +1,14 @@ +use crate::state_transition::unshield_transition::v0::UnshieldTransitionV0; +use crate::state_transition::StateTransitionStructureValidation; +use crate::validation::SimpleConsensusValidationResult; +use platform_version::version::PlatformVersion; + +impl StateTransitionStructureValidation for UnshieldTransitionV0 { + fn validate_structure( + &self, + _platform_version: &PlatformVersion, + ) -> SimpleConsensusValidationResult { + // TODO: Add proper structure validation for unshield transition + SimpleConsensusValidationResult::new() + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/types.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/types.rs new file mode 100644 index 00000000000..928054d5a4f --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/types.rs @@ -0,0 +1,16 @@ +use crate::state_transition::unshield_transition::v0::UnshieldTransitionV0; +use crate::state_transition::StateTransitionFieldTypes; + +impl StateTransitionFieldTypes for UnshieldTransitionV0 { + fn signature_property_paths() -> Vec<&'static str> { + vec![] + } + + fn identifiers_property_paths() -> Vec<&'static str> { + vec![] + } + + fn binary_property_paths() -> Vec<&'static str> { + vec![] + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/version.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/version.rs new file mode 100644 index 00000000000..540c8bc9e45 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/version.rs @@ -0,0 +1,9 @@ +use crate::state_transition::unshield_transition::v0::UnshieldTransitionV0; +use crate::state_transition::FeatureVersioned; +use crate::version::FeatureVersion; + +impl FeatureVersioned for UnshieldTransitionV0 { + fn feature_version(&self) -> FeatureVersion { + 0 + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/version.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/version.rs new file mode 100644 index 00000000000..83c92c77caa --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/version.rs @@ -0,0 +1,11 @@ +use crate::state_transition::unshield_transition::UnshieldTransition; +use crate::state_transition::FeatureVersioned; +use crate::version::FeatureVersion; + +impl FeatureVersioned for UnshieldTransition { + fn feature_version(&self) -> FeatureVersion { + match self { + UnshieldTransition::V0(v0) => v0.feature_version(), + } + } +} 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 090cb1ce4ab..34cd630efa9 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 @@ -27,6 +27,12 @@ use drive::drive::saved_block_transactions::{ ADDRESS_BALANCES_KEY_U8, COMPACTED_ADDRESSES_EXPIRATION_TIME_KEY_U8, COMPACTED_ADDRESS_BALANCES_KEY_U8, }; +use drive::drive::shielded::paths::{ + shielded_anchors_path, shielded_credit_pool_path, SHIELDED_ANCHORS_KEY_U8, + SHIELDED_COMMITMENTS_KEY, SHIELDED_CREDIT_POOL_KEY, SHIELDED_CREDIT_POOL_KEY_U8, + SHIELDED_ENCRYPTED_NOTES_KEY, SHIELDED_NULLIFIERS_KEY, SHIELDED_PARAMS_KEY, + SHIELDED_TOTAL_BALANCE_KEY, +}; use drive::drive::system::misc_path; use drive::drive::tokens::paths::{ token_distributions_root_path, token_timed_distributions_path, tokens_root_path, @@ -110,6 +116,10 @@ impl Platform { self.transition_to_version_11(transaction, platform_version)?; } + if previous_protocol_version < 12 && platform_version.protocol_version >= 12 { + self.transition_to_version_12(transaction, platform_version)?; + } + Ok(()) } @@ -598,4 +608,100 @@ impl Platform { Ok(()) } + + /// We introduced in version 12 Shielded Pools + fn transition_to_version_12( + &self, + transaction: &Transaction, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let addresses_path = Drive::addresses_path(); + + // Shielded credit pool SumTree under AddressBalances: [AddressBalances] / "s" + self.drive.grove_insert_if_not_exists( + addresses_path.as_slice().into(), + &[SHIELDED_CREDIT_POOL_KEY_U8], + Element::empty_sum_tree(), + Some(transaction), + None, + &platform_version.drive, + )?; + + // Commitments tree (CommitmentTree): [AddressBalances, "s"] / [1] + let shielded_pool_path = shielded_credit_pool_path(); + self.drive.grove_insert_if_not_exists( + (&shielded_pool_path).into(), + &[SHIELDED_COMMITMENTS_KEY], + Element::empty_commitment_tree(), + Some(transaction), + None, + &platform_version.drive, + )?; + + // Nullifiers tree (NormalTree): [AddressBalances, "s"] / [2] + self.drive.grove_insert_if_not_exists( + (&shielded_pool_path).into(), + &[SHIELDED_NULLIFIERS_KEY], + Element::empty_tree(), + Some(transaction), + None, + &platform_version.drive, + )?; + + // Encrypted notes tree (NormalTree): [AddressBalances, "s"] / [3] + self.drive.grove_insert_if_not_exists( + (&shielded_pool_path).into(), + &[SHIELDED_ENCRYPTED_NOTES_KEY], + Element::empty_tree(), + Some(transaction), + None, + &platform_version.drive, + )?; + + // Params item: [AddressBalances, "s"] / [4] + let initial_params = dpp::shielded::ShieldedPoolParams::default(); + let encoded_params = bincode::encode_to_vec(&initial_params, bincode::config::standard()) + .expect("expected to encode default shielded pool params"); + self.drive.grove_insert_if_not_exists( + (&shielded_pool_path).into(), + &[SHIELDED_PARAMS_KEY], + Element::new_item(encoded_params), + Some(transaction), + None, + &platform_version.drive, + )?; + + // Total balance SumItem(0): [AddressBalances, "s"] / [5] + self.drive.grove_insert_if_not_exists( + (&shielded_pool_path).into(), + &[SHIELDED_TOTAL_BALANCE_KEY], + Element::new_sum_item(0), + Some(transaction), + None, + &platform_version.drive, + )?; + + // Anchors tree (NormalTree) under AddressBalances: [AddressBalances] / "a" + self.drive.grove_insert_if_not_exists( + addresses_path.as_slice().into(), + &[SHIELDED_ANCHORS_KEY_U8], + Element::empty_tree(), + Some(transaction), + None, + &platform_version.drive, + )?; + + // Credit pool anchors tree: [AddressBalances, "a"] / "s" + let anchors_path = shielded_anchors_path(); + self.drive.grove_insert_if_not_exists( + (&anchors_path).into(), + SHIELDED_CREDIT_POOL_KEY, + Element::empty_tree(), + Some(transaction), + None, + &platform_version.drive, + )?; + + Ok(()) + } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/address_balances_and_nonces.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/address_balances_and_nonces.rs index e614e861e1d..4dbd6e41c23 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/address_balances_and_nonces.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/address_balances_and_nonces.rs @@ -11,6 +11,7 @@ use dpp::state_transition::state_transitions::identity::identity_topup_from_addr use dpp::state_transition::state_transitions::address_funds::address_funds_transfer_transition::AddressFundsTransferTransition; use dpp::state_transition::state_transitions::address_funds::address_funding_from_asset_lock_transition::AddressFundingFromAssetLockTransition; use dpp::state_transition::state_transitions::address_funds::address_credit_withdrawal_transition::AddressCreditWithdrawalTransition; +use dpp::state_transition::shield_transition::ShieldTransition; use drive::drive::Drive; use drive::error::Error; use drive::grovedb::TransactionArg; @@ -139,6 +140,7 @@ impl StateTransitionAddressBalancesAndNoncesInnerValidation { } impl StateTransitionAddressBalancesAndNoncesInnerValidation for AddressCreditWithdrawalTransition {} +impl StateTransitionAddressBalancesAndNoncesInnerValidation for ShieldTransition {} /// Trait for validating address balances and nonces in state transitions. pub trait StateTransitionAddressBalancesAndNoncesValidation { @@ -164,7 +166,8 @@ impl StateTransitionAddressBalancesAndNoncesValidation for StateTransition { | StateTransition::AddressFundsTransfer(_) | StateTransition::AddressFundingFromAssetLock(_) | StateTransition::AddressCreditWithdrawal(_) - | StateTransition::IdentityTopUpFromAddresses(_) => true, + | StateTransition::IdentityTopUpFromAddresses(_) + | StateTransition::Shield(_) => true, StateTransition::DataContractCreate(_) | StateTransition::IdentityCreate(_) | StateTransition::DataContractUpdate(_) @@ -174,7 +177,9 @@ impl StateTransitionAddressBalancesAndNoncesValidation for StateTransition { | StateTransition::IdentityTopUp(_) | StateTransition::IdentityCreditTransfer(_) | StateTransition::MasternodeVote(_) - | StateTransition::IdentityCreditTransferToAddresses(_) => false, + | StateTransition::IdentityCreditTransferToAddresses(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => false, } } @@ -222,6 +227,13 @@ impl StateTransitionAddressBalancesAndNoncesValidation for StateTransition { transaction, platform_version, ), + StateTransition::Shield(st) => st + .validate_address_balances_and_nonces_internal_validation( + drive, + execution_context, + transaction, + platform_version, + ), StateTransition::DataContractCreate(_) | StateTransition::DataContractUpdate(_) | StateTransition::Batch(_) @@ -231,7 +243,9 @@ impl StateTransitionAddressBalancesAndNoncesValidation for StateTransition { | StateTransition::IdentityUpdate(_) | StateTransition::IdentityCreditTransfer(_) | StateTransition::MasternodeVote(_) - | StateTransition::IdentityCreditTransferToAddresses(_) => { + | StateTransition::IdentityCreditTransferToAddresses(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => { Ok(ConsensusValidationResult::new_with_data(BTreeMap::new())) } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/address_witnesses.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/address_witnesses.rs index 8aede4de054..d14d137453d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/address_witnesses.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/address_witnesses.rs @@ -68,6 +68,7 @@ impl StateTransitionAddressWitnessValidationV0 for StateTransition { StateTransition::AddressFundingFromAssetLock(st) => { st.validate_witnesses(&signable_bytes) } + StateTransition::Shield(st) => st.validate_witnesses(&signable_bytes), // These state transitions don't have address witness validation StateTransition::DataContractCreate(_) | StateTransition::DataContractUpdate(_) @@ -78,7 +79,9 @@ impl StateTransitionAddressWitnessValidationV0 for StateTransition { | StateTransition::IdentityUpdate(_) | StateTransition::IdentityCreditTransfer(_) | StateTransition::MasternodeVote(_) - | StateTransition::IdentityCreditTransferToAddresses(_) => { + | StateTransition::IdentityCreditTransferToAddresses(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => { return Ok(SimpleConsensusValidationResult::new()); } }; @@ -180,7 +183,8 @@ impl StateTransitionHasAddressWitnessValidationV0 for StateTransition { | StateTransition::IdentityCreateFromAddresses(_) | StateTransition::IdentityTopUpFromAddresses(_) | StateTransition::AddressCreditWithdrawal(_) - | StateTransition::AddressFundingFromAssetLock(_) => true, + | StateTransition::AddressFundingFromAssetLock(_) + | StateTransition::Shield(_) => true, StateTransition::DataContractCreate(_) | StateTransition::DataContractUpdate(_) | StateTransition::Batch(_) @@ -190,7 +194,9 @@ impl StateTransitionHasAddressWitnessValidationV0 for StateTransition { | StateTransition::IdentityUpdate(_) | StateTransition::IdentityCreditTransfer(_) | StateTransition::MasternodeVote(_) - | StateTransition::IdentityCreditTransferToAddresses(_) => false, + | StateTransition::IdentityCreditTransferToAddresses(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => false, }; Ok(has_address_witness_validation) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/addresses_minimum_balance.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/addresses_minimum_balance.rs index c76b79953d5..70ab968da18 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/addresses_minimum_balance.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/addresses_minimum_balance.rs @@ -58,6 +58,7 @@ impl StateTransitionAddressesMinimumBalanceValidationV0 for StateTransition { transition.validate_estimated_fee(remaining_address_balances, platform_version) } // AddressFundingFromAssetLock doesn't need balance check - funds come from asset lock + // Shielded transitions don't use address minimum balance validation // All other state transitions don't use address minimum balance validation StateTransition::AddressFundingFromAssetLock(_) | StateTransition::DataContractCreate(_) @@ -69,7 +70,10 @@ impl StateTransitionAddressesMinimumBalanceValidationV0 for StateTransition { | StateTransition::IdentityCreditWithdrawal(_) | StateTransition::IdentityCreditTransferToAddresses(_) | StateTransition::Batch(_) - | StateTransition::MasternodeVote(_) => { + | StateTransition::MasternodeVote(_) + | StateTransition::Shield(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => { return Ok(SimpleConsensusValidationResult::new()); } }?; @@ -96,7 +100,10 @@ impl StateTransitionAddressesMinimumBalanceValidationV0 for StateTransition { | StateTransition::IdentityCreditTransferToAddresses(_) | StateTransition::Batch(_) | StateTransition::MasternodeVote(_) - | StateTransition::AddressFundingFromAssetLock(_) => false, + | StateTransition::AddressFundingFromAssetLock(_) + | StateTransition::Shield(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => false, } } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/basic_structure.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/basic_structure.rs index b9d1c491e7a..a8c151e3446 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/basic_structure.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/basic_structure.rs @@ -237,6 +237,9 @@ impl StateTransitionBasicStructureValidationV0 for StateTransition { })), } } + StateTransition::Shield(st) => Ok(st.validate_structure(platform_version)), + StateTransition::ShieldedTransfer(st) => Ok(st.validate_structure(platform_version)), + StateTransition::Unshield(st) => Ok(st.validate_structure(platform_version)), } } fn has_basic_structure_validation(&self, platform_version: &PlatformVersion) -> bool { @@ -272,7 +275,10 @@ impl StateTransitionBasicStructureValidationV0 for StateTransition { | StateTransition::IdentityCreateFromAddresses(_) | StateTransition::IdentityTopUpFromAddresses(_) | StateTransition::AddressFundingFromAssetLock(_) - | StateTransition::AddressCreditWithdrawal(_) => true, + | StateTransition::AddressCreditWithdrawal(_) + | StateTransition::Shield(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => true, StateTransition::MasternodeVote(_) => false, } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_balance.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_balance.rs index e9bd2e6dd34..9a51f5a233a 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_balance.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_balance.rs @@ -76,9 +76,10 @@ impl StateTransitionIdentityBalanceValidationV0 for StateTransition { | StateTransition::IdentityTopUpFromAddresses(_) | StateTransition::AddressFundsTransfer(_) | StateTransition::AddressFundingFromAssetLock(_) - | StateTransition::AddressCreditWithdrawal(_) => { - Ok(SimpleConsensusValidationResult::new()) - } + | StateTransition::AddressCreditWithdrawal(_) + | StateTransition::Shield(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => Ok(SimpleConsensusValidationResult::new()), } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_based_signature.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_based_signature.rs index e7854d46439..d5861ce1057 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_based_signature.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_based_signature.rs @@ -130,7 +130,10 @@ impl StateTransitionIdentityBasedSignatureValidationV0 for StateTransition { | StateTransition::IdentityTopUpFromAddresses(_) | StateTransition::AddressFundsTransfer(_) | StateTransition::AddressFundingFromAssetLock(_) - | StateTransition::AddressCreditWithdrawal(_) => Ok(ConsensusValidationResult::new()), + | StateTransition::AddressCreditWithdrawal(_) + | StateTransition::Shield(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => Ok(ConsensusValidationResult::new()), } } @@ -165,7 +168,10 @@ impl StateTransitionIdentityBasedSignatureValidationV0 for StateTransition { | StateTransition::IdentityCreateFromAddresses(_) | StateTransition::AddressFundsTransfer(_) | StateTransition::AddressFundingFromAssetLock(_) - | StateTransition::AddressCreditWithdrawal(_) => false, + | StateTransition::AddressCreditWithdrawal(_) + | StateTransition::Shield(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => false, StateTransition::DataContractCreate(_) | StateTransition::DataContractUpdate(_) | StateTransition::Batch(_) @@ -188,7 +194,10 @@ impl StateTransitionIdentityBasedSignatureValidationV0 for StateTransition { | StateTransition::AddressFundingFromAssetLock(_) | StateTransition::AddressCreditWithdrawal(_) | StateTransition::IdentityTopUpFromAddresses(_) - | StateTransition::IdentityTopUp(_) => false, + | StateTransition::IdentityTopUp(_) + | StateTransition::Shield(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => false, StateTransition::DataContractCreate(_) | StateTransition::DataContractUpdate(_) | StateTransition::Batch(_) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_nonces.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_nonces.rs index d54e789757e..819124bc185 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_nonces.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_nonces.rs @@ -114,7 +114,10 @@ impl StateTransitionIdentityNonceValidationV0 for StateTransition { | StateTransition::IdentityTopUpFromAddresses(_) | StateTransition::AddressFundsTransfer(_) | StateTransition::IdentityCreate(_) - | StateTransition::IdentityTopUp(_) => Ok(SimpleConsensusValidationResult::new()), + | StateTransition::IdentityTopUp(_) + | StateTransition::Shield(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => Ok(SimpleConsensusValidationResult::new()), } } } @@ -160,7 +163,10 @@ impl StateTransitionHasIdentityNonceValidationV0 for StateTransition { | StateTransition::IdentityTopUpFromAddresses(_) | StateTransition::AddressFundsTransfer(_) | StateTransition::AddressFundingFromAssetLock(_) - | StateTransition::AddressCreditWithdrawal(_) => false, + | StateTransition::AddressCreditWithdrawal(_) + | StateTransition::Shield(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => false, }; Ok(has_nonce_validation) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/is_allowed.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/is_allowed.rs index 935b725bca3..80d6f35de35 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/is_allowed.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/is_allowed.rs @@ -5,7 +5,9 @@ use crate::rpc::core::CoreRPCLike; use dpp::consensus::basic::state_transition::StateTransitionNotActiveError; use dpp::prelude::ConsensusValidationResult; use dpp::state_transition::StateTransition; -use dpp::version::feature_initial_protocol_versions::ADDRESS_FUNDS_INITIAL_PROTOCOL_VERSION; +use dpp::version::feature_initial_protocol_versions::{ + ADDRESS_FUNDS_INITIAL_PROTOCOL_VERSION, SHIELDED_POOL_INITIAL_PROTOCOL_VERSION, +}; use dpp::version::PlatformVersion; /// A trait for validating state transitions within a blockchain. @@ -29,7 +31,10 @@ impl StateTransitionIsAllowedValidationV0 for StateTransition { | StateTransition::AddressFundsTransfer(_) | StateTransition::IdentityCreditTransferToAddresses(_) | StateTransition::AddressFundingFromAssetLock(_) - | StateTransition::AddressCreditWithdrawal(_) => Ok(true), + | StateTransition::AddressCreditWithdrawal(_) + | StateTransition::Shield(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => Ok(true), StateTransition::DataContractCreate(_) | StateTransition::DataContractUpdate(_) | StateTransition::IdentityCreate(_) @@ -67,6 +72,22 @@ impl StateTransitionIsAllowedValidationV0 for StateTransition { ])) } } + StateTransition::Shield(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => { + if platform_version.protocol_version >= SHIELDED_POOL_INITIAL_PROTOCOL_VERSION { + Ok(ConsensusValidationResult::new()) + } else { + Ok(ConsensusValidationResult::new_with_errors(vec![ + StateTransitionNotActiveError::new( + self.state_transition_type().to_string(), + platform_version.protocol_version, + SHIELDED_POOL_INITIAL_PROTOCOL_VERSION, + ) + .into(), + ])) + } + } _ => Err(Error::Execution(ExecutionError::CorruptedCodeExecution( "validate_is_allowed is not implemented for this state transition", ))), diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/state.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/state.rs index f9d176acc19..9535229012b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/state.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/state.rs @@ -185,6 +185,17 @@ impl StateTransitionStateValidation for StateTransition { "address credit withdrawal should not have state validation", ))) } + StateTransition::Shield(_) => Err(Error::Execution( + ExecutionError::CorruptedCodeExecution("shield should not have state validation"), + )), + StateTransition::ShieldedTransfer(_) => { + Err(Error::Execution(ExecutionError::CorruptedCodeExecution( + "shielded transfer should not have state validation", + ))) + } + StateTransition::Unshield(_) => Err(Error::Execution( + ExecutionError::CorruptedCodeExecution("unshield should not have state validation"), + )), } } @@ -204,7 +215,10 @@ impl StateTransitionStateValidation for StateTransition { | StateTransition::IdentityTopUpFromAddresses(_) | StateTransition::IdentityCreditWithdrawal(_) | StateTransition::AddressCreditWithdrawal(_) - | StateTransition::IdentityCreditTransferToAddresses(_) => false, + | StateTransition::IdentityCreditTransferToAddresses(_) + | StateTransition::Shield(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => false, } } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs index 3ea8b849437..6995947ab3b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs @@ -229,6 +229,21 @@ impl StateTransitionActionTransformer for StateTransition { remaining_address_input_balances.clone(), ) } + StateTransition::Shield(_) => { + Err(Error::Execution(ExecutionError::CorruptedCodeExecution( + "shield transition transformer is not yet implemented", + ))) + } + StateTransition::ShieldedTransfer(_) => { + Err(Error::Execution(ExecutionError::CorruptedCodeExecution( + "shielded transfer transition transformer is not yet implemented", + ))) + } + StateTransition::Unshield(_) => { + Err(Error::Execution(ExecutionError::CorruptedCodeExecution( + "unshield transition transformer is not yet implemented", + ))) + } } } } diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index 2fd0676d080..6693456791b 100644 --- a/packages/rs-drive/Cargo.toml +++ b/packages/rs-drive/Cargo.toml @@ -52,12 +52,12 @@ enum-map = { version = "2.0.3", optional = true } intmap = { version = "3.0.1", features = ["serde"], optional = true } chrono = { version = "0.4.35", optional = true } itertools = { version = "0.13", optional = true } -grovedb = { git = "https://github.com/dashpay/grovedb", rev = "33dfd48a1718160cb333fa95424be491785f1897", optional = true, default-features = false } -grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "33dfd48a1718160cb333fa95424be491785f1897", optional = true } -grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "33dfd48a1718160cb333fa95424be491785f1897" } -grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "33dfd48a1718160cb333fa95424be491785f1897", optional = true } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "33dfd48a1718160cb333fa95424be491785f1897" } -grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "33dfd48a1718160cb333fa95424be491785f1897" } +grovedb = { git = "https://github.com/dashpay/grovedb", rev = "219ba2e73f08a9f428c9427f7ab5c73907d670bf", optional = true, default-features = false } +grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "219ba2e73f08a9f428c9427f7ab5c73907d670bf", optional = true } +grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "219ba2e73f08a9f428c9427f7ab5c73907d670bf" } +grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "219ba2e73f08a9f428c9427f7ab5c73907d670bf", optional = true } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "219ba2e73f08a9f428c9427f7ab5c73907d670bf" } +grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "219ba2e73f08a9f428c9427f7ab5c73907d670bf" } [dev-dependencies] criterion = "0.5" diff --git a/packages/rs-drive/src/drive/initialization/mod.rs b/packages/rs-drive/src/drive/initialization/mod.rs index d9d8add1817..f08df6e01c3 100644 --- a/packages/rs-drive/src/drive/initialization/mod.rs +++ b/packages/rs-drive/src/drive/initialization/mod.rs @@ -4,6 +4,7 @@ mod genesis_core_height; mod v0; mod v1; mod v2; +mod v3; use crate::drive::Drive; use crate::error::drive::DriveError; @@ -28,9 +29,10 @@ impl Drive { 0 => self.create_initial_state_structure_v0(transaction, platform_version), 1 => self.create_initial_state_structure_v1(transaction, platform_version), 2 => self.create_initial_state_structure_v2(transaction, platform_version), + 3 => self.create_initial_state_structure_v3(transaction, platform_version), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { method: "create_initial_state_structure".to_string(), - known_versions: vec![0, 1, 2], + known_versions: vec![0, 1, 2, 3], received: version, })), } diff --git a/packages/rs-drive/src/drive/initialization/v3/mod.rs b/packages/rs-drive/src/drive/initialization/v3/mod.rs new file mode 100644 index 00000000000..7fdc1e0f736 --- /dev/null +++ b/packages/rs-drive/src/drive/initialization/v3/mod.rs @@ -0,0 +1,137 @@ +//! Drive Initialization + +use crate::drive::shielded::paths::*; +use crate::drive::{Drive, RootTree}; +use crate::error::Error; +use crate::util::batch::grovedb_op_batch::GroveDbOpBatchV0Methods; +use crate::util::batch::GroveDbOpBatch; +use dpp::shielded::ShieldedPoolParams; +use dpp::version::PlatformVersion; +use grovedb::{Element, TransactionArg, TreeType}; +use grovedb_path::SubtreePath; + +impl Drive { + /// Creates the initial state structure. + pub(super) fn create_initial_state_structure_v3( + &self, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let drive_version = &platform_version.drive; + self.create_initial_state_structure_top_level_0(transaction, platform_version)?; + + self.grove_insert_empty_tree( + SubtreePath::empty(), + &[RootTree::GroupActions as u8], + TreeType::NormalTree, + transaction, + None, + &mut vec![], + drive_version, + )?; + + // AddressBalances top-level sum tree (introduced in v2) + self.grove_insert_empty_tree( + SubtreePath::empty(), + &[RootTree::AddressBalances as u8], + TreeType::SumTree, + transaction, + None, + &mut vec![], + drive_version, + )?; + + // SavedBlockTransactions for address-based transaction sync + self.grove_insert_empty_tree( + SubtreePath::empty(), + &[RootTree::SavedBlockTransactions as u8], + TreeType::NormalTree, + transaction, + None, + &mut vec![], + drive_version, + )?; + + // On lower layers we can use batching + + let mut batch = + self.create_initial_state_structure_lower_layers_operations_0(platform_version)?; + + self.initial_state_structure_lower_layers_add_operations_2(&mut batch, platform_version)?; + + // Add shielded pool structures + self.initial_state_structure_shielded_pool_operations(&mut batch)?; + + self.grove_apply_batch(batch, false, transaction, drive_version)?; + + Ok(()) + } + + /// Adds shielded pool batch operations for initialization. + pub(in crate::drive::initialization) fn initial_state_structure_shielded_pool_operations( + &self, + batch: &mut GroveDbOpBatch, + ) -> Result<(), Error> { + // 1. Shielded credit pool SumTree under AddressBalances + batch.add_insert( + vec![vec![RootTree::AddressBalances as u8]], + vec![SHIELDED_CREDIT_POOL_KEY_U8], + Element::empty_sum_tree(), + ); + + // 2. Commitments tree (CommitmentTree) + batch.add_insert( + shielded_credit_pool_path_vec(), + vec![SHIELDED_COMMITMENTS_KEY], + Element::empty_commitment_tree(), + ); + + // 3. Nullifiers tree (NormalTree) + batch.add_insert( + shielded_credit_pool_path_vec(), + vec![SHIELDED_NULLIFIERS_KEY], + Element::empty_tree(), + ); + + // 4. Encrypted notes tree (NormalTree) + batch.add_insert( + shielded_credit_pool_path_vec(), + vec![SHIELDED_ENCRYPTED_NOTES_KEY], + Element::empty_tree(), + ); + + // 5. Params item + let initial_params = ShieldedPoolParams::default(); + batch.add_insert( + shielded_credit_pool_path_vec(), + vec![SHIELDED_PARAMS_KEY], + Element::new_item( + bincode::encode_to_vec(&initial_params, bincode::config::standard()) + .expect("expected to encode"), + ), + ); + + // 6. Total balance SumItem(0) + batch.add_insert( + shielded_credit_pool_path_vec(), + vec![SHIELDED_TOTAL_BALANCE_KEY], + Element::new_sum_item(0), + ); + + // 7. Anchors tree (NormalTree) under AddressBalances + batch.add_insert( + vec![vec![RootTree::AddressBalances as u8]], + vec![SHIELDED_ANCHORS_KEY_U8], + Element::empty_tree(), + ); + + // 8. Credit pool anchors tree + batch.add_insert( + shielded_anchors_path_vec(), + SHIELDED_CREDIT_POOL_KEY.to_vec(), + Element::empty_tree(), + ); + + Ok(()) + } +} diff --git a/packages/rs-drive/src/drive/mod.rs b/packages/rs-drive/src/drive/mod.rs index 54f08566cd3..613dcceae61 100644 --- a/packages/rs-drive/src/drive/mod.rs +++ b/packages/rs-drive/src/drive/mod.rs @@ -71,6 +71,9 @@ pub mod address_funds; /// Saved block transactions module #[cfg(feature = "server")] pub mod saved_block_transactions; +/// Shielded pools module +#[cfg(any(feature = "server", feature = "verify"))] +pub mod shielded; /// Token module #[cfg(any(feature = "server", feature = "verify"))] pub mod tokens; diff --git a/packages/rs-drive/src/drive/shielded/mod.rs b/packages/rs-drive/src/drive/shielded/mod.rs new file mode 100644 index 00000000000..774df92744d --- /dev/null +++ b/packages/rs-drive/src/drive/shielded/mod.rs @@ -0,0 +1,3 @@ +/// Shielded pool paths and constants +#[cfg(any(feature = "server", feature = "verify"))] +pub mod paths; diff --git a/packages/rs-drive/src/drive/shielded/paths.rs b/packages/rs-drive/src/drive/shielded/paths.rs new file mode 100644 index 00000000000..ef76337c58f --- /dev/null +++ b/packages/rs-drive/src/drive/shielded/paths.rs @@ -0,0 +1,96 @@ +use crate::drive::RootTree; + +/// The subtree key for the shielded credit pool under AddressBalances +pub const SHIELDED_CREDIT_POOL_KEY: &[u8; 1] = b"s"; + +/// The subtree key for the shielded credit pool as a u8 +pub const SHIELDED_CREDIT_POOL_KEY_U8: u8 = b's'; + +/// The subtree key for the shielded anchors under AddressBalances +pub const SHIELDED_ANCHORS_KEY: &[u8; 1] = b"a"; + +/// The subtree key for the shielded anchors as a u8 +pub const SHIELDED_ANCHORS_KEY_U8: u8 = b'a'; + +/// Key for the commitments tree inside a shielded pool +pub const SHIELDED_COMMITMENTS_KEY: u8 = 1; + +/// Key for the nullifiers tree inside a shielded pool +pub const SHIELDED_NULLIFIERS_KEY: u8 = 2; + +/// Key for the encrypted notes tree inside a shielded pool +pub const SHIELDED_ENCRYPTED_NOTES_KEY: u8 = 3; + +/// Key for the params item inside a shielded pool +pub const SHIELDED_PARAMS_KEY: u8 = 4; + +/// Key for the total balance sum item inside a shielded pool +pub const SHIELDED_TOTAL_BALANCE_KEY: u8 = 5; + +/// Path to the shielded credit pool: [AddressBalances, "s"] +pub fn shielded_credit_pool_path() -> [&'static [u8]; 2] { + [ + Into::<&[u8; 1]>::into(RootTree::AddressBalances), + SHIELDED_CREDIT_POOL_KEY, + ] +} + +/// Path to the shielded credit pool as a vec +pub fn shielded_credit_pool_path_vec() -> Vec> { + vec![ + vec![RootTree::AddressBalances as u8], + SHIELDED_CREDIT_POOL_KEY.to_vec(), + ] +} + +/// Path to the commitments tree: [AddressBalances, "s", [1]] +pub fn shielded_credit_pool_commitments_path() -> [&'static [u8]; 3] { + [ + Into::<&[u8; 1]>::into(RootTree::AddressBalances), + SHIELDED_CREDIT_POOL_KEY, + &[SHIELDED_COMMITMENTS_KEY], + ] +} + +/// Path to the nullifiers tree: [AddressBalances, "s", [2]] +pub fn shielded_credit_pool_nullifiers_path() -> [&'static [u8]; 3] { + [ + Into::<&[u8; 1]>::into(RootTree::AddressBalances), + SHIELDED_CREDIT_POOL_KEY, + &[SHIELDED_NULLIFIERS_KEY], + ] +} + +/// Path to the encrypted notes tree: [AddressBalances, "s", [3]] +pub fn shielded_credit_pool_encrypted_notes_path() -> [&'static [u8]; 3] { + [ + Into::<&[u8; 1]>::into(RootTree::AddressBalances), + SHIELDED_CREDIT_POOL_KEY, + &[SHIELDED_ENCRYPTED_NOTES_KEY], + ] +} + +/// Path to the anchors tree: [AddressBalances, "a"] +pub fn shielded_anchors_path() -> [&'static [u8]; 2] { + [ + Into::<&[u8; 1]>::into(RootTree::AddressBalances), + SHIELDED_ANCHORS_KEY, + ] +} + +/// Path to the anchors tree as a vec +pub fn shielded_anchors_path_vec() -> Vec> { + vec![ + vec![RootTree::AddressBalances as u8], + SHIELDED_ANCHORS_KEY.to_vec(), + ] +} + +/// Path to the credit pool anchors: [AddressBalances, "a", "s"] +pub fn shielded_anchors_credit_pool_path() -> [&'static [u8]; 3] { + [ + Into::<&[u8; 1]>::into(RootTree::AddressBalances), + SHIELDED_ANCHORS_KEY, + SHIELDED_CREDIT_POOL_KEY, + ] +} diff --git a/packages/rs-drive/src/fees/op.rs b/packages/rs-drive/src/fees/op.rs index 9364d8f473b..b2429a6c035 100644 --- a/packages/rs-drive/src/fees/op.rs +++ b/packages/rs-drive/src/fees/op.rs @@ -579,6 +579,7 @@ impl LowLevelDriveOperationTreeTypeConverter for TreeType { TreeType::ProvableCountSumTree => { Element::empty_provable_count_sum_tree_with_flags(element_flags) } + TreeType::CommitmentTree => Element::empty_commitment_tree_with_flags(element_flags), }; LowLevelDriveOperation::insert_for_known_path_key_element(path, key, element) diff --git a/packages/rs-drive/src/prove/prove_state_transition/v0/mod.rs b/packages/rs-drive/src/prove/prove_state_transition/v0/mod.rs index 6f3837e0201..f573737beb8 100644 --- a/packages/rs-drive/src/prove/prove_state_transition/v0/mod.rs +++ b/packages/rs-drive/src/prove/prove_state_transition/v0/mod.rs @@ -301,6 +301,13 @@ impl Drive { .chain(st.output().into_iter().map(|(address, _)| address)); Drive::balances_for_clear_addresses_query(addresses_to_check) } + StateTransition::Shield(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => { + return Err(Error::Proof(ProofError::InvalidTransition( + "shielded state transitions do not support proof generation yet".to_string(), + ))); + } }; let proof = self.grove_get_proved_path_query( diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs index dd57109a435..9bad810dfad 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs @@ -7,6 +7,7 @@ mod address_funds; mod batch; mod contract; mod identity; +mod shielded; mod system; use crate::error::Error; @@ -106,6 +107,15 @@ impl DriveHighLevelOperationConverter for StateTransitionAction { address_funding_from_asset_lock .into_high_level_drive_operations(epoch, platform_version) } + StateTransitionAction::ShieldAction(shield_action) => { + shield_action.into_high_level_drive_operations(epoch, platform_version) + } + StateTransitionAction::ShieldedTransferAction(shielded_transfer_action) => { + shielded_transfer_action.into_high_level_drive_operations(epoch, platform_version) + } + StateTransitionAction::UnshieldAction(unshield_action) => { + unshield_action.into_high_level_drive_operations(epoch, platform_version) + } } } } diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs new file mode 100644 index 00000000000..d7c54b2cbeb --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs @@ -0,0 +1,41 @@ +use crate::error::Error; +use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; +use crate::state_transition_action::shielded::shield::ShieldTransitionAction; +use crate::state_transition_action::shielded::shielded_transfer::ShieldedTransferTransitionAction; +use crate::state_transition_action::shielded::unshield::UnshieldTransitionAction; +use crate::util::batch::DriveOperation; +use dpp::block::epoch::Epoch; +use dpp::version::PlatformVersion; + +impl DriveHighLevelOperationConverter for ShieldTransitionAction { + fn into_high_level_drive_operations<'a>( + self, + _epoch: &Epoch, + _platform_version: &PlatformVersion, + ) -> Result>, Error> { + // TODO: Implement shield drive operations + Ok(vec![]) + } +} + +impl DriveHighLevelOperationConverter for ShieldedTransferTransitionAction { + fn into_high_level_drive_operations<'a>( + self, + _epoch: &Epoch, + _platform_version: &PlatformVersion, + ) -> Result>, Error> { + // TODO: Implement shielded transfer drive operations + Ok(vec![]) + } +} + +impl DriveHighLevelOperationConverter for UnshieldTransitionAction { + fn into_high_level_drive_operations<'a>( + self, + _epoch: &Epoch, + _platform_version: &PlatformVersion, + ) -> Result>, Error> { + // TODO: Implement unshield drive operations + Ok(vec![]) + } +} diff --git a/packages/rs-drive/src/state_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/mod.rs index 24ef0fbc272..7f955432044 100644 --- a/packages/rs-drive/src/state_transition_action/mod.rs +++ b/packages/rs-drive/src/state_transition_action/mod.rs @@ -11,6 +11,8 @@ pub mod action_convert_to_operations; pub mod address_funds; /// documents_batch pub mod batch; +/// shielded +pub mod shielded; use crate::state_transition_action::address_funds::address_credit_withdrawal::AddressCreditWithdrawalTransitionAction; use crate::state_transition_action::address_funds::address_funding_from_asset_lock::AddressFundingFromAssetLockTransitionAction; @@ -27,6 +29,9 @@ use crate::state_transition_action::identity::identity_topup::IdentityTopUpTrans use crate::state_transition_action::identity::identity_topup_from_addresses::IdentityTopUpFromAddressesTransitionAction; use crate::state_transition_action::identity::identity_update::IdentityUpdateTransitionAction; use crate::state_transition_action::identity::masternode_vote::MasternodeVoteTransitionAction; +use crate::state_transition_action::shielded::shield::ShieldTransitionAction; +use crate::state_transition_action::shielded::shielded_transfer::ShieldedTransferTransitionAction; +use crate::state_transition_action::shielded::unshield::UnshieldTransitionAction; use crate::state_transition_action::system::bump_address_input_nonces_action::{ BumpAddressInputNonceActionAccessorsV0, BumpAddressInputNoncesAction, }; @@ -90,6 +95,12 @@ pub enum StateTransitionAction { /// partially use the asset lock for funding invalid asset lock transactions like /// identity top up and identity create BumpAddressInputNoncesAction(BumpAddressInputNoncesAction), + /// shield (address -> shielded pool) + ShieldAction(ShieldTransitionAction), + /// shielded transfer (shielded -> shielded) + ShieldedTransferAction(ShieldedTransferTransitionAction), + /// unshield (shielded pool -> address) + UnshieldAction(UnshieldTransitionAction), } impl StateTransitionAction { @@ -135,6 +146,9 @@ impl StateTransitionAction { StateTransitionAction::BumpAddressInputNoncesAction(action) => { action.user_fee_increase() } + StateTransitionAction::ShieldAction(action) => action.user_fee_increase(), + StateTransitionAction::ShieldedTransferAction(action) => action.user_fee_increase(), + StateTransitionAction::UnshieldAction(action) => action.user_fee_increase(), } } } diff --git a/packages/rs-drive/src/state_transition_action/shielded/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/mod.rs new file mode 100644 index 00000000000..0fad9d78d6d --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/mod.rs @@ -0,0 +1,6 @@ +/// Shield transition action +pub mod shield; +/// Shielded transfer transition action +pub mod shielded_transfer; +/// Unshield transition action +pub mod unshield; diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/mod.rs new file mode 100644 index 00000000000..c19419bbc88 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/mod.rs @@ -0,0 +1,59 @@ +/// transformer +pub mod transformer; +/// v0 +pub mod v0; + +use crate::state_transition_action::shielded::shield::v0::ShieldTransitionActionV0; +use derive_more::From; +use dpp::address_funds::{AddressFundsFeeStrategy, PlatformAddress}; +use dpp::fee::Credits; +use dpp::prelude::{AddressNonce, UserFeeIncrease}; +use std::collections::BTreeMap; + +/// Shield transition action +#[derive(Debug, Clone, From)] +pub enum ShieldTransitionAction { + /// v0 + V0(ShieldTransitionActionV0), +} + +impl ShieldTransitionAction { + /// Get inputs with remaining balance + pub fn inputs_with_remaining_balance( + &self, + ) -> &BTreeMap { + match self { + ShieldTransitionAction::V0(transition) => &transition.inputs_with_remaining_balance, + } + } + /// Get the shield amount + pub fn shield_amount(&self) -> Credits { + match self { + ShieldTransitionAction::V0(transition) => transition.shield_amount, + } + } + /// Get note commitments + pub fn note_commitments(&self) -> &Vec<[u8; 32]> { + match self { + ShieldTransitionAction::V0(transition) => &transition.note_commitments, + } + } + /// Get encrypted notes + pub fn encrypted_notes(&self) -> &Vec> { + match self { + ShieldTransitionAction::V0(transition) => &transition.encrypted_notes, + } + } + /// fee multiplier + pub fn user_fee_increase(&self) -> UserFeeIncrease { + match self { + ShieldTransitionAction::V0(transition) => transition.user_fee_increase, + } + } + /// fee strategy + pub fn fee_strategy(&self) -> &AddressFundsFeeStrategy { + match self { + ShieldTransitionAction::V0(transition) => &transition.fee_strategy, + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs new file mode 100644 index 00000000000..d6c982854ab --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs @@ -0,0 +1,31 @@ +use crate::state_transition_action::shielded::shield::v0::ShieldTransitionActionV0; +use crate::state_transition_action::shielded::shield::ShieldTransitionAction; +use dpp::address_funds::PlatformAddress; +use dpp::fee::Credits; +use dpp::prelude::{AddressNonce, ConsensusValidationResult}; +use dpp::state_transition::shield_transition::ShieldTransition; +use std::collections::BTreeMap; + +impl ShieldTransitionAction { + /// Transforms the state transition into an action + pub fn try_from_transition( + value: &ShieldTransition, + inputs_with_remaining_balance: BTreeMap, + shield_amount: Credits, + note_commitments: Vec<[u8; 32]>, + encrypted_notes: Vec>, + ) -> ConsensusValidationResult { + match value { + ShieldTransition::V0(v0) => { + let result = ShieldTransitionActionV0::try_from_transition( + v0, + inputs_with_remaining_balance, + shield_amount, + note_commitments, + encrypted_notes, + ); + result.map(|action| action.into()) + } + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs new file mode 100644 index 00000000000..cacf9588e04 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs @@ -0,0 +1,23 @@ +mod transformer; + +use dpp::address_funds::{AddressFundsFeeStrategy, PlatformAddress}; +use dpp::fee::Credits; +use dpp::prelude::{AddressNonce, UserFeeIncrease}; +use std::collections::BTreeMap; + +/// Shield transition action v0 +#[derive(Default, Debug, Clone)] +pub struct ShieldTransitionActionV0 { + /// inputs with remaining balance after shielding + pub inputs_with_remaining_balance: BTreeMap, + /// The amount being shielded (sent into the shielded pool) + pub shield_amount: Credits, + /// Note commitments from the orchard bundle (cmx values) + pub note_commitments: Vec<[u8; 32]>, + /// Encrypted notes from the orchard bundle + pub encrypted_notes: Vec>, + /// fee strategy + pub fee_strategy: AddressFundsFeeStrategy, + /// fee multiplier + pub user_fee_increase: UserFeeIncrease, +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs new file mode 100644 index 00000000000..9b9217165c2 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs @@ -0,0 +1,26 @@ +use crate::state_transition_action::shielded::shield::v0::ShieldTransitionActionV0; +use dpp::address_funds::PlatformAddress; +use dpp::fee::Credits; +use dpp::prelude::{AddressNonce, ConsensusValidationResult}; +use dpp::state_transition::state_transitions::shielded::shield_transition::v0::ShieldTransitionV0; +use std::collections::BTreeMap; + +impl ShieldTransitionActionV0 { + /// Transforms the shield transition into an action + pub fn try_from_transition( + value: &ShieldTransitionV0, + inputs_with_remaining_balance: BTreeMap, + shield_amount: Credits, + note_commitments: Vec<[u8; 32]>, + encrypted_notes: Vec>, + ) -> ConsensusValidationResult { + ConsensusValidationResult::new_with_data(ShieldTransitionActionV0 { + inputs_with_remaining_balance, + shield_amount, + note_commitments, + encrypted_notes, + fee_strategy: value.fee_strategy.clone(), + user_fee_increase: value.user_fee_increase, + }) + } +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/mod.rs new file mode 100644 index 00000000000..4571a55d1f4 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/mod.rs @@ -0,0 +1,55 @@ +/// transformer +pub mod transformer; +/// v0 +pub mod v0; + +use crate::state_transition_action::shielded::shielded_transfer::v0::ShieldedTransferTransitionActionV0; +use derive_more::From; +use dpp::fee::Credits; +use dpp::prelude::UserFeeIncrease; + +/// Shielded transfer transition action +#[derive(Debug, Clone, From)] +pub enum ShieldedTransferTransitionAction { + /// v0 + V0(ShieldedTransferTransitionActionV0), +} + +impl ShieldedTransferTransitionAction { + /// Get nullifiers + pub fn nullifiers(&self) -> &Vec<[u8; 32]> { + match self { + ShieldedTransferTransitionAction::V0(transition) => &transition.nullifiers, + } + } + /// Get note commitments + pub fn note_commitments(&self) -> &Vec<[u8; 32]> { + match self { + ShieldedTransferTransitionAction::V0(transition) => &transition.note_commitments, + } + } + /// Get encrypted notes + pub fn encrypted_notes(&self) -> &Vec> { + match self { + ShieldedTransferTransitionAction::V0(transition) => &transition.encrypted_notes, + } + } + /// Get anchor + pub fn anchor(&self) -> &[u8; 32] { + match self { + ShieldedTransferTransitionAction::V0(transition) => &transition.anchor, + } + } + /// Get fee amount + pub fn fee_amount(&self) -> Credits { + match self { + ShieldedTransferTransitionAction::V0(transition) => transition.fee_amount, + } + } + /// fee multiplier + pub fn user_fee_increase(&self) -> UserFeeIncrease { + match self { + ShieldedTransferTransitionAction::V0(transition) => transition.user_fee_increase, + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/transformer.rs new file mode 100644 index 00000000000..b33745d6038 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/transformer.rs @@ -0,0 +1,31 @@ +use crate::state_transition_action::shielded::shielded_transfer::v0::ShieldedTransferTransitionActionV0; +use crate::state_transition_action::shielded::shielded_transfer::ShieldedTransferTransitionAction; +use dpp::fee::Credits; +use dpp::prelude::ConsensusValidationResult; +use dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition; + +impl ShieldedTransferTransitionAction { + /// Transforms the state transition into an action + pub fn try_from_transition( + value: &ShieldedTransferTransition, + nullifiers: Vec<[u8; 32]>, + note_commitments: Vec<[u8; 32]>, + encrypted_notes: Vec>, + anchor: [u8; 32], + fee_amount: Credits, + ) -> ConsensusValidationResult { + match value { + ShieldedTransferTransition::V0(v0) => { + let result = ShieldedTransferTransitionActionV0::try_from_transition( + v0, + nullifiers, + note_commitments, + encrypted_notes, + anchor, + fee_amount, + ); + result.map(|action| action.into()) + } + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs new file mode 100644 index 00000000000..de77b61439c --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs @@ -0,0 +1,21 @@ +mod transformer; + +use dpp::fee::Credits; +use dpp::prelude::UserFeeIncrease; + +/// Shielded transfer transition action v0 +#[derive(Default, Debug, Clone)] +pub struct ShieldedTransferTransitionActionV0 { + /// Nullifiers from spent notes + pub nullifiers: Vec<[u8; 32]>, + /// Note commitments for new output notes + pub note_commitments: Vec<[u8; 32]>, + /// Encrypted notes for new output notes + pub encrypted_notes: Vec>, + /// The anchor (root of the commitment tree) used for verification + pub anchor: [u8; 32], + /// Fee amount extracted from the value balance + pub fee_amount: Credits, + /// fee multiplier + pub user_fee_increase: UserFeeIncrease, +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs new file mode 100644 index 00000000000..22ad9e00452 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs @@ -0,0 +1,25 @@ +use crate::state_transition_action::shielded::shielded_transfer::v0::ShieldedTransferTransitionActionV0; +use dpp::fee::Credits; +use dpp::prelude::ConsensusValidationResult; +use dpp::state_transition::state_transitions::shielded::shielded_transfer_transition::v0::ShieldedTransferTransitionV0; + +impl ShieldedTransferTransitionActionV0 { + /// Transforms the shielded transfer transition into an action + pub fn try_from_transition( + value: &ShieldedTransferTransitionV0, + nullifiers: Vec<[u8; 32]>, + note_commitments: Vec<[u8; 32]>, + encrypted_notes: Vec>, + anchor: [u8; 32], + fee_amount: Credits, + ) -> ConsensusValidationResult { + ConsensusValidationResult::new_with_data(ShieldedTransferTransitionActionV0 { + nullifiers, + note_commitments, + encrypted_notes, + anchor, + fee_amount, + user_fee_increase: value.user_fee_increase, + }) + } +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/mod.rs new file mode 100644 index 00000000000..868b732de81 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/mod.rs @@ -0,0 +1,62 @@ +/// transformer +pub mod transformer; +/// v0 +pub mod v0; + +use crate::state_transition_action::shielded::unshield::v0::UnshieldTransitionActionV0; +use derive_more::From; +use dpp::address_funds::PlatformAddress; +use dpp::fee::Credits; +use dpp::prelude::UserFeeIncrease; + +/// Unshield transition action +#[derive(Debug, Clone, From)] +pub enum UnshieldTransitionAction { + /// v0 + V0(UnshieldTransitionActionV0), +} + +impl UnshieldTransitionAction { + /// Get output address + pub fn output_address(&self) -> &PlatformAddress { + match self { + UnshieldTransitionAction::V0(transition) => &transition.output_address, + } + } + /// Get amount + pub fn amount(&self) -> Credits { + match self { + UnshieldTransitionAction::V0(transition) => transition.amount, + } + } + /// Get nullifiers + pub fn nullifiers(&self) -> &Vec<[u8; 32]> { + match self { + UnshieldTransitionAction::V0(transition) => &transition.nullifiers, + } + } + /// Get note commitments + pub fn note_commitments(&self) -> &Vec<[u8; 32]> { + match self { + UnshieldTransitionAction::V0(transition) => &transition.note_commitments, + } + } + /// Get encrypted notes + pub fn encrypted_notes(&self) -> &Vec> { + match self { + UnshieldTransitionAction::V0(transition) => &transition.encrypted_notes, + } + } + /// Get anchor + pub fn anchor(&self) -> &[u8; 32] { + match self { + UnshieldTransitionAction::V0(transition) => &transition.anchor, + } + } + /// fee multiplier + pub fn user_fee_increase(&self) -> UserFeeIncrease { + match self { + UnshieldTransitionAction::V0(transition) => transition.user_fee_increase, + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/transformer.rs new file mode 100644 index 00000000000..2d68b43293f --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/transformer.rs @@ -0,0 +1,28 @@ +use crate::state_transition_action::shielded::unshield::v0::UnshieldTransitionActionV0; +use crate::state_transition_action::shielded::unshield::UnshieldTransitionAction; +use dpp::prelude::ConsensusValidationResult; +use dpp::state_transition::unshield_transition::UnshieldTransition; + +impl UnshieldTransitionAction { + /// Transforms the state transition into an action + pub fn try_from_transition( + value: &UnshieldTransition, + nullifiers: Vec<[u8; 32]>, + note_commitments: Vec<[u8; 32]>, + encrypted_notes: Vec>, + anchor: [u8; 32], + ) -> ConsensusValidationResult { + match value { + UnshieldTransition::V0(v0) => { + let result = UnshieldTransitionActionV0::try_from_transition( + v0, + nullifiers, + note_commitments, + encrypted_notes, + anchor, + ); + result.map(|action| action.into()) + } + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs new file mode 100644 index 00000000000..260f437d055 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs @@ -0,0 +1,24 @@ +mod transformer; + +use dpp::address_funds::PlatformAddress; +use dpp::fee::Credits; +use dpp::prelude::UserFeeIncrease; + +/// Unshield transition action v0 +#[derive(Default, Debug, Clone)] +pub struct UnshieldTransitionActionV0 { + /// The address receiving unshielded funds + pub output_address: PlatformAddress, + /// Amount being unshielded + pub amount: Credits, + /// Nullifiers from spent notes + pub nullifiers: Vec<[u8; 32]>, + /// Note commitments for change outputs + pub note_commitments: Vec<[u8; 32]>, + /// Encrypted notes for change outputs + pub encrypted_notes: Vec>, + /// The anchor used for verification + pub anchor: [u8; 32], + /// fee multiplier + pub user_fee_increase: UserFeeIncrease, +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs new file mode 100644 index 00000000000..526d50bc61c --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs @@ -0,0 +1,24 @@ +use crate::state_transition_action::shielded::unshield::v0::UnshieldTransitionActionV0; +use dpp::prelude::ConsensusValidationResult; +use dpp::state_transition::state_transitions::shielded::unshield_transition::v0::UnshieldTransitionV0; + +impl UnshieldTransitionActionV0 { + /// Transforms the unshield transition into an action + pub fn try_from_transition( + value: &UnshieldTransitionV0, + nullifiers: Vec<[u8; 32]>, + note_commitments: Vec<[u8; 32]>, + encrypted_notes: Vec>, + anchor: [u8; 32], + ) -> ConsensusValidationResult { + ConsensusValidationResult::new_with_data(UnshieldTransitionActionV0 { + output_address: value.output_address.clone(), + amount: value.amount, + nullifiers, + note_commitments, + encrypted_notes, + anchor, + user_fee_increase: value.user_fee_increase, + }) + } +} diff --git a/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs index 2cdfa09e3f3..15e0fbf9f39 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs @@ -28,6 +28,7 @@ impl Drive { TreeType::CountSumTree => Element::empty_count_sum_tree(), TreeType::ProvableCountTree => Element::empty_provable_count_tree(), TreeType::ProvableCountSumTree => Element::empty_provable_count_sum_tree(), + TreeType::CommitmentTree => Element::empty_commitment_tree(), }; let cost_context = self.grove.insert( path, diff --git a/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs b/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs index e04c54f25ea..3b9fd00d9f4 100644 --- a/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs +++ b/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs @@ -1115,6 +1115,11 @@ impl Drive { Ok((root_hash, VerifiedAddressInfos(balances))) } + StateTransition::Shield(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) => Err(Error::Proof(ProofError::InvalidTransition( + "shielded state transitions do not support proof verification yet".to_string(), + ))), } } } diff --git a/packages/rs-platform-version/Cargo.toml b/packages/rs-platform-version/Cargo.toml index f7b7e5d2e8b..f2932c88232 100644 --- a/packages/rs-platform-version/Cargo.toml +++ b/packages/rs-platform-version/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT" thiserror = { version = "2.0.12" } bincode = { version = "=2.0.1" } versioned-feature-core = { git = "https://github.com/dashpay/versioned-feature-core", version = "1.0.0" } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "33dfd48a1718160cb333fa95424be491785f1897" } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "219ba2e73f08a9f428c9427f7ab5c73907d670bf" } [features] mock-versions = [] diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/mod.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/mod.rs index b1a027dc430..947dbd6dd46 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/mod.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/mod.rs @@ -28,6 +28,9 @@ pub struct DPPStateTransitionSerializationVersions { pub address_funds_transfer_state_transition: FeatureVersionBounds, pub address_funding_from_asset_lock_state_transition: FeatureVersionBounds, pub address_credit_withdrawal_state_transition: FeatureVersionBounds, + pub shield_state_transition: FeatureVersionBounds, + pub shielded_transfer_state_transition: FeatureVersionBounds, + pub unshield_state_transition: FeatureVersionBounds, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v1.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v1.rs index 88cd1d3c661..6524e176cf3 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v1.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v1.rs @@ -132,4 +132,19 @@ pub const STATE_TRANSITION_SERIALIZATION_VERSIONS_V1: DPPStateTransitionSerializ max_version: 0, default_current_version: 0, }, + shield_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + shielded_transfer_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + unshield_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, }; diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v2.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v2.rs index b3b5292c76d..0c1c9762333 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v2.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v2.rs @@ -132,4 +132,19 @@ pub const STATE_TRANSITION_SERIALIZATION_VERSIONS_V2: DPPStateTransitionSerializ max_version: 0, default_current_version: 0, }, + shield_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + shielded_transfer_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + unshield_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs index 23163606246..decad09ad4f 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 @@ -59,6 +59,10 @@ pub struct DriveAbciStateTransitionValidationVersions { pub address_credit_withdrawal: DriveAbciStateTransitionValidationVersion, pub address_funds_from_asset_lock: DriveAbciStateTransitionValidationVersion, pub address_funds_transfer: DriveAbciStateTransitionValidationVersion, + + pub shield_state_transition: DriveAbciStateTransitionValidationVersion, + pub shielded_transfer_state_transition: DriveAbciStateTransitionValidationVersion, + pub unshield_state_transition: DriveAbciStateTransitionValidationVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs index 5fe30a0fb84..2f2cb5e3bfc 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs @@ -200,6 +200,30 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V1: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, + shield_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + shielded_transfer_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + unshield_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, }, has_nonce_validation: 0, has_address_witness_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs index e3fa0aa7649..e9682304d7e 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs @@ -200,6 +200,30 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V2: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, + shield_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + shielded_transfer_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + unshield_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, }, has_nonce_validation: 0, has_address_witness_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs index 2fd5cc1d3bd..5803d5c492c 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs @@ -200,6 +200,30 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V3: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, + shield_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + shielded_transfer_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + unshield_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, }, has_nonce_validation: 0, has_address_witness_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v4.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v4.rs index 796f8615dca..74ccf1c3735 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 @@ -203,6 +203,30 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V4: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, + shield_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + shielded_transfer_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + unshield_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, }, has_nonce_validation: 1, // <---- changed this has_address_witness_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs index c9d4e774c33..aea4c18ce6f 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs @@ -204,6 +204,30 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V5: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, + shield_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + shielded_transfer_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + unshield_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, }, has_nonce_validation: 1, has_address_witness_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs index 3b656d6c1e4..d4c07ee6082 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs @@ -207,6 +207,30 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V6: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, + shield_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + shielded_transfer_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + unshield_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, }, has_nonce_validation: 1, has_address_witness_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs index 5f2ceb620c7..da426ac0c1a 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs @@ -201,6 +201,30 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V7: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, + shield_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: Some(0), + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + shielded_transfer_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: Some(0), + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + unshield_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: Some(0), + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, }, has_nonce_validation: 1, has_address_witness_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/mod.rs index 5391ca01e1f..ed891cdaa26 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/mod.rs @@ -48,6 +48,9 @@ pub struct DriveStateTransitionActionConvertToHighLevelOperationsMethodVersions pub address_funds_transfer_transition: FeatureVersion, pub address_credit_withdrawal_transition: FeatureVersion, pub address_funding_from_asset_lock_transition: FeatureVersion, + pub shield_transition: FeatureVersion, + pub shielded_transfer_transition: FeatureVersion, + pub unshield_transition: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v1.rs index 0e1b6602175..73019890ee7 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v1.rs @@ -49,5 +49,8 @@ pub const DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V1: DriveStateTransitionMethodV address_funds_transfer_transition: 0, address_credit_withdrawal_transition: 0, address_funding_from_asset_lock_transition: 0, + shield_transition: 0, + shielded_transfer_transition: 0, + unshield_transition: 0, }, }; diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v2.rs b/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v2.rs index 29e7442262a..4e83f05bea8 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v2.rs @@ -50,5 +50,8 @@ pub const DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V2: DriveStateTransitionMethodV address_funds_transfer_transition: 0, address_credit_withdrawal_transition: 0, address_funding_from_asset_lock_transition: 0, + shield_transition: 0, + shielded_transfer_transition: 0, + unshield_transition: 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 e7eba236c55..bb441c2b103 100644 --- a/packages/rs-platform-version/src/version/drive_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/mod.rs @@ -31,6 +31,7 @@ pub mod v3; pub mod v4; pub mod v5; pub mod v6; +pub mod v7; #[derive(Clone, Debug, Default)] pub struct DriveVersion { diff --git a/packages/rs-platform-version/src/version/drive_versions/v7.rs b/packages/rs-platform-version/src/version/drive_versions/v7.rs new file mode 100644 index 00000000000..940cd9b2f7c --- /dev/null +++ b/packages/rs-platform-version/src/version/drive_versions/v7.rs @@ -0,0 +1,118 @@ +use crate::version::drive_versions::drive_address_funds_method_versions::v1::DRIVE_ADDRESS_FUNDS_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_contract_method_versions::v2::DRIVE_CONTRACT_METHOD_VERSIONS_V2; +use crate::version::drive_versions::drive_credit_pool_method_versions::v1::CREDIT_POOL_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_document_method_versions::v2::DRIVE_DOCUMENT_METHOD_VERSIONS_V2; +use crate::version::drive_versions::drive_group_method_versions::v1::DRIVE_GROUP_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_grove_method_versions::v1::DRIVE_GROVE_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_identity_method_versions::v1::DRIVE_IDENTITY_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_state_transition_method_versions::v2::DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V2; +use crate::version::drive_versions::drive_structure_version::v1::DRIVE_STRUCTURE_V1; +use crate::version::drive_versions::drive_token_method_versions::v1::DRIVE_TOKEN_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_verify_method_versions::v1::DRIVE_VERIFY_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_vote_method_versions::v2::DRIVE_VOTE_METHOD_VERSIONS_V2; +use crate::version::drive_versions::{ + DriveAssetLockMethodVersions, DriveBalancesMethodVersions, DriveBatchOperationsMethodVersion, + DriveEstimatedCostsMethodVersions, DriveFeesMethodVersions, DriveFetchMethodVersions, + DriveInitializationMethodVersions, DriveMethodVersions, DriveOperationsMethodVersion, + DrivePlatformStateMethodVersions, DrivePlatformSystemMethodVersions, + DrivePrefundedSpecializedMethodVersions, DriveProtocolUpgradeVersions, + DriveProveMethodVersions, DriveSavedBlockTransactionsMethodVersions, + DriveSystemEstimationCostsMethodVersions, DriveVersion, +}; +use grovedb_version::version::v2::GROVE_V2; + +/// This was introduced in protocol v12 for shielded transactions. +pub const DRIVE_VERSION_V7: DriveVersion = DriveVersion { + structure: DRIVE_STRUCTURE_V1, + methods: DriveMethodVersions { + initialization: DriveInitializationMethodVersions { + create_initial_state_structure: 3, + }, + 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, + prove_state_transition: 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: 1, // Changed because we now add the address trees + }, + document: DRIVE_DOCUMENT_METHOD_VERSIONS_V2, // Changed + vote: DRIVE_VOTE_METHOD_VERSIONS_V2, + contract: DRIVE_CONTRACT_METHOD_VERSIONS_V2, + fees: DriveFeesMethodVersions { calculate_fee: 0 }, + estimated_costs: DriveEstimatedCostsMethodVersions { + add_estimation_costs_for_levels_up_to_contract: 0, + add_estimation_costs_for_levels_up_to_contract_document_type_excluded: 0, + add_estimation_costs_for_contested_document_tree_levels_up_to_contract: 0, + add_estimation_costs_for_contested_document_tree_levels_up_to_contract_document_type_excluded: 0, + }, + asset_lock: DriveAssetLockMethodVersions { + add_asset_lock_outpoint: 0, + add_estimation_costs_for_adding_asset_lock: 0, + fetch_asset_lock_outpoint_info: 0, + }, + verify: DRIVE_VERIFY_METHOD_VERSIONS_V1, + identity: DRIVE_IDENTITY_METHOD_VERSIONS_V1, + token: DRIVE_TOKEN_METHOD_VERSIONS_V1, + platform_system: DrivePlatformSystemMethodVersions { + estimation_costs: DriveSystemEstimationCostsMethodVersions { + for_total_system_credits_update: 0, + }, + }, + operations: DriveOperationsMethodVersion { + rollback_transaction: 0, + drop_cache: 0, + commit_transaction: 0, + apply_partial_batch_low_level_drive_operations: 0, + apply_partial_batch_grovedb_operations: 0, + apply_batch_low_level_drive_operations: 0, + apply_batch_grovedb_operations: 0, + }, + state_transitions: DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V2, //changed + batch_operations: DriveBatchOperationsMethodVersion { + convert_drive_operations_to_grove_operations: 0, + apply_drive_operations: 0, + }, + platform_state: DrivePlatformStateMethodVersions { + fetch_platform_state_bytes: 0, + store_platform_state_bytes: 0, + }, + fetch: DriveFetchMethodVersions { fetch_elements: 0 }, + prefunded_specialized_balances: DrivePrefundedSpecializedMethodVersions { + fetch_single: 0, + prove_single: 0, + add_prefunded_specialized_balance: 0, + add_prefunded_specialized_balance_operations: 1, + deduct_from_prefunded_specialized_balance: 1, + deduct_from_prefunded_specialized_balance_operations: 0, + estimated_cost_for_prefunded_specialized_balance_update: 0, + empty_prefunded_specialized_balance: 0, + }, + group: DRIVE_GROUP_METHOD_VERSIONS_V1, + address_funds: DRIVE_ADDRESS_FUNDS_METHOD_VERSIONS_V1, + saved_block_transactions: DriveSavedBlockTransactionsMethodVersions { + store_address_balances: 0, + fetch_address_balances: 0, + compact_address_balances: 0, + cleanup_expired_address_balances: 0, + max_blocks_before_compaction: 64, + max_addresses_before_compaction: 2048, + }, + }, + grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, + grove_version: GROVE_V2, +}; diff --git a/packages/rs-platform-version/src/version/feature_initial_protocol_versions.rs b/packages/rs-platform-version/src/version/feature_initial_protocol_versions.rs index 4607cf71d20..e004582a10e 100644 --- a/packages/rs-platform-version/src/version/feature_initial_protocol_versions.rs +++ b/packages/rs-platform-version/src/version/feature_initial_protocol_versions.rs @@ -1,3 +1,4 @@ use crate::version::ProtocolVersion; pub const ADDRESS_FUNDS_INITIAL_PROTOCOL_VERSION: ProtocolVersion = 11; +pub const SHIELDED_POOL_INITIAL_PROTOCOL_VERSION: ProtocolVersion = 12; diff --git a/packages/rs-platform-version/src/version/v12.rs b/packages/rs-platform-version/src/version/v12.rs index 486f4be1fb5..e03f4503f29 100644 --- a/packages/rs-platform-version/src/version/v12.rs +++ b/packages/rs-platform-version/src/version/v12.rs @@ -21,7 +21,7 @@ use crate::version::drive_abci_versions::drive_abci_structure_versions::v1::DRIV use crate::version::drive_abci_versions::drive_abci_validation_versions::v7::DRIVE_ABCI_VALIDATION_VERSIONS_V7; 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::v6::DRIVE_VERSION_V6; +use crate::version::drive_versions::v7::DRIVE_VERSION_V7; use crate::version::fee::v2::FEE_VERSION2; use crate::version::protocol_version::PlatformVersion; use crate::version::system_data_contract_versions::v1::SYSTEM_DATA_CONTRACT_VERSIONS_V1; @@ -30,10 +30,10 @@ use crate::version::ProtocolVersion; pub const PROTOCOL_VERSION_12: ProtocolVersion = 12; -/// This version was for Platform release 3.1.0 +/// This version was for Platform release 3.1.0 with shielded transactions support. pub const PLATFORM_V12: PlatformVersion = PlatformVersion { protocol_version: PROTOCOL_VERSION_12, - drive: DRIVE_VERSION_V6, + drive: DRIVE_VERSION_V7, drive_abci: DriveAbciVersion { structs: DRIVE_ABCI_STRUCTURE_VERSIONS_V1, methods: DRIVE_ABCI_METHOD_VERSIONS_V7, From e4c1cf0f3574f829c2b4c44b3758824f4d1f3ee7 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 10 Feb 2026 00:08:47 +0000 Subject: [PATCH 02/40] transactions --- packages/rs-dpp/src/shielded/mod.rs | 28 ++ .../shielded/shield_transition/v0/mod.rs | 18 +- .../v0/state_transition_validation.rs | 129 ++++++++- .../shielded_transfer_transition/v0/mod.rs | 15 +- .../v0/state_transition_like.rs | 10 +- .../v0/state_transition_validation.rs | 65 ++++- .../shielded/unshield_transition/v0/mod.rs | 18 +- .../v0/state_transition_like.rs | 10 +- .../v0/state_transition_validation.rs | 85 +++++- .../state_transition/state_transitions/mod.rs | 7 + .../state_transitions/shield/mod.rs | 55 ++++ .../shield/transform_into_action/mod.rs | 1 + .../shield/transform_into_action/v0/mod.rs | 61 ++++ .../shielded_transfer/mod.rs | 46 +++ .../transform_into_action/mod.rs | 1 + .../transform_into_action/v0/mod.rs | 72 +++++ .../state_transitions/unshield/mod.rs | 46 +++ .../unshield/transform_into_action/mod.rs | 1 + .../unshield/transform_into_action/v0/mod.rs | 62 ++++ .../state_transition/transformer/mod.rs | 30 +- packages/rs-drive/src/drive/shielded/paths.rs | 36 +++ .../shielded/mod.rs | 266 +++++++++++++++++- .../shielded/shield/transformer.rs | 4 + .../shielded/shield/v0/mod.rs | 4 + .../shielded/shield/v0/transformer.rs | 4 + .../shielded/shielded_transfer/transformer.rs | 4 + .../shielded/shielded_transfer/v0/mod.rs | 4 + .../shielded_transfer/v0/transformer.rs | 4 + .../shielded/unshield/transformer.rs | 5 + .../shielded/unshield/v0/mod.rs | 4 + .../shielded/unshield/v0/transformer.rs | 5 + 31 files changed, 1066 insertions(+), 34 deletions(-) create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs diff --git a/packages/rs-dpp/src/shielded/mod.rs b/packages/rs-dpp/src/shielded/mod.rs index cbf5881ef7e..3e3f765b905 100644 --- a/packages/rs-dpp/src/shielded/mod.rs +++ b/packages/rs-dpp/src/shielded/mod.rs @@ -1,4 +1,6 @@ use bincode::{Decode, Encode}; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; /// Parameters for a shielded pool, stored as an Item in the pool's subtree #[derive(Debug, Clone, Encode, Decode, Default, PartialEq)] @@ -6,3 +8,29 @@ pub struct ShieldedPoolParams { /// Counter for commitment tree checkpoint IDs (monotonically increasing) pub checkpoint_id_counter: u64, } + +/// A serialized Orchard action extracted from a bundle. +/// +/// Each action represents one spend-and-output pair. The fields are raw bytes +/// suitable for serialization. Validation code reconstructs orchard types from +/// these bytes using grovedb-commitment-tree re-exports. +#[derive(Debug, Clone, Encode, Decode, PartialEq)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +pub struct SerializedAction { + /// Nullifier of the spent note (Nullifier::to_bytes()) + pub nullifier: [u8; 32], + /// Randomized spend validating key + pub rk: [u8; 32], + /// Extracted note commitment (ExtractedNoteCommitment::to_bytes()) + pub cmx: [u8; 32], + /// Encrypted note ciphertext (epk + enc + out from TransmittedNoteCiphertext) + pub encrypted_note: Vec, + /// Value commitment (cv_net bytes) + pub cv_net: [u8; 32], + /// RedPallas spend authorization signature (64 bytes) + pub spend_auth_sig: Vec, +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs index 3e82a6919db..085e6449d6a 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs @@ -8,6 +8,7 @@ use std::collections::BTreeMap; use crate::address_funds::{AddressFundsFeeStrategy, AddressWitness, PlatformAddress}; use crate::fee::Credits; use crate::prelude::{AddressNonce, UserFeeIncrease}; +use crate::shielded::SerializedAction; use crate::ProtocolError; use bincode::{Decode, Encode}; use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize, PlatformSignable}; @@ -32,10 +33,25 @@ use serde::{Deserialize, Serialize}; #[platform_serialize(unversioned)] #[derive(Default)] pub struct ShieldTransitionV0 { + /// Address inputs funding the shield (address -> nonce + amount) pub inputs: BTreeMap, - pub orchard_bundle: Vec, + /// Orchard actions (spend-output pairs) + pub actions: Vec, + /// Bundle flags (spends_enabled | outputs_enabled) + pub flags: u8, + /// Net value flowing into/out of the shielded pool + pub value_balance: i64, + /// Merkle root of the commitment tree at time of bundle creation + pub anchor: [u8; 32], + /// Halo2 proof bytes + pub proof: Vec, + /// RedPallas binding signature (64 bytes) + pub binding_signature: Vec, + /// Fee payment strategy pub fee_strategy: AddressFundsFeeStrategy, + /// Fee multiplier pub user_fee_increase: UserFeeIncrease, + /// Address witness signatures (excluded from sig hash) #[platform_signable(exclude_from_sig_hash)] pub input_witnesses: Vec, } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs index f5f82472ae9..003d80239aa 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs @@ -1,14 +1,139 @@ +use crate::consensus::basic::overflow_error::OverflowError; +use crate::consensus::basic::state_transition::{ + FeeStrategyDuplicateError, FeeStrategyEmptyError, FeeStrategyTooManyStepsError, + InputBelowMinimumError, InputWitnessCountMismatchError, TransitionNoInputsError, +}; +use crate::consensus::basic::BasicError; use crate::state_transition::shield_transition::v0::ShieldTransitionV0; use crate::state_transition::StateTransitionStructureValidation; use crate::validation::SimpleConsensusValidationResult; use platform_version::version::PlatformVersion; +use std::collections::HashSet; impl StateTransitionStructureValidation for ShieldTransitionV0 { fn validate_structure( &self, - _platform_version: &PlatformVersion, + platform_version: &PlatformVersion, ) -> SimpleConsensusValidationResult { - // TODO: Add proper structure validation for shield transition + // Actions must not be empty + if self.actions.is_empty() { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Shield transition must have at least one action".to_string(), + )) + .into(), + ); + } + + // Inputs must not be empty (shield requires address funding) + if self.inputs.is_empty() { + return SimpleConsensusValidationResult::new_with_error( + BasicError::TransitionNoInputsError(TransitionNoInputsError::new()).into(), + ); + } + + // Input witnesses must match inputs count + if self.inputs.len() != self.input_witnesses.len() { + return SimpleConsensusValidationResult::new_with_error( + BasicError::InputWitnessCountMismatchError(InputWitnessCountMismatchError::new( + self.inputs.len().min(u16::MAX as usize) as u16, + self.input_witnesses.len().min(u16::MAX as usize) as u16, + )) + .into(), + ); + } + + // Validate each input amount is > 0 + let min_input_amount = platform_version + .dpp + .state_transitions + .address_funds + .min_input_amount; + for (_nonce, amount) in self.inputs.values() { + if *amount < min_input_amount { + return SimpleConsensusValidationResult::new_with_error( + BasicError::InputBelowMinimumError(InputBelowMinimumError::new( + *amount, + min_input_amount, + )) + .into(), + ); + } + } + + // value_balance must be negative (credits flowing into pool) + if self.value_balance >= 0 { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Shield transition value_balance must be negative (credits flow into pool)" + .to_string(), + )) + .into(), + ); + } + + // Proof must not be empty + if self.proof.is_empty() { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Shield transition proof must not be empty".to_string(), + )) + .into(), + ); + } + + // Binding signature must be exactly 64 bytes + if self.binding_signature.len() != 64 { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Shield transition binding_signature must be exactly 64 bytes".to_string(), + )) + .into(), + ); + } + + // Each action's spend_auth_sig must be exactly 64 bytes + for action in &self.actions { + if action.spend_auth_sig.len() != 64 { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Each action spend_auth_sig must be exactly 64 bytes".to_string(), + )) + .into(), + ); + } + } + + // Fee strategy validation (reuse address funds patterns) + if self.fee_strategy.is_empty() { + return SimpleConsensusValidationResult::new_with_error( + BasicError::FeeStrategyEmptyError(FeeStrategyEmptyError::new()).into(), + ); + } + + let max_fee_strategies = platform_version + .dpp + .state_transitions + .max_address_fee_strategies as usize; + if self.fee_strategy.len() > max_fee_strategies { + return SimpleConsensusValidationResult::new_with_error( + BasicError::FeeStrategyTooManyStepsError(FeeStrategyTooManyStepsError::new( + self.fee_strategy.len().min(u8::MAX as usize) as u8, + max_fee_strategies.min(u8::MAX as usize) as u8, + )) + .into(), + ); + } + + let mut seen = HashSet::with_capacity(self.fee_strategy.len()); + for step in &self.fee_strategy { + if !seen.insert(step) { + return SimpleConsensusValidationResult::new_with_error( + BasicError::FeeStrategyDuplicateError(FeeStrategyDuplicateError::new()).into(), + ); + } + } + SimpleConsensusValidationResult::new() } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs index 5c1ab56b259..a14194c03b6 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs @@ -4,6 +4,7 @@ mod types; mod version; use crate::prelude::UserFeeIncrease; +use crate::shielded::SerializedAction; use crate::ProtocolError; use bincode::{Decode, Encode}; use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize, PlatformSignable}; @@ -28,6 +29,18 @@ use serde::{Deserialize, Serialize}; #[platform_serialize(unversioned)] #[derive(Default)] pub struct ShieldedTransferTransitionV0 { - pub orchard_bundle: Vec, + /// Orchard actions (spend-output pairs) + pub actions: Vec, + /// Bundle flags (spends_enabled | outputs_enabled) + pub flags: u8, + /// Net value balance (fee amount extracted from shielded pool) + pub value_balance: i64, + /// Merkle root of the commitment tree used for spends + pub anchor: [u8; 32], + /// Halo2 proof bytes + pub proof: Vec, + /// RedPallas binding signature (64 bytes) + pub binding_signature: Vec, + /// Fee multiplier pub user_fee_increase: UserFeeIncrease, } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_like.rs index 12efcc4ae81..df051601d51 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_like.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_like.rs @@ -32,11 +32,13 @@ impl StateTransitionLike for ShieldedTransferTransitionV0 { vec![] } - /// For ZK-only transitions, uniqueness comes from nullifiers in the bundle, - /// but at the DPP level we use the hash of the orchard bundle as a unique identifier. + /// For ZK-only transitions, uniqueness comes from nullifiers in the actions. + /// Each nullifier can only be used once, making them natural unique identifiers. fn unique_identifiers(&self) -> Vec { - use crate::util::hash::hash_single; - vec![hex::encode(hash_single(&self.orchard_bundle))] + self.actions + .iter() + .map(|action| hex::encode(action.nullifier)) + .collect() } fn user_fee_increase(&self) -> UserFeeIncrease { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs index d9d398e4da6..1c0ba7f2a06 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs @@ -1,3 +1,5 @@ +use crate::consensus::basic::overflow_error::OverflowError; +use crate::consensus::basic::BasicError; use crate::state_transition::shielded_transfer_transition::v0::ShieldedTransferTransitionV0; use crate::state_transition::StateTransitionStructureValidation; use crate::validation::SimpleConsensusValidationResult; @@ -8,7 +10,68 @@ impl StateTransitionStructureValidation for ShieldedTransferTransitionV0 { &self, _platform_version: &PlatformVersion, ) -> SimpleConsensusValidationResult { - // TODO: Add proper structure validation for shielded transfer transition + // Actions must not be empty + if self.actions.is_empty() { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Shielded transfer transition must have at least one action".to_string(), + )) + .into(), + ); + } + + // value_balance must be >= 0 (fee extracted from pool, 0 means no fee) + if self.value_balance < 0 { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Shielded transfer value_balance must be non-negative (fee only)".to_string(), + )) + .into(), + ); + } + + // Proof must not be empty + if self.proof.is_empty() { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Shielded transfer proof must not be empty".to_string(), + )) + .into(), + ); + } + + // Binding signature must be exactly 64 bytes + if self.binding_signature.len() != 64 { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Shielded transfer binding_signature must be exactly 64 bytes".to_string(), + )) + .into(), + ); + } + + // Each action's spend_auth_sig must be exactly 64 bytes + for action in &self.actions { + if action.spend_auth_sig.len() != 64 { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Each action spend_auth_sig must be exactly 64 bytes".to_string(), + )) + .into(), + ); + } + } + + // Anchor must not be all zeros + if self.anchor == [0u8; 32] { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Shielded transfer anchor must not be all zeros".to_string(), + )) + .into(), + ); + } + SimpleConsensusValidationResult::new() } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs index 172c3668ac9..581cb0eac13 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs @@ -5,6 +5,7 @@ mod version; use crate::address_funds::PlatformAddress; use crate::prelude::UserFeeIncrease; +use crate::shielded::SerializedAction; use crate::ProtocolError; use bincode::{Decode, Encode}; use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize, PlatformSignable}; @@ -27,10 +28,23 @@ use serde::{Deserialize, Serialize}; serde(rename_all = "camelCase") )] #[platform_serialize(unversioned)] -#[derive(Default)] pub struct UnshieldTransitionV0 { + /// Address receiving the unshielded funds pub output_address: PlatformAddress, + /// Amount being unshielded (in credits) pub amount: u64, - pub orchard_bundle: Vec, + /// Orchard actions (spend-output pairs) + pub actions: Vec, + /// Bundle flags (spends_enabled | outputs_enabled) + pub flags: u8, + /// Net value balance (amount + fee flowing out of shielded pool) + pub value_balance: i64, + /// Merkle root of the commitment tree used for spends + pub anchor: [u8; 32], + /// Halo2 proof bytes + pub proof: Vec, + /// RedPallas binding signature (64 bytes) + pub binding_signature: Vec, + /// Fee multiplier pub user_fee_increase: UserFeeIncrease, } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_like.rs index 3b705e88146..f3c508f0f0e 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_like.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_like.rs @@ -32,11 +32,13 @@ impl StateTransitionLike for UnshieldTransitionV0 { vec![] } - /// For ZK-only transitions, uniqueness comes from nullifiers in the bundle, - /// but at the DPP level we use the hash of the orchard bundle as a unique identifier. + /// For ZK-only transitions, uniqueness comes from nullifiers in the actions. + /// Each nullifier can only be used once, making them natural unique identifiers. fn unique_identifiers(&self) -> Vec { - use crate::util::hash::hash_single; - vec![hex::encode(hash_single(&self.orchard_bundle))] + self.actions + .iter() + .map(|action| hex::encode(action.nullifier)) + .collect() } fn user_fee_increase(&self) -> UserFeeIncrease { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs index 533c29ff947..6b20a21e271 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs @@ -1,3 +1,5 @@ +use crate::consensus::basic::overflow_error::OverflowError; +use crate::consensus::basic::BasicError; use crate::state_transition::unshield_transition::v0::UnshieldTransitionV0; use crate::state_transition::StateTransitionStructureValidation; use crate::validation::SimpleConsensusValidationResult; @@ -8,7 +10,88 @@ impl StateTransitionStructureValidation for UnshieldTransitionV0 { &self, _platform_version: &PlatformVersion, ) -> SimpleConsensusValidationResult { - // TODO: Add proper structure validation for unshield transition + // Actions must not be empty + if self.actions.is_empty() { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Unshield transition must have at least one action".to_string(), + )) + .into(), + ); + } + + // Amount must be > 0 + if self.amount == 0 { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Unshield transition amount must be greater than zero".to_string(), + )) + .into(), + ); + } + + // value_balance must be positive (credits flowing out of pool = amount + fee) + if self.value_balance <= 0 { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Unshield transition value_balance must be positive".to_string(), + )) + .into(), + ); + } + + // value_balance must be >= amount (value_balance = amount + fee) + if (self.value_balance as u64) < self.amount { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Unshield transition value_balance must be >= amount".to_string(), + )) + .into(), + ); + } + + // Proof must not be empty + if self.proof.is_empty() { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Unshield transition proof must not be empty".to_string(), + )) + .into(), + ); + } + + // Binding signature must be exactly 64 bytes + if self.binding_signature.len() != 64 { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Unshield transition binding_signature must be exactly 64 bytes".to_string(), + )) + .into(), + ); + } + + // Each action's spend_auth_sig must be exactly 64 bytes + for action in &self.actions { + if action.spend_auth_sig.len() != 64 { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Each action spend_auth_sig must be exactly 64 bytes".to_string(), + )) + .into(), + ); + } + } + + // Anchor must not be all zeros + if self.anchor == [0u8; 32] { + return SimpleConsensusValidationResult::new_with_error( + BasicError::OverflowError(OverflowError::new( + "Unshield transition anchor must not be all zeros".to_string(), + )) + .into(), + ); + } + SimpleConsensusValidationResult::new() } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs index 95ec1d27704..7693c43f39f 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs @@ -41,6 +41,13 @@ pub mod address_credit_withdrawal; pub mod address_funds_transfer; mod identity_top_up_from_addresses; +/// Module for shield transition validation +pub mod shield; +/// Module for shielded transfer transition validation +pub mod shielded_transfer; +/// Module for unshield transition validation +pub mod unshield; + /// The validation mode we are using #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum ValidationMode { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/mod.rs new file mode 100644 index 00000000000..1c51730f6a7 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/mod.rs @@ -0,0 +1,55 @@ +mod transform_into_action; + +use dpp::address_funds::PlatformAddress; +use dpp::fee::Credits; +use dpp::prelude::AddressNonce; +use dpp::state_transition::shield_transition::ShieldTransition; +use dpp::validation::ConsensusValidationResult; +use drive::state_transition_action::StateTransitionAction; +use std::collections::BTreeMap; + +use crate::error::execution::ExecutionError; +use crate::error::Error; +use crate::execution::validation::state_transition::shield::transform_into_action::v0::ShieldStateTransitionTransformIntoActionValidationV0; +use crate::platform_types::platform::PlatformRef; +use crate::rpc::core::CoreRPCLike; + +use crate::platform_types::platform_state::PlatformStateV0Methods; + +/// A trait to transform into an action for shield transition +pub trait StateTransitionShieldTransitionActionTransformer { + /// Transform into an action for shield transition + fn transform_into_action_for_shield_transition( + &self, + platform: &PlatformRef, + inputs_with_remaining_balance: BTreeMap, + ) -> Result, Error>; +} + +impl StateTransitionShieldTransitionActionTransformer for ShieldTransition { + fn transform_into_action_for_shield_transition( + &self, + platform: &PlatformRef, + inputs_with_remaining_balance: BTreeMap, + ) -> Result, Error> { + let platform_version = platform.state.current_platform_version()?; + + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .shield_state_transition + .transform_into_action + { + 0 => self.transform_into_action_v0( + inputs_with_remaining_balance, + platform_version, + ), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "shield transition: transform_into_action".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/mod.rs new file mode 100644 index 00000000000..9a1925de7fc --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/mod.rs @@ -0,0 +1 @@ +pub(crate) mod v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs new file mode 100644 index 00000000000..aee9fb4fee8 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs @@ -0,0 +1,61 @@ +use crate::error::Error; +use dpp::address_funds::PlatformAddress; +use dpp::fee::Credits; +use dpp::prelude::{AddressNonce, ConsensusValidationResult}; +use dpp::state_transition::shield_transition::ShieldTransition; +use dpp::version::PlatformVersion; +use drive::state_transition_action::shielded::shield::ShieldTransitionAction; +use drive::state_transition_action::StateTransitionAction; +use std::collections::BTreeMap; + +pub(in crate::execution::validation::state_transition::state_transitions::shield) trait ShieldStateTransitionTransformIntoActionValidationV0 +{ + fn transform_into_action_v0( + &self, + inputs_with_remaining_balance: BTreeMap, + platform_version: &PlatformVersion, + ) -> Result, Error>; +} + +impl ShieldStateTransitionTransformIntoActionValidationV0 for ShieldTransition { + fn transform_into_action_v0( + &self, + inputs_with_remaining_balance: BTreeMap, + _platform_version: &PlatformVersion, + ) -> Result, Error> { + // Extract note commitments and encrypted notes from serialized actions + let note_commitments: Vec<[u8; 32]> = match self { + ShieldTransition::V0(v0) => v0.actions.iter().map(|a| a.cmx).collect(), + }; + let encrypted_notes: Vec> = match self { + ShieldTransition::V0(v0) => { + v0.actions.iter().map(|a| a.encrypted_note.clone()).collect() + } + }; + + // The value_balance is negative for shield (funds flowing into the pool) + let shield_amount = match self { + ShieldTransition::V0(v0) => (-v0.value_balance) as u64, + }; + + // TODO: Read current shielded pool state from GroveDB. + // These should be fetched from the shielded pool tree in GroveDB: + // - current_checkpoint_id: the latest checkpoint epoch ID + // - current_total_balance: the running total balance of the shielded pool + // For now, use default values until the GroveDB API for shielded pool is available. + let current_checkpoint_id: u64 = 0; + let current_total_balance: Credits = 0; + + let result = ShieldTransitionAction::try_from_transition( + self, + inputs_with_remaining_balance, + shield_amount, + note_commitments, + encrypted_notes, + current_checkpoint_id, + current_total_balance, + ); + + Ok(result.map(|action| action.into())) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/mod.rs new file mode 100644 index 00000000000..6fae8a40d0a --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/mod.rs @@ -0,0 +1,46 @@ +mod transform_into_action; + +use dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition; +use dpp::validation::ConsensusValidationResult; +use drive::state_transition_action::StateTransitionAction; + +use crate::error::execution::ExecutionError; +use crate::error::Error; +use crate::execution::validation::state_transition::shielded_transfer::transform_into_action::v0::ShieldedTransferStateTransitionTransformIntoActionValidationV0; +use crate::platform_types::platform::PlatformRef; +use crate::rpc::core::CoreRPCLike; + +use crate::platform_types::platform_state::PlatformStateV0Methods; + +/// A trait to transform into an action for shielded transfer transition +pub trait StateTransitionShieldedTransferTransitionActionTransformer { + /// Transform into an action for shielded transfer transition + fn transform_into_action_for_shielded_transfer_transition( + &self, + platform: &PlatformRef, + ) -> Result, Error>; +} + +impl StateTransitionShieldedTransferTransitionActionTransformer for ShieldedTransferTransition { + fn transform_into_action_for_shielded_transfer_transition( + &self, + platform: &PlatformRef, + ) -> Result, Error> { + let platform_version = platform.state.current_platform_version()?; + + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .shielded_transfer_state_transition + .transform_into_action + { + 0 => self.transform_into_action_v0(platform_version), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "shielded transfer transition: transform_into_action".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/mod.rs new file mode 100644 index 00000000000..9a1925de7fc --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/mod.rs @@ -0,0 +1 @@ +pub(crate) mod v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs new file mode 100644 index 00000000000..d61eea10c59 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs @@ -0,0 +1,72 @@ +use crate::error::Error; +use dpp::fee::Credits; +use dpp::prelude::ConsensusValidationResult; +use dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition; +use dpp::version::PlatformVersion; +use drive::state_transition_action::shielded::shielded_transfer::ShieldedTransferTransitionAction; +use drive::state_transition_action::StateTransitionAction; + +pub(in crate::execution::validation::state_transition::state_transitions::shielded_transfer) trait ShieldedTransferStateTransitionTransformIntoActionValidationV0 +{ + fn transform_into_action_v0( + &self, + platform_version: &PlatformVersion, + ) -> Result, Error>; +} + +impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 + for ShieldedTransferTransition +{ + fn transform_into_action_v0( + &self, + _platform_version: &PlatformVersion, + ) -> Result, Error> { + // Extract nullifiers, note commitments, and encrypted notes from serialized actions + let nullifiers: Vec<[u8; 32]> = match self { + ShieldedTransferTransition::V0(v0) => { + v0.actions.iter().map(|a| a.nullifier).collect() + } + }; + let note_commitments: Vec<[u8; 32]> = match self { + ShieldedTransferTransition::V0(v0) => v0.actions.iter().map(|a| a.cmx).collect(), + }; + let encrypted_notes: Vec> = match self { + ShieldedTransferTransition::V0(v0) => { + v0.actions.iter().map(|a| a.encrypted_note.clone()).collect() + } + }; + + // The anchor from the transition (Merkle root of commitment tree) + let anchor: [u8; 32] = match self { + ShieldedTransferTransition::V0(v0) => v0.anchor, + }; + + // The value_balance is positive for shielded transfer (fee extracted from pool) + let fee_amount: Credits = match self { + ShieldedTransferTransition::V0(v0) => v0.value_balance as u64, + }; + + // TODO: Read current shielded pool state from GroveDB. + // These should be fetched from the shielded pool tree in GroveDB: + // - current_checkpoint_id: the latest checkpoint epoch ID + // - current_total_balance: the running total balance of the shielded pool + // For now, use default values until the GroveDB API for shielded pool is available. + let current_checkpoint_id: u64 = 0; + let current_total_balance: Credits = 0; + + // TODO: Verify the anchor exists in the commitment tree before proceeding. + + let result = ShieldedTransferTransitionAction::try_from_transition( + self, + nullifiers, + note_commitments, + encrypted_notes, + anchor, + fee_amount, + current_checkpoint_id, + current_total_balance, + ); + + Ok(result.map(|action| action.into())) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/mod.rs new file mode 100644 index 00000000000..91eb04921c1 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/mod.rs @@ -0,0 +1,46 @@ +mod transform_into_action; + +use dpp::state_transition::unshield_transition::UnshieldTransition; +use dpp::validation::ConsensusValidationResult; +use drive::state_transition_action::StateTransitionAction; + +use crate::error::execution::ExecutionError; +use crate::error::Error; +use crate::execution::validation::state_transition::unshield::transform_into_action::v0::UnshieldStateTransitionTransformIntoActionValidationV0; +use crate::platform_types::platform::PlatformRef; +use crate::rpc::core::CoreRPCLike; + +use crate::platform_types::platform_state::PlatformStateV0Methods; + +/// A trait to transform into an action for unshield transition +pub trait StateTransitionUnshieldTransitionActionTransformer { + /// Transform into an action for unshield transition + fn transform_into_action_for_unshield_transition( + &self, + platform: &PlatformRef, + ) -> Result, Error>; +} + +impl StateTransitionUnshieldTransitionActionTransformer for UnshieldTransition { + fn transform_into_action_for_unshield_transition( + &self, + platform: &PlatformRef, + ) -> Result, Error> { + let platform_version = platform.state.current_platform_version()?; + + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .unshield_state_transition + .transform_into_action + { + 0 => self.transform_into_action_v0(platform_version), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "unshield transition: transform_into_action".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/mod.rs new file mode 100644 index 00000000000..9a1925de7fc --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/mod.rs @@ -0,0 +1 @@ +pub(crate) mod v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs new file mode 100644 index 00000000000..96833110508 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs @@ -0,0 +1,62 @@ +use crate::error::Error; +use dpp::fee::Credits; +use dpp::prelude::ConsensusValidationResult; +use dpp::state_transition::unshield_transition::UnshieldTransition; +use dpp::version::PlatformVersion; +use drive::state_transition_action::shielded::unshield::UnshieldTransitionAction; +use drive::state_transition_action::StateTransitionAction; + +pub(in crate::execution::validation::state_transition::state_transitions::unshield) trait UnshieldStateTransitionTransformIntoActionValidationV0 +{ + fn transform_into_action_v0( + &self, + platform_version: &PlatformVersion, + ) -> Result, Error>; +} + +impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransition { + fn transform_into_action_v0( + &self, + _platform_version: &PlatformVersion, + ) -> Result, Error> { + // Extract nullifiers, note commitments, and encrypted notes from serialized actions + let nullifiers: Vec<[u8; 32]> = match self { + UnshieldTransition::V0(v0) => v0.actions.iter().map(|a| a.nullifier).collect(), + }; + let note_commitments: Vec<[u8; 32]> = match self { + UnshieldTransition::V0(v0) => v0.actions.iter().map(|a| a.cmx).collect(), + }; + let encrypted_notes: Vec> = match self { + UnshieldTransition::V0(v0) => { + v0.actions.iter().map(|a| a.encrypted_note.clone()).collect() + } + }; + + // The anchor from the transition (Merkle root of commitment tree) + let anchor: [u8; 32] = match self { + UnshieldTransition::V0(v0) => v0.anchor, + }; + + // TODO: Read current shielded pool state from GroveDB. + // These should be fetched from the shielded pool tree in GroveDB: + // - current_checkpoint_id: the latest checkpoint epoch ID + // - current_total_balance: the running total balance of the shielded pool + // For now, use default values until the GroveDB API for shielded pool is available. + let current_checkpoint_id: u64 = 0; + let current_total_balance: Credits = 0; + + // TODO: Verify the anchor exists in the commitment tree before proceeding. + + let result = UnshieldTransitionAction::try_from_transition( + self, + nullifiers, + note_commitments, + encrypted_notes, + anchor, + current_checkpoint_id, + current_total_balance, + ); + + Ok(result.map(|action| action.into())) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs index 6995947ab3b..2a959e5a850 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs @@ -7,6 +7,9 @@ use crate::execution::validation::state_transition::address_funds_transfer::Stat use crate::execution::validation::state_transition::identity_create::StateTransitionActionTransformerForIdentityCreateTransitionV0; use crate::execution::validation::state_transition::identity_create_from_addresses::StateTransitionActionTransformerForIdentityCreateFromAddressesTransitionV0; use crate::execution::validation::state_transition::identity_top_up::StateTransitionIdentityTopUpTransitionActionTransformer; +use crate::execution::validation::state_transition::shield::StateTransitionShieldTransitionActionTransformer; +use crate::execution::validation::state_transition::shielded_transfer::StateTransitionShieldedTransferTransitionActionTransformer; +use crate::execution::validation::state_transition::unshield::StateTransitionUnshieldTransitionActionTransformer; use crate::execution::validation::state_transition::ValidationMode; use crate::platform_types::platform::PlatformRef; use crate::rpc::core::CoreRPCLike; @@ -229,20 +232,23 @@ impl StateTransitionActionTransformer for StateTransition { remaining_address_input_balances.clone(), ) } - StateTransition::Shield(_) => { - Err(Error::Execution(ExecutionError::CorruptedCodeExecution( - "shield transition transformer is not yet implemented", - ))) + StateTransition::Shield(st) => { + let Some(remaining_address_input_balances) = remaining_address_input_balances + else { + return Err(Error::Execution(ExecutionError::CorruptedCodeExecution( + "we must have remaining address input balances", + ))); + }; + st.transform_into_action_for_shield_transition( + platform, + remaining_address_input_balances.clone(), + ) } - StateTransition::ShieldedTransfer(_) => { - Err(Error::Execution(ExecutionError::CorruptedCodeExecution( - "shielded transfer transition transformer is not yet implemented", - ))) + StateTransition::ShieldedTransfer(st) => { + st.transform_into_action_for_shielded_transfer_transition(platform) } - StateTransition::Unshield(_) => { - Err(Error::Execution(ExecutionError::CorruptedCodeExecution( - "unshield transition transformer is not yet implemented", - ))) + StateTransition::Unshield(st) => { + st.transform_into_action_for_unshield_transition(platform) } } } diff --git a/packages/rs-drive/src/drive/shielded/paths.rs b/packages/rs-drive/src/drive/shielded/paths.rs index ef76337c58f..8318179042c 100644 --- a/packages/rs-drive/src/drive/shielded/paths.rs +++ b/packages/rs-drive/src/drive/shielded/paths.rs @@ -86,6 +86,42 @@ pub fn shielded_anchors_path_vec() -> Vec> { ] } +/// Path to the commitments tree as a vec: [AddressBalances, "s", [1]] +pub fn shielded_credit_pool_commitments_path_vec() -> Vec> { + vec![ + vec![RootTree::AddressBalances as u8], + SHIELDED_CREDIT_POOL_KEY.to_vec(), + vec![SHIELDED_COMMITMENTS_KEY], + ] +} + +/// Path to the nullifiers tree as a vec: [AddressBalances, "s", [2]] +pub fn shielded_credit_pool_nullifiers_path_vec() -> Vec> { + vec![ + vec![RootTree::AddressBalances as u8], + SHIELDED_CREDIT_POOL_KEY.to_vec(), + vec![SHIELDED_NULLIFIERS_KEY], + ] +} + +/// Path to the encrypted notes tree as a vec: [AddressBalances, "s", [3]] +pub fn shielded_credit_pool_encrypted_notes_path_vec() -> Vec> { + vec![ + vec![RootTree::AddressBalances as u8], + SHIELDED_CREDIT_POOL_KEY.to_vec(), + vec![SHIELDED_ENCRYPTED_NOTES_KEY], + ] +} + +/// Path to the anchors credit pool as a vec: [AddressBalances, "a", "s"] +pub fn shielded_anchors_credit_pool_path_vec() -> Vec> { + vec![ + vec![RootTree::AddressBalances as u8], + SHIELDED_ANCHORS_KEY.to_vec(), + SHIELDED_CREDIT_POOL_KEY.to_vec(), + ] +} + /// Path to the credit pool anchors: [AddressBalances, "a", "s"] pub fn shielded_anchors_credit_pool_path() -> [&'static [u8]; 3] { [ diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs index d7c54b2cbeb..9a26559541f 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs @@ -1,11 +1,20 @@ +use crate::drive::shielded::paths::{ + shielded_credit_pool_commitments_path_vec, shielded_credit_pool_encrypted_notes_path_vec, + shielded_credit_pool_nullifiers_path_vec, shielded_credit_pool_path_vec, + SHIELDED_PARAMS_KEY, SHIELDED_TOTAL_BALANCE_KEY, +}; use crate::error::Error; use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; use crate::state_transition_action::shielded::shield::ShieldTransitionAction; use crate::state_transition_action::shielded::shielded_transfer::ShieldedTransferTransitionAction; use crate::state_transition_action::shielded::unshield::UnshieldTransitionAction; +use crate::util::batch::drive_op_batch::AddressFundsOperationType; use crate::util::batch::DriveOperation; use dpp::block::epoch::Epoch; +use dpp::shielded::ShieldedPoolParams; use dpp::version::PlatformVersion; +use grovedb::batch::QualifiedGroveDbOp; +use grovedb::Element; impl DriveHighLevelOperationConverter for ShieldTransitionAction { fn into_high_level_drive_operations<'a>( @@ -13,8 +22,84 @@ impl DriveHighLevelOperationConverter for ShieldTransitionAction { _epoch: &Epoch, _platform_version: &PlatformVersion, ) -> Result>, Error> { - // TODO: Implement shield drive operations - Ok(vec![]) + match self { + ShieldTransitionAction::V0(v0) => { + let mut ops: Vec> = Vec::new(); + + // 1. Debit each input address: set remaining balance + for (address, (nonce, remaining_balance)) in v0.inputs_with_remaining_balance { + ops.push(DriveOperation::AddressFundsOperation( + AddressFundsOperationType::SetBalanceToAddress { + address, + nonce, + balance: remaining_balance, + }, + )); + } + + let commitments_path = shielded_credit_pool_commitments_path_vec(); + let encrypted_notes_path = shielded_credit_pool_encrypted_notes_path_vec(); + let pool_path = shielded_credit_pool_path_vec(); + + // We start with the current checkpoint_id and increment for each commitment + let mut next_checkpoint_id = v0.current_checkpoint_id; + + // 2. Append each note commitment to the commitment tree + for cmx in v0.note_commitments.iter() { + next_checkpoint_id += 1; + ops.push(DriveOperation::GroveDBOperation( + QualifiedGroveDbOp::commitment_tree_append_op( + commitments_path.clone(), + vec![], // key is empty for commitment tree append + *cmx, + next_checkpoint_id, + ), + )); + } + + // 3. Insert encrypted notes keyed by their commitment + for (cmx, encrypted_note) in + v0.note_commitments.iter().zip(v0.encrypted_notes.iter()) + { + ops.push(DriveOperation::GroveDBOperation( + QualifiedGroveDbOp::insert_only_op( + encrypted_notes_path.clone(), + cmx.to_vec(), + Element::new_item(encrypted_note.clone()), + ), + )); + } + + // 4. Update total balance SumItem: current_total_balance + shield_amount + let new_total_balance = v0.current_total_balance + v0.shield_amount; + ops.push(DriveOperation::GroveDBOperation( + QualifiedGroveDbOp::insert_or_replace_op( + pool_path.clone(), + vec![SHIELDED_TOTAL_BALANCE_KEY], + Element::new_sum_item(new_total_balance as i64), + ), + )); + + // 5. Update params with incremented checkpoint_id_counter + let new_params = ShieldedPoolParams { + checkpoint_id_counter: next_checkpoint_id, + }; + let encoded_params = + bincode::encode_to_vec(&new_params, bincode::config::standard()) + .expect("expected to encode shielded pool params"); + ops.push(DriveOperation::GroveDBOperation( + QualifiedGroveDbOp::insert_or_replace_op( + pool_path, + vec![SHIELDED_PARAMS_KEY], + Element::new_item(encoded_params), + ), + )); + + // TODO: Record anchor after batch is applied (needs post-batch semantics) + + Ok(ops) + } + } } } @@ -24,8 +109,88 @@ impl DriveHighLevelOperationConverter for ShieldedTransferTransitionAction { _epoch: &Epoch, _platform_version: &PlatformVersion, ) -> Result>, Error> { - // TODO: Implement shielded transfer drive operations - Ok(vec![]) + match self { + ShieldedTransferTransitionAction::V0(v0) => { + let mut ops: Vec> = Vec::new(); + + let nullifiers_path = shielded_credit_pool_nullifiers_path_vec(); + let commitments_path = shielded_credit_pool_commitments_path_vec(); + let encrypted_notes_path = shielded_credit_pool_encrypted_notes_path_vec(); + let pool_path = shielded_credit_pool_path_vec(); + + // 1. Insert each nullifier (empty Item, InsertOnly to prevent double-spend) + for nullifier in v0.nullifiers.iter() { + ops.push(DriveOperation::GroveDBOperation( + QualifiedGroveDbOp::insert_only_op( + nullifiers_path.clone(), + nullifier.to_vec(), + Element::new_item(vec![]), + ), + )); + } + + // We start with the current checkpoint_id and increment for each commitment + let mut next_checkpoint_id = v0.current_checkpoint_id; + + // 2. Append each note commitment to the commitment tree + for cmx in v0.note_commitments.iter() { + next_checkpoint_id += 1; + ops.push(DriveOperation::GroveDBOperation( + QualifiedGroveDbOp::commitment_tree_append_op( + commitments_path.clone(), + vec![], + *cmx, + next_checkpoint_id, + ), + )); + } + + // 3. Insert encrypted notes keyed by their commitment + for (cmx, encrypted_note) in + v0.note_commitments.iter().zip(v0.encrypted_notes.iter()) + { + ops.push(DriveOperation::GroveDBOperation( + QualifiedGroveDbOp::insert_only_op( + encrypted_notes_path.clone(), + cmx.to_vec(), + Element::new_item(encrypted_note.clone()), + ), + )); + } + + // 4. Update total balance SumItem: subtract fee_amount + let new_total_balance = v0 + .current_total_balance + .checked_sub(v0.fee_amount) + .expect("total balance must be >= fee_amount"); + ops.push(DriveOperation::GroveDBOperation( + QualifiedGroveDbOp::insert_or_replace_op( + pool_path.clone(), + vec![SHIELDED_TOTAL_BALANCE_KEY], + Element::new_sum_item(new_total_balance as i64), + ), + )); + + // 5. Update params with incremented checkpoint_id_counter + let new_params = ShieldedPoolParams { + checkpoint_id_counter: next_checkpoint_id, + }; + let encoded_params = + bincode::encode_to_vec(&new_params, bincode::config::standard()) + .expect("expected to encode shielded pool params"); + ops.push(DriveOperation::GroveDBOperation( + QualifiedGroveDbOp::insert_or_replace_op( + pool_path, + vec![SHIELDED_PARAMS_KEY], + Element::new_item(encoded_params), + ), + )); + + // TODO: Record anchor after batch is applied (needs post-batch semantics) + + Ok(ops) + } + } } } @@ -35,7 +200,96 @@ impl DriveHighLevelOperationConverter for UnshieldTransitionAction { _epoch: &Epoch, _platform_version: &PlatformVersion, ) -> Result>, Error> { - // TODO: Implement unshield drive operations - Ok(vec![]) + match self { + UnshieldTransitionAction::V0(v0) => { + let mut ops: Vec> = Vec::new(); + + let nullifiers_path = shielded_credit_pool_nullifiers_path_vec(); + let commitments_path = shielded_credit_pool_commitments_path_vec(); + let encrypted_notes_path = shielded_credit_pool_encrypted_notes_path_vec(); + let pool_path = shielded_credit_pool_path_vec(); + + // 1. Insert each nullifier (empty Item, InsertOnly to prevent double-spend) + for nullifier in v0.nullifiers.iter() { + ops.push(DriveOperation::GroveDBOperation( + QualifiedGroveDbOp::insert_only_op( + nullifiers_path.clone(), + nullifier.to_vec(), + Element::new_item(vec![]), + ), + )); + } + + // 2. Credit the output address with the unshielded amount + ops.push(DriveOperation::AddressFundsOperation( + AddressFundsOperationType::AddBalanceToAddress { + address: v0.output_address, + balance_to_add: v0.amount, + }, + )); + + // We start with the current checkpoint_id and increment for each commitment + let mut next_checkpoint_id = v0.current_checkpoint_id; + + // 3. Append each note commitment (change outputs) to the commitment tree + for cmx in v0.note_commitments.iter() { + next_checkpoint_id += 1; + ops.push(DriveOperation::GroveDBOperation( + QualifiedGroveDbOp::commitment_tree_append_op( + commitments_path.clone(), + vec![], + *cmx, + next_checkpoint_id, + ), + )); + } + + // 4. Insert encrypted notes keyed by their commitment + for (cmx, encrypted_note) in + v0.note_commitments.iter().zip(v0.encrypted_notes.iter()) + { + ops.push(DriveOperation::GroveDBOperation( + QualifiedGroveDbOp::insert_only_op( + encrypted_notes_path.clone(), + cmx.to_vec(), + Element::new_item(encrypted_note.clone()), + ), + )); + } + + // 5. Update total balance SumItem: subtract the unshielded amount + // (fee is handled separately by the fee system) + let new_total_balance = v0 + .current_total_balance + .checked_sub(v0.amount) + .expect("total balance must be >= unshield amount"); + ops.push(DriveOperation::GroveDBOperation( + QualifiedGroveDbOp::insert_or_replace_op( + pool_path.clone(), + vec![SHIELDED_TOTAL_BALANCE_KEY], + Element::new_sum_item(new_total_balance as i64), + ), + )); + + // 6. Update params with incremented checkpoint_id_counter + let new_params = ShieldedPoolParams { + checkpoint_id_counter: next_checkpoint_id, + }; + let encoded_params = + bincode::encode_to_vec(&new_params, bincode::config::standard()) + .expect("expected to encode shielded pool params"); + ops.push(DriveOperation::GroveDBOperation( + QualifiedGroveDbOp::insert_or_replace_op( + pool_path, + vec![SHIELDED_PARAMS_KEY], + Element::new_item(encoded_params), + ), + )); + + // TODO: Record anchor after batch is applied (needs post-batch semantics) + + Ok(ops) + } + } } } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs index d6c982854ab..2af560e126e 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs @@ -14,6 +14,8 @@ impl ShieldTransitionAction { shield_amount: Credits, note_commitments: Vec<[u8; 32]>, encrypted_notes: Vec>, + current_checkpoint_id: u64, + current_total_balance: Credits, ) -> ConsensusValidationResult { match value { ShieldTransition::V0(v0) => { @@ -23,6 +25,8 @@ impl ShieldTransitionAction { shield_amount, note_commitments, encrypted_notes, + current_checkpoint_id, + current_total_balance, ); result.map(|action| action.into()) } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs index cacf9588e04..43e27a99bc2 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs @@ -20,4 +20,8 @@ pub struct ShieldTransitionActionV0 { pub fee_strategy: AddressFundsFeeStrategy, /// fee multiplier pub user_fee_increase: UserFeeIncrease, + /// Current checkpoint ID counter read from shielded pool params + pub current_checkpoint_id: u64, + /// Current total balance of the shielded pool + pub current_total_balance: Credits, } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs index 9b9217165c2..7ceb8a65cba 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs @@ -13,6 +13,8 @@ impl ShieldTransitionActionV0 { shield_amount: Credits, note_commitments: Vec<[u8; 32]>, encrypted_notes: Vec>, + current_checkpoint_id: u64, + current_total_balance: Credits, ) -> ConsensusValidationResult { ConsensusValidationResult::new_with_data(ShieldTransitionActionV0 { inputs_with_remaining_balance, @@ -21,6 +23,8 @@ impl ShieldTransitionActionV0 { encrypted_notes, fee_strategy: value.fee_strategy.clone(), user_fee_increase: value.user_fee_increase, + current_checkpoint_id, + current_total_balance, }) } } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/transformer.rs index b33745d6038..b782b21f009 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/transformer.rs @@ -13,6 +13,8 @@ impl ShieldedTransferTransitionAction { encrypted_notes: Vec>, anchor: [u8; 32], fee_amount: Credits, + current_checkpoint_id: u64, + current_total_balance: Credits, ) -> ConsensusValidationResult { match value { ShieldedTransferTransition::V0(v0) => { @@ -23,6 +25,8 @@ impl ShieldedTransferTransitionAction { encrypted_notes, anchor, fee_amount, + current_checkpoint_id, + current_total_balance, ); result.map(|action| action.into()) } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs index de77b61439c..9c9ab122ece 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs @@ -18,4 +18,8 @@ pub struct ShieldedTransferTransitionActionV0 { pub fee_amount: Credits, /// fee multiplier pub user_fee_increase: UserFeeIncrease, + /// Current checkpoint ID counter read from shielded pool params + pub current_checkpoint_id: u64, + /// Current total balance of the shielded pool + pub current_total_balance: Credits, } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs index 22ad9e00452..ff971278375 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs @@ -12,6 +12,8 @@ impl ShieldedTransferTransitionActionV0 { encrypted_notes: Vec>, anchor: [u8; 32], fee_amount: Credits, + current_checkpoint_id: u64, + current_total_balance: Credits, ) -> ConsensusValidationResult { ConsensusValidationResult::new_with_data(ShieldedTransferTransitionActionV0 { nullifiers, @@ -20,6 +22,8 @@ impl ShieldedTransferTransitionActionV0 { anchor, fee_amount, user_fee_increase: value.user_fee_increase, + current_checkpoint_id, + current_total_balance, }) } } diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/transformer.rs index 2d68b43293f..c45b3306092 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/unshield/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/transformer.rs @@ -1,5 +1,6 @@ use crate::state_transition_action::shielded::unshield::v0::UnshieldTransitionActionV0; use crate::state_transition_action::shielded::unshield::UnshieldTransitionAction; +use dpp::fee::Credits; use dpp::prelude::ConsensusValidationResult; use dpp::state_transition::unshield_transition::UnshieldTransition; @@ -11,6 +12,8 @@ impl UnshieldTransitionAction { note_commitments: Vec<[u8; 32]>, encrypted_notes: Vec>, anchor: [u8; 32], + current_checkpoint_id: u64, + current_total_balance: Credits, ) -> ConsensusValidationResult { match value { UnshieldTransition::V0(v0) => { @@ -20,6 +23,8 @@ impl UnshieldTransitionAction { note_commitments, encrypted_notes, anchor, + current_checkpoint_id, + current_total_balance, ); result.map(|action| action.into()) } diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs index 260f437d055..4b69433748a 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs @@ -21,4 +21,8 @@ pub struct UnshieldTransitionActionV0 { pub anchor: [u8; 32], /// fee multiplier pub user_fee_increase: UserFeeIncrease, + /// Current checkpoint ID counter read from shielded pool params + pub current_checkpoint_id: u64, + /// Current total balance of the shielded pool + pub current_total_balance: Credits, } diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs index 526d50bc61c..af80bf2e002 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs @@ -1,4 +1,5 @@ use crate::state_transition_action::shielded::unshield::v0::UnshieldTransitionActionV0; +use dpp::fee::Credits; use dpp::prelude::ConsensusValidationResult; use dpp::state_transition::state_transitions::shielded::unshield_transition::v0::UnshieldTransitionV0; @@ -10,6 +11,8 @@ impl UnshieldTransitionActionV0 { note_commitments: Vec<[u8; 32]>, encrypted_notes: Vec>, anchor: [u8; 32], + current_checkpoint_id: u64, + current_total_balance: Credits, ) -> ConsensusValidationResult { ConsensusValidationResult::new_with_data(UnshieldTransitionActionV0 { output_address: value.output_address.clone(), @@ -19,6 +22,8 @@ impl UnshieldTransitionActionV0 { encrypted_notes, anchor, user_fee_increase: value.user_fee_increase, + current_checkpoint_id, + current_total_balance, }) } } From a4ad035752bf8f01408294748b23a220b617924d Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 10 Feb 2026 06:24:25 +0000 Subject: [PATCH 03/40] more work --- Cargo.lock | 3 + packages/rs-dpp/src/errors/consensus/codes.rs | 5 + .../rs-dpp/src/errors/consensus/state/mod.rs | 1 + .../state/shielded/invalid_anchor_error.rs | 36 + .../shielded/invalid_shielded_proof_error.rs | 36 + .../errors/consensus/state/shielded/mod.rs | 7 + .../shielded/nullifier_already_spent_error.rs | 36 + .../src/errors/consensus/state/state_error.rs | 12 + packages/rs-drive-abci/Cargo.toml | 3 + .../state_transition/state_transitions/mod.rs | 2 + .../state_transitions/shield/mod.rs | 7 + .../state_transitions/shield/tests.rs | 979 ++++++++++++++++++ .../shield/transform_into_action/v0/mod.rs | 80 +- .../state_transitions/shielded_common/mod.rs | 144 +++ .../shielded_transfer/mod.rs | 5 +- .../transform_into_action/v0/mod.rs | 121 ++- .../state_transitions/unshield/mod.rs | 5 +- .../unshield/transform_into_action/v0/mod.rs | 122 ++- .../state_transition/transformer/mod.rs | 5 +- .../shielded/mod.rs | 16 +- .../apply_drive_operations/v0/mod.rs | 2 +- .../batch/drive_op_batch/finalize_task.rs | 46 +- .../src/util/batch/drive_op_batch/mod.rs | 6 +- 23 files changed, 1642 insertions(+), 37 deletions(-) create mode 100644 packages/rs-dpp/src/errors/consensus/state/shielded/invalid_anchor_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/state/shielded/invalid_shielded_proof_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/state/shielded/mod.rs create mode 100644 packages/rs-dpp/src/errors/consensus/state/shielded/nullifier_already_spent_error.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs diff --git a/Cargo.lock b/Cargo.lock index a8d8d37b2d2..c04f2faff3c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1955,6 +1955,7 @@ dependencies = [ "drive-proof-verifier", "envy", "file-rotate", + "grovedb-commitment-tree", "hex", "indexmap 2.12.1", "integer-encoding", @@ -1964,6 +1965,8 @@ dependencies = [ "metrics", "metrics-exporter-prometheus", "mockall", + "nonempty", + "orchard", "platform-version", "prost 0.14.1", "rand 0.8.5", diff --git a/packages/rs-dpp/src/errors/consensus/codes.rs b/packages/rs-dpp/src/errors/consensus/codes.rs index 1758f022ac8..fe4f544a768 100644 --- a/packages/rs-dpp/src/errors/consensus/codes.rs +++ b/packages/rs-dpp/src/errors/consensus/codes.rs @@ -370,6 +370,11 @@ impl ErrorWithCode for StateError { Self::GroupActionAlreadyCompletedError(_) => 40802, Self::GroupActionAlreadySignedByIdentityError(_) => 40803, Self::ModificationOfGroupActionMainParametersNotPermittedError(_) => 40804, + + // Shielded errors: 40900-40999 + Self::InvalidAnchorError(_) => 40900, + Self::NullifierAlreadySpentError(_) => 40901, + Self::InvalidShieldedProofError(_) => 40902, } } } diff --git a/packages/rs-dpp/src/errors/consensus/state/mod.rs b/packages/rs-dpp/src/errors/consensus/state/mod.rs index b0e64d6bc80..57585a79711 100644 --- a/packages/rs-dpp/src/errors/consensus/state/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/state/mod.rs @@ -5,6 +5,7 @@ pub mod document; pub mod group; pub mod identity; pub mod prefunded_specialized_balances; +pub mod shielded; pub mod state_error; pub mod token; pub mod voting; diff --git a/packages/rs-dpp/src/errors/consensus/state/shielded/invalid_anchor_error.rs b/packages/rs-dpp/src/errors/consensus/state/shielded/invalid_anchor_error.rs new file mode 100644 index 00000000000..59ce4e3bb5f --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/shielded/invalid_anchor_error.rs @@ -0,0 +1,36 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[platform_serialize(unversioned)] +#[error("Anchor not found in the recorded anchors tree: {}", hex::encode(anchor))] +pub struct InvalidAnchorError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + anchor: [u8; 32], +} + +impl InvalidAnchorError { + pub fn new(anchor: [u8; 32]) -> Self { + Self { anchor } + } + + pub fn anchor(&self) -> [u8; 32] { + self.anchor + } +} + +impl From for ConsensusError { + fn from(err: InvalidAnchorError) -> Self { + Self::StateError(StateError::InvalidAnchorError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/state/shielded/invalid_shielded_proof_error.rs b/packages/rs-dpp/src/errors/consensus/state/shielded/invalid_shielded_proof_error.rs new file mode 100644 index 00000000000..b18b8c30f58 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/shielded/invalid_shielded_proof_error.rs @@ -0,0 +1,36 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[platform_serialize(unversioned)] +#[error("Invalid shielded transaction proof: {message}")] +pub struct InvalidShieldedProofError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + message: String, +} + +impl InvalidShieldedProofError { + pub fn new(message: String) -> Self { + Self { message } + } + + pub fn message(&self) -> &str { + &self.message + } +} + +impl From for ConsensusError { + fn from(err: InvalidShieldedProofError) -> Self { + Self::StateError(StateError::InvalidShieldedProofError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/state/shielded/mod.rs b/packages/rs-dpp/src/errors/consensus/state/shielded/mod.rs new file mode 100644 index 00000000000..d3361548fc5 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/shielded/mod.rs @@ -0,0 +1,7 @@ +pub mod invalid_anchor_error; +pub mod invalid_shielded_proof_error; +pub mod nullifier_already_spent_error; + +pub use invalid_anchor_error::*; +pub use invalid_shielded_proof_error::*; +pub use nullifier_already_spent_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/state/shielded/nullifier_already_spent_error.rs b/packages/rs-dpp/src/errors/consensus/state/shielded/nullifier_already_spent_error.rs new file mode 100644 index 00000000000..a82430c6d0f --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/shielded/nullifier_already_spent_error.rs @@ -0,0 +1,36 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[platform_serialize(unversioned)] +#[error("Nullifier has already been spent: {}", hex::encode(nullifier))] +pub struct NullifierAlreadySpentError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + nullifier: [u8; 32], +} + +impl NullifierAlreadySpentError { + pub fn new(nullifier: [u8; 32]) -> Self { + Self { nullifier } + } + + pub fn nullifier(&self) -> [u8; 32] { + self.nullifier + } +} + +impl From for ConsensusError { + fn from(err: NullifierAlreadySpentError) -> Self { + Self::StateError(StateError::NullifierAlreadySpentError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/state/state_error.rs b/packages/rs-dpp/src/errors/consensus/state/state_error.rs index f3d3e9ad731..cb7a7278657 100644 --- a/packages/rs-dpp/src/errors/consensus/state/state_error.rs +++ b/packages/rs-dpp/src/errors/consensus/state/state_error.rs @@ -4,6 +4,9 @@ use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; use thiserror::Error; use crate::consensus::state::address_funds::{AddressDoesNotExistError, AddressInvalidNonceError, AddressNotEnoughFundsError, AddressesNotEnoughFundsError}; +use crate::consensus::state::shielded::invalid_anchor_error::InvalidAnchorError; +use crate::consensus::state::shielded::invalid_shielded_proof_error::InvalidShieldedProofError; +use crate::consensus::state::shielded::nullifier_already_spent_error::NullifierAlreadySpentError; use crate::consensus::state::data_contract::data_contract_already_present_error::DataContractAlreadyPresentError; use crate::consensus::state::data_contract::data_contract_config_update_error::DataContractConfigUpdateError; use crate::consensus::state::data_contract::data_contract_is_readonly_error::DataContractIsReadonlyError; @@ -334,6 +337,15 @@ pub enum StateError { #[error(transparent)] AddressInvalidNonceError(AddressInvalidNonceError), + + #[error(transparent)] + InvalidAnchorError(InvalidAnchorError), + + #[error(transparent)] + NullifierAlreadySpentError(NullifierAlreadySpentError), + + #[error(transparent)] + InvalidShieldedProofError(InvalidShieldedProofError), } impl From for ConsensusError { diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index 261851cebf0..228de1fb5dd 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -82,6 +82,9 @@ derive_more = { version = "1.0", features = ["from", "deref", "deref_mut"] } async-trait = "0.1.77" console-subscriber = { version = "0.4", optional = true } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f", optional = true } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "219ba2e73f08a9f428c9427f7ab5c73907d670bf" } +orchard = "0.12" +nonempty = "0.11" [dev-dependencies] platform-version = { path = "../rs-platform-version", features = [ diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs index 7693c43f39f..ae5d30e23eb 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs @@ -43,6 +43,8 @@ mod identity_top_up_from_addresses; /// Module for shield transition validation pub mod shield; +/// Common validation logic shared by shielded transitions (proof verification) +pub mod shielded_common; /// Module for shielded transfer transition validation pub mod shielded_transfer; /// Module for unshield transition validation diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/mod.rs index 1c51730f6a7..ba3a3dfa59e 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/mod.rs @@ -1,3 +1,5 @@ +#[cfg(test)] +mod tests; mod transform_into_action; use dpp::address_funds::PlatformAddress; @@ -5,6 +7,7 @@ use dpp::fee::Credits; use dpp::prelude::AddressNonce; use dpp::state_transition::shield_transition::ShieldTransition; use dpp::validation::ConsensusValidationResult; +use drive::grovedb::TransactionArg; use drive::state_transition_action::StateTransitionAction; use std::collections::BTreeMap; @@ -23,6 +26,7 @@ pub trait StateTransitionShieldTransitionActionTransformer { &self, platform: &PlatformRef, inputs_with_remaining_balance: BTreeMap, + tx: TransactionArg, ) -> Result, Error>; } @@ -31,6 +35,7 @@ impl StateTransitionShieldTransitionActionTransformer for ShieldTransition { &self, platform: &PlatformRef, inputs_with_remaining_balance: BTreeMap, + tx: TransactionArg, ) -> Result, Error> { let platform_version = platform.state.current_platform_version()?; @@ -42,6 +47,8 @@ impl StateTransitionShieldTransitionActionTransformer for ShieldTransition { .transform_into_action { 0 => self.transform_into_action_v0( + platform.drive, + tx, inputs_with_remaining_balance, platform_version, ), diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs new file mode 100644 index 00000000000..919abf8ced8 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs @@ -0,0 +1,979 @@ +#[cfg(test)] +mod tests { + use crate::config::{PlatformConfig, PlatformTestConfig}; + use crate::execution::validation::state_transition::state_transitions::test_helpers::{ + create_dummy_witness, create_platform_address, setup_address_with_balance, + TestAddressSigner, + }; + use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; + use crate::test::helpers::setup::TestPlatformBuilder; + use assert_matches::assert_matches; + use dpp::address_funds::{ + AddressFundsFeeStrategy, AddressFundsFeeStrategyStep, AddressWitness, PlatformAddress, + }; + use dpp::block::block_info::BlockInfo; + use dpp::consensus::basic::BasicError; + use dpp::consensus::signature::SignatureError; + use dpp::consensus::state::state_error::StateError; + use dpp::consensus::ConsensusError; + use dpp::dash_to_credits; + use dpp::fee::Credits; + use dpp::prelude::AddressNonce; + use dpp::identity::signer::Signer; + use dpp::serialization::{PlatformSerializable, Signable}; + use dpp::shielded::SerializedAction; + use dpp::state_transition::shield_transition::ShieldTransition; + use dpp::state_transition::shield_transition::v0::ShieldTransitionV0; + use dpp::state_transition::StateTransition; + use platform_version::version::PlatformVersion; + use std::collections::BTreeMap; + + // ========================================== + // Helper Functions + // ========================================== + + /// Create a `SerializedAction` with syntactically valid sizes but meaningless crypto data. + /// Passes structure validation (correct field sizes) but will fail ZK proof verification. + fn create_dummy_serialized_action() -> SerializedAction { + SerializedAction { + nullifier: [1u8; 32], + rk: [2u8; 32], + cmx: [3u8; 32], + encrypted_note: vec![4u8; 692], // epk(32) + enc(580) + out(80) + cv_net: [5u8; 32], + spend_auth_sig: vec![6u8; 64], + } + } + + /// Builds a raw `ShieldTransitionV0` with dummy witnesses. Used for structure validation tests + /// that don't need valid signatures (the structure error is caught before or alongside witness + /// validation, or inputs are empty so witness validation is vacuously true). + fn create_raw_shield_transition( + inputs: BTreeMap, + actions: Vec, + flags: u8, + value_balance: i64, + proof: Vec, + binding_signature: Vec, + fee_strategy: AddressFundsFeeStrategy, + witness_count: usize, + ) -> StateTransition { + let witnesses: Vec = (0..witness_count) + .map(|_| create_dummy_witness()) + .collect(); + StateTransition::Shield(ShieldTransition::V0(ShieldTransitionV0 { + inputs, + actions, + flags, + value_balance, + anchor: [0u8; 32], + proof, + binding_signature, + fee_strategy, + user_fee_increase: 0, + input_witnesses: witnesses, + })) + } + + /// Builds a `ShieldTransitionV0` and signs it with the provided signer. + /// The transition will have valid witnesses for all inputs. + fn create_signed_shield_transition( + signer: &TestAddressSigner, + inputs: BTreeMap, + actions: Vec, + flags: u8, + value_balance: i64, + proof: Vec, + binding_signature: Vec, + fee_strategy: AddressFundsFeeStrategy, + ) -> StateTransition { + // First create with empty witnesses to compute signable bytes + let mut st = StateTransition::Shield(ShieldTransition::V0(ShieldTransitionV0 { + inputs: inputs.clone(), + actions, + flags, + value_balance, + anchor: [0u8; 32], + proof, + binding_signature, + fee_strategy, + user_fee_increase: 0, + input_witnesses: vec![], + })); + + // Compute signable bytes (excludes input_witnesses due to #[platform_signable(exclude_from_sig_hash)]) + let signable_bytes = st.signable_bytes().expect("should compute signable bytes"); + + // Sign each input with the signer + let witnesses: Vec = inputs + .keys() + .map(|address| { + signer + .sign_create_witness(address, &signable_bytes) + .expect("should sign") + }) + .collect(); + + // Inject witnesses + if let StateTransition::Shield(ShieldTransition::V0(ref mut v0)) = st { + v0.input_witnesses = witnesses; + } + st + } + + /// Shorthand for creating a structurally valid (but cryptographically invalid) signed shield + /// transition with a single input address. The ZK proof data is random/dummy. + fn create_default_signed_shield_transition( + signer: &TestAddressSigner, + input_address: PlatformAddress, + input_nonce: AddressNonce, + input_amount: Credits, + ) -> StateTransition { + let mut inputs = BTreeMap::new(); + inputs.insert(input_address, (input_nonce, input_amount)); + + create_signed_shield_transition( + signer, + inputs, + vec![create_dummy_serialized_action()], + 0x03, // spends_enabled | outputs_enabled + -1000, + vec![0u8; 100], // dummy proof bytes + vec![0u8; 64], // dummy binding signature + AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput(0)]), + ) + } + + /// Standard platform setup for tests. + fn setup_platform( + ) -> crate::test::helpers::setup::TempPlatform { + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + TestPlatformBuilder::new() + .with_config(platform_config) + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state() + } + + /// Execute a state transition through the full processing pipeline and return the result. + fn process_transition( + platform: &crate::test::helpers::setup::TempPlatform, + transition: StateTransition, + platform_version: &PlatformVersion, + ) -> crate::platform_types::state_transitions_processing_result::StateTransitionsProcessingResult + { + let transition_bytes = transition + .serialize_to_bytes() + .expect("should serialize transition"); + let platform_state = platform.state.load(); + let transaction = platform.drive.grove.start_transaction(); + + platform + .platform + .process_raw_state_transitions( + &vec![transition_bytes], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition") + } + + // ========================================== + // STRUCTURE VALIDATION TESTS (BasicError) + // ========================================== + + mod structure_validation { + use super::*; + + #[test] + fn test_empty_actions_returns_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + // Need a properly signed transition with address in state so we get past + // witness and address validation + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + setup_address_with_balance( + &mut platform, + input_address, + 0, + dash_to_credits!(1.0), + ); + + let mut inputs = BTreeMap::new(); + inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); + + let transition = create_signed_shield_transition( + &signer, + inputs, + vec![], // Empty actions — invalid + 0x03, + -1000, + vec![0u8; 100], + vec![0u8; 64], + AddressFundsFeeStrategy::from(vec![ + AddressFundsFeeStrategyStep::DeductFromInput(0), + ]), + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_no_inputs_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + // Empty inputs — witness and address validation are vacuously true + let transition = create_raw_shield_transition( + BTreeMap::new(), // no inputs + vec![create_dummy_serialized_action()], + 0x03, + -1000, + vec![0u8; 100], + vec![0u8; 64], + AddressFundsFeeStrategy::from(vec![ + AddressFundsFeeStrategyStep::DeductFromInput(0), + ]), + 0, // 0 witnesses to match 0 inputs + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::TransitionNoInputsError(_)) + )] + ); + } + + #[test] + fn test_witness_count_mismatch_returns_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + setup_address_with_balance( + &mut platform, + input_address, + 0, + dash_to_credits!(1.0), + ); + + // Create a properly signed transition (1 input, 1 valid witness) + let mut transition = create_default_signed_shield_transition( + &signer, + input_address, + 1, + dash_to_credits!(0.5), + ); + + // Add an extra dummy witness to cause mismatch (1 input, 2 witnesses) + if let StateTransition::Shield(ShieldTransition::V0(ref mut v0)) = transition { + v0.input_witnesses.push(create_dummy_witness()); + } + + let processing_result = process_transition(&platform, transition, platform_version); + + // Witness validation runs before structure validation in the pipeline, + // so count mismatch is caught as a SignatureError, not a BasicError. + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::SignatureError( + SignatureError::InvalidStateTransitionSignatureError(_) + ) + )] + ); + } + + #[test] + fn test_input_below_minimum_returns_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + setup_address_with_balance( + &mut platform, + input_address, + 0, + dash_to_credits!(1.0), + ); + + let mut inputs = BTreeMap::new(); + inputs.insert(input_address, (1 as AddressNonce, 1)); // 1 credit — below minimum + + let transition = create_signed_shield_transition( + &signer, + inputs, + vec![create_dummy_serialized_action()], + 0x03, + -1, + vec![0u8; 100], + vec![0u8; 64], + AddressFundsFeeStrategy::from(vec![ + AddressFundsFeeStrategyStep::DeductFromInput(0), + ]), + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::InputBelowMinimumError(_)) + )] + ); + } + + #[test] + fn test_positive_value_balance_returns_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + setup_address_with_balance( + &mut platform, + input_address, + 0, + dash_to_credits!(1.0), + ); + + let mut inputs = BTreeMap::new(); + inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); + + let transition = create_signed_shield_transition( + &signer, + inputs, + vec![create_dummy_serialized_action()], + 0x03, + 1000, // Positive — invalid for shield (must be negative) + vec![0u8; 100], + vec![0u8; 64], + AddressFundsFeeStrategy::from(vec![ + AddressFundsFeeStrategyStep::DeductFromInput(0), + ]), + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_zero_value_balance_returns_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + setup_address_with_balance( + &mut platform, + input_address, + 0, + dash_to_credits!(1.0), + ); + + let mut inputs = BTreeMap::new(); + inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); + + let transition = create_signed_shield_transition( + &signer, + inputs, + vec![create_dummy_serialized_action()], + 0x03, + 0, // Zero — invalid for shield (must be negative) + vec![0u8; 100], + vec![0u8; 64], + AddressFundsFeeStrategy::from(vec![ + AddressFundsFeeStrategyStep::DeductFromInput(0), + ]), + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_empty_proof_returns_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + setup_address_with_balance( + &mut platform, + input_address, + 0, + dash_to_credits!(1.0), + ); + + let mut inputs = BTreeMap::new(); + inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); + + let transition = create_signed_shield_transition( + &signer, + inputs, + vec![create_dummy_serialized_action()], + 0x03, + -1000, + vec![], // Empty proof — invalid + vec![0u8; 64], + AddressFundsFeeStrategy::from(vec![ + AddressFundsFeeStrategyStep::DeductFromInput(0), + ]), + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_wrong_binding_sig_length_returns_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + setup_address_with_balance( + &mut platform, + input_address, + 0, + dash_to_credits!(1.0), + ); + + let mut inputs = BTreeMap::new(); + inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); + + let transition = create_signed_shield_transition( + &signer, + inputs, + vec![create_dummy_serialized_action()], + 0x03, + -1000, + vec![0u8; 100], + vec![0u8; 32], // 32 bytes instead of 64 — invalid + AddressFundsFeeStrategy::from(vec![ + AddressFundsFeeStrategyStep::DeductFromInput(0), + ]), + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_wrong_spend_auth_sig_length_returns_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + setup_address_with_balance( + &mut platform, + input_address, + 0, + dash_to_credits!(1.0), + ); + + let mut inputs = BTreeMap::new(); + inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); + + let mut bad_action = create_dummy_serialized_action(); + bad_action.spend_auth_sig = vec![0u8; 32]; // 32 bytes instead of 64 + + let transition = create_signed_shield_transition( + &signer, + inputs, + vec![bad_action], + 0x03, + -1000, + vec![0u8; 100], + vec![0u8; 64], + AddressFundsFeeStrategy::from(vec![ + AddressFundsFeeStrategyStep::DeductFromInput(0), + ]), + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_empty_fee_strategy_returns_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + setup_address_with_balance( + &mut platform, + input_address, + 0, + dash_to_credits!(1.0), + ); + + let mut inputs = BTreeMap::new(); + inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); + + let transition = create_signed_shield_transition( + &signer, + inputs, + vec![create_dummy_serialized_action()], + 0x03, + -1000, + vec![0u8; 100], + vec![0u8; 64], + AddressFundsFeeStrategy::from(vec![]), // Empty fee strategy + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::FeeStrategyEmptyError(_)) + )] + ); + } + + #[test] + fn test_fee_strategy_too_many_steps_returns_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + setup_address_with_balance( + &mut platform, + input_address, + 0, + dash_to_credits!(1.0), + ); + + let mut inputs = BTreeMap::new(); + inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); + + // More steps than the max allowed (typically 4) + let transition = create_signed_shield_transition( + &signer, + inputs, + vec![create_dummy_serialized_action()], + 0x03, + -1000, + vec![0u8; 100], + vec![0u8; 64], + AddressFundsFeeStrategy::from(vec![ + AddressFundsFeeStrategyStep::DeductFromInput(0), + AddressFundsFeeStrategyStep::DeductFromInput(1), + AddressFundsFeeStrategyStep::DeductFromInput(2), + AddressFundsFeeStrategyStep::DeductFromInput(3), + AddressFundsFeeStrategyStep::DeductFromInput(4), + ]), + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::FeeStrategyTooManyStepsError(_)) + )] + ); + } + + #[test] + fn test_fee_strategy_duplicate_returns_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + setup_address_with_balance( + &mut platform, + input_address, + 0, + dash_to_credits!(1.0), + ); + + let mut inputs = BTreeMap::new(); + inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); + + let transition = create_signed_shield_transition( + &signer, + inputs, + vec![create_dummy_serialized_action()], + 0x03, + -1000, + vec![0u8; 100], + vec![0u8; 64], + AddressFundsFeeStrategy::from(vec![ + AddressFundsFeeStrategyStep::DeductFromInput(0), + AddressFundsFeeStrategyStep::DeductFromInput(0), // Duplicate + ]), + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::FeeStrategyDuplicateError(_)) + )] + ); + } + } + + // ========================================== + // WITNESS VALIDATION TESTS (SignatureError) + // ========================================== + + mod witness_validation { + use super::*; + + #[test] + fn test_invalid_witness_returns_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + setup_address_with_balance( + &mut platform, + input_address, + 0, + dash_to_credits!(1.0), + ); + + // Create properly signed transition, then tamper with the witness + let mut transition = create_default_signed_shield_transition( + &signer, + input_address, + 1, + dash_to_credits!(0.5), + ); + + // Tamper the witness signature + if let StateTransition::Shield(ShieldTransition::V0(ref mut v0)) = transition { + if let Some(AddressWitness::P2pkh { ref mut signature }) = + v0.input_witnesses.first_mut() + { + // Flip a byte in the signature + if let Some(byte) = signature.0.first_mut() { + *byte ^= 0xFF; + } + } + } + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::SignatureError( + SignatureError::InvalidStateTransitionSignatureError(_) + ) + )] + ); + } + + #[test] + fn test_wrong_key_witness_returns_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + setup_address_with_balance( + &mut platform, + input_address, + 0, + dash_to_credits!(1.0), + ); + + // Create a second signer with different key + let mut wrong_signer = TestAddressSigner::new(); + let _wrong_address = wrong_signer.add_p2pkh([2u8; 32]); + + // Build transition for the real input address but sign with wrong key's signer + let mut inputs = BTreeMap::new(); + inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); + + // The wrong_signer doesn't have input_address, so we manually create a bad witness + let mut transition = create_signed_shield_transition( + &signer, + inputs, + vec![create_dummy_serialized_action()], + 0x03, + -1000, + vec![0u8; 100], + vec![0u8; 64], + AddressFundsFeeStrategy::from(vec![ + AddressFundsFeeStrategyStep::DeductFromInput(0), + ]), + ); + + // Replace the valid witness with one signed by a different key + let signable_bytes = transition + .signable_bytes() + .expect("should compute signable bytes"); + let wrong_witness = wrong_signer + .sign_create_witness(&_wrong_address, &signable_bytes) + .expect("should sign"); + + if let StateTransition::Shield(ShieldTransition::V0(ref mut v0)) = transition { + v0.input_witnesses = vec![wrong_witness]; + } + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::SignatureError( + SignatureError::InvalidStateTransitionSignatureError(_) + ) + )] + ); + } + } + + // ========================================== + // ADDRESS STATE VALIDATION TESTS (StateError) + // ========================================== + + mod address_state_validation { + use super::*; + + #[test] + fn test_address_not_found_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + // NOTE: No setup_address_with_balance — address does not exist in state + + let transition = create_default_signed_shield_transition( + &signer, + input_address, + 1, + dash_to_credits!(0.5), + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::AddressDoesNotExistError(_)) + )] + ); + } + + #[test] + fn test_wrong_nonce_returns_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + // Set up address with nonce 0 + setup_address_with_balance( + &mut platform, + input_address, + 0, + dash_to_credits!(1.0), + ); + + // Create transition with nonce 5 (expected nonce is 1) + let transition = create_default_signed_shield_transition( + &signer, + input_address, + 5, // Wrong nonce — state has 0, expected next is 1 + dash_to_credits!(0.5), + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::AddressInvalidNonceError(_)) + )] + ); + } + + #[test] + fn test_insufficient_balance_returns_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + // Set up address with small balance + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(0.001)); + + // Try to shield more than the balance + let transition = create_default_signed_shield_transition( + &signer, + input_address, + 1, + dash_to_credits!(1.0), // Way more than 0.001 Dash balance + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::AddressNotEnoughFundsError(_)) + )] + ); + } + } + + // ========================================== + // ZK PROOF VERIFICATION TESTS (InvalidShieldedProofError) + // ========================================== + + mod proof_verification { + use super::*; + + #[test] + fn test_invalid_proof_returns_shielded_proof_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + setup_address_with_balance( + &mut platform, + input_address, + 0, + dash_to_credits!(1.0), + ); + + // This transition is structurally valid but has random ZK proof data. + // It should pass structure validation, witness validation, and address validation + // but fail at proof verification in transform_into_action. + let transition = create_default_signed_shield_transition( + &signer, + input_address, + 1, + dash_to_credits!(0.5), + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // The proof verification happens during transform_into_action. + // With random data, reconstruct_and_verify_bundle should fail at + // parsing the cryptographic fields (nullifier, rk, cmx, cv_net) or + // at the actual proof verification step. + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + + #[test] + fn test_wrong_encrypted_note_size_returns_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + setup_address_with_balance( + &mut platform, + input_address, + 0, + dash_to_credits!(1.0), + ); + + // Create action with wrong encrypted_note size + let mut bad_action = create_dummy_serialized_action(); + bad_action.encrypted_note = vec![0u8; 100]; // 100 bytes instead of 692 + + let mut inputs = BTreeMap::new(); + inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); + + let transition = create_signed_shield_transition( + &signer, + inputs, + vec![bad_action], + 0x03, + -1000, + vec![0u8; 100], + vec![0u8; 64], + AddressFundsFeeStrategy::from(vec![ + AddressFundsFeeStrategyStep::DeductFromInput(0), + ]), + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // The encrypted_note size check happens in reconstruct_and_verify_bundle, + // which runs during transform_into_action after all prior validations pass. + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs index aee9fb4fee8..abb57553c4a 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs @@ -1,17 +1,28 @@ use crate::error::Error; +use crate::execution::validation::state_transition::state_transitions::shielded_common::reconstruct_and_verify_bundle; use dpp::address_funds::PlatformAddress; +use dpp::consensus::state::state_error::StateError; use dpp::fee::Credits; use dpp::prelude::{AddressNonce, ConsensusValidationResult}; +use dpp::shielded::ShieldedPoolParams; use dpp::state_transition::shield_transition::ShieldTransition; use dpp::version::PlatformVersion; +use drive::drive::shielded::paths::{ + shielded_credit_pool_path, SHIELDED_PARAMS_KEY, SHIELDED_TOTAL_BALANCE_KEY, +}; +use drive::drive::Drive; +use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::shield::ShieldTransitionAction; use drive::state_transition_action::StateTransitionAction; +use drive::util::grove_operations::DirectQueryType; use std::collections::BTreeMap; pub(in crate::execution::validation::state_transition::state_transitions::shield) trait ShieldStateTransitionTransformIntoActionValidationV0 { fn transform_into_action_v0( &self, + drive: &Drive, + transaction: TransactionArg, inputs_with_remaining_balance: BTreeMap, platform_version: &PlatformVersion, ) -> Result, Error>; @@ -20,8 +31,10 @@ pub(in crate::execution::validation::state_transition::state_transitions::shield impl ShieldStateTransitionTransformIntoActionValidationV0 for ShieldTransition { fn transform_into_action_v0( &self, + drive: &Drive, + transaction: TransactionArg, inputs_with_remaining_balance: BTreeMap, - _platform_version: &PlatformVersion, + platform_version: &PlatformVersion, ) -> Result, Error> { // Extract note commitments and encrypted notes from serialized actions let note_commitments: Vec<[u8; 32]> = match self { @@ -38,13 +51,64 @@ impl ShieldStateTransitionTransformIntoActionValidationV0 for ShieldTransition { ShieldTransition::V0(v0) => (-v0.value_balance) as u64, }; - // TODO: Read current shielded pool state from GroveDB. - // These should be fetched from the shielded pool tree in GroveDB: - // - current_checkpoint_id: the latest checkpoint epoch ID - // - current_total_balance: the running total balance of the shielded pool - // For now, use default values until the GroveDB API for shielded pool is available. - let current_checkpoint_id: u64 = 0; - let current_total_balance: Credits = 0; + // Read current shielded pool state from GroveDB + let mut drive_operations = vec![]; + let pool_path = shielded_credit_pool_path(); + + let params_bytes = drive.grove_get_raw_item( + (&pool_path).into(), + &[SHIELDED_PARAMS_KEY], + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )?; + let (params, _): (ShieldedPoolParams, _) = + bincode::decode_from_slice(¶ms_bytes, bincode::config::standard()) + .map_err(|e| { + Error::Protocol( + dpp::ProtocolError::DecodingError(format!( + "could not decode shielded pool params: {e}" + )), + ) + })?; + let current_checkpoint_id = params.checkpoint_id_counter; + + let current_total_balance = drive + .grove_get_raw_value_u64_from_encoded_var_vec( + (&pool_path).into(), + &[SHIELDED_TOTAL_BALANCE_KEY], + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )? + .unwrap_or(0); + + // Verify the ZK proof + let (actions, flags, value_balance, anchor, proof, binding_signature) = match self { + ShieldTransition::V0(v0) => ( + &v0.actions, + v0.flags, + v0.value_balance, + &v0.anchor, + v0.proof.as_slice(), + v0.binding_signature.as_slice(), + ), + }; + + if let Err(e) = reconstruct_and_verify_bundle( + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + ) { + return Ok(ConsensusValidationResult::new_with_error( + StateError::InvalidShieldedProofError(e).into(), + )); + } let result = ShieldTransitionAction::try_from_transition( self, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs new file mode 100644 index 00000000000..ef3397ecf7b --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs @@ -0,0 +1,144 @@ +use dpp::consensus::state::shielded::invalid_shielded_proof_error::InvalidShieldedProofError; +use dpp::shielded::SerializedAction; +use grovedb_commitment_tree::{ + Action, Anchor, Authorized, Bundle, ExtractedNoteCommitment, Flags, Nullifier, Proof, + VerifyingKey, +}; +use orchard::note::TransmittedNoteCiphertext; +use orchard::primitives::redpallas; +use orchard::value::ValueCommitment; +use std::sync::OnceLock; + +/// Cached verifying key for shielded proof verification. +/// +/// The key is deterministic (same circuit → same key) and immutable. +/// Building it takes ~5s, so it's lazily initialized on first use. +static SHIELDED_VERIFYING_KEY: OnceLock = OnceLock::new(); + +fn get_verifying_key() -> &'static VerifyingKey { + SHIELDED_VERIFYING_KEY.get_or_init(VerifyingKey::build) +} + +const EPK_SIZE: usize = 32; +const ENC_CIPHERTEXT_SIZE: usize = 580; +const OUT_CIPHERTEXT_SIZE: usize = 80; +const ENCRYPTED_NOTE_SIZE: usize = EPK_SIZE + ENC_CIPHERTEXT_SIZE + OUT_CIPHERTEXT_SIZE; // 692 + +/// Reconstructs an orchard `Bundle` from the serialized fields +/// of a shielded state transition and verifies the Halo 2 ZK proof. +/// +/// Returns `Ok(())` if the proof is valid, or an `InvalidShieldedProofError` +/// wrapped in `Error` if reconstruction or verification fails. +pub fn reconstruct_and_verify_bundle( + actions: &[SerializedAction], + flags: u8, + value_balance: i64, + anchor: &[u8; 32], + proof: &[u8], + binding_signature: &[u8], +) -> Result<(), InvalidShieldedProofError> { + let vk = get_verifying_key(); + + // Reconstruct each Action + let mut orchard_actions = Vec::with_capacity(actions.len()); + for a in actions { + // Parse encrypted_note (692 bytes = epk 32 + enc 580 + out 80) + if a.encrypted_note.len() != ENCRYPTED_NOTE_SIZE { + return Err(InvalidShieldedProofError::new(format!( + "encrypted note size mismatch: expected {ENCRYPTED_NOTE_SIZE}, got {}", + a.encrypted_note.len() + ))); + } + let epk_bytes: [u8; 32] = a.encrypted_note[..EPK_SIZE].try_into().unwrap(); + let enc_ciphertext: [u8; ENC_CIPHERTEXT_SIZE] = a.encrypted_note + [EPK_SIZE..EPK_SIZE + ENC_CIPHERTEXT_SIZE] + .try_into() + .unwrap(); + let out_ciphertext: [u8; OUT_CIPHERTEXT_SIZE] = a.encrypted_note + [EPK_SIZE + ENC_CIPHERTEXT_SIZE..] + .try_into() + .unwrap(); + + let nullifier: Nullifier = + Option::from(Nullifier::from_bytes(&a.nullifier)).ok_or_else(|| { + InvalidShieldedProofError::new("invalid nullifier bytes".to_string()) + })?; + + let rk = redpallas::VerificationKey::try_from(a.rk).map_err(|e| { + InvalidShieldedProofError::new(format!("invalid spend validating key: {e}")) + })?; + + let cmx: ExtractedNoteCommitment = + Option::from(ExtractedNoteCommitment::from_bytes(&a.cmx)).ok_or_else(|| { + InvalidShieldedProofError::new("invalid note commitment bytes".to_string()) + })?; + + let cv_net: ValueCommitment = + Option::from(ValueCommitment::from_bytes(&a.cv_net)).ok_or_else(|| { + InvalidShieldedProofError::new("invalid value commitment bytes".to_string()) + })?; + + let spend_auth_sig_bytes: [u8; 64] = + a.spend_auth_sig.as_slice().try_into().map_err(|_| { + InvalidShieldedProofError::new(format!( + "spend auth signature size mismatch: expected 64, got {}", + a.spend_auth_sig.len() + )) + })?; + + let action = Action::from_parts( + nullifier, + rk, + cmx, + TransmittedNoteCiphertext { + epk_bytes, + enc_ciphertext, + out_ciphertext, + }, + cv_net, + redpallas::Signature::from(spend_auth_sig_bytes), + ); + orchard_actions.push(action); + } + + // Reconstruct Authorized (proof + binding signature) + let binding_sig_bytes: [u8; 64] = binding_signature.try_into().map_err(|_| { + InvalidShieldedProofError::new(format!( + "binding signature size mismatch: expected 64, got {}", + binding_signature.len() + )) + })?; + + let authorized = Authorized::from_parts( + Proof::new(proof.to_vec()), + redpallas::Signature::from(binding_sig_bytes), + ); + + // Reconstruct Bundle + let orchard_flags = Flags::from_byte(flags).ok_or_else(|| { + InvalidShieldedProofError::new(format!("invalid bundle flags byte: {flags:#04x}")) + })?; + + let orchard_anchor = Option::from(Anchor::from_bytes(*anchor)).ok_or_else(|| { + InvalidShieldedProofError::new("invalid anchor bytes".to_string()) + })?; + + let actions_nonempty = nonempty::NonEmpty::from_vec(orchard_actions).ok_or_else(|| { + InvalidShieldedProofError::new("bundle has no actions".to_string()) + })?; + + let bundle = Bundle::from_parts( + actions_nonempty, + orchard_flags, + value_balance, + orchard_anchor, + authorized, + ); + + // Verify the Halo 2 proof + bundle.verify_proof(vk).map_err(|e| { + InvalidShieldedProofError::new(format!("proof verification failed: {e}")) + })?; + + Ok(()) +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/mod.rs index 6fae8a40d0a..102ae541f55 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/mod.rs @@ -2,6 +2,7 @@ mod transform_into_action; use dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition; use dpp::validation::ConsensusValidationResult; +use drive::grovedb::TransactionArg; use drive::state_transition_action::StateTransitionAction; use crate::error::execution::ExecutionError; @@ -18,6 +19,7 @@ pub trait StateTransitionShieldedTransferTransitionActionTransformer { fn transform_into_action_for_shielded_transfer_transition( &self, platform: &PlatformRef, + tx: TransactionArg, ) -> Result, Error>; } @@ -25,6 +27,7 @@ impl StateTransitionShieldedTransferTransitionActionTransformer for ShieldedTran fn transform_into_action_for_shielded_transfer_transition( &self, platform: &PlatformRef, + tx: TransactionArg, ) -> Result, Error> { let platform_version = platform.state.current_platform_version()?; @@ -35,7 +38,7 @@ impl StateTransitionShieldedTransferTransitionActionTransformer for ShieldedTran .shielded_transfer_state_transition .transform_into_action { - 0 => self.transform_into_action_v0(platform_version), + 0 => self.transform_into_action_v0(platform.drive, tx, platform_version), version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { method: "shielded transfer transition: transform_into_action".to_string(), known_versions: vec![0], diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs index d61eea10c59..7ddb9439949 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs @@ -1,15 +1,29 @@ use crate::error::Error; +use crate::execution::validation::state_transition::state_transitions::shielded_common::reconstruct_and_verify_bundle; +use dpp::consensus::state::shielded::invalid_anchor_error::InvalidAnchorError; +use dpp::consensus::state::shielded::nullifier_already_spent_error::NullifierAlreadySpentError; +use dpp::consensus::state::state_error::StateError; use dpp::fee::Credits; use dpp::prelude::ConsensusValidationResult; +use dpp::shielded::ShieldedPoolParams; use dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition; use dpp::version::PlatformVersion; +use drive::drive::shielded::paths::{ + shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, + shielded_credit_pool_path, SHIELDED_PARAMS_KEY, SHIELDED_TOTAL_BALANCE_KEY, +}; +use drive::drive::Drive; +use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::shielded_transfer::ShieldedTransferTransitionAction; use drive::state_transition_action::StateTransitionAction; +use drive::util::grove_operations::DirectQueryType; pub(in crate::execution::validation::state_transition::state_transitions::shielded_transfer) trait ShieldedTransferStateTransitionTransformIntoActionValidationV0 { fn transform_into_action_v0( &self, + drive: &Drive, + transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result, Error>; } @@ -19,7 +33,9 @@ impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 { fn transform_into_action_v0( &self, - _platform_version: &PlatformVersion, + drive: &Drive, + transaction: TransactionArg, + platform_version: &PlatformVersion, ) -> Result, Error> { // Extract nullifiers, note commitments, and encrypted notes from serialized actions let nullifiers: Vec<[u8; 32]> = match self { @@ -46,15 +62,102 @@ impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 ShieldedTransferTransition::V0(v0) => v0.value_balance as u64, }; - // TODO: Read current shielded pool state from GroveDB. - // These should be fetched from the shielded pool tree in GroveDB: - // - current_checkpoint_id: the latest checkpoint epoch ID - // - current_total_balance: the running total balance of the shielded pool - // For now, use default values until the GroveDB API for shielded pool is available. - let current_checkpoint_id: u64 = 0; - let current_total_balance: Credits = 0; + // Read current shielded pool state from GroveDB + let mut drive_operations = vec![]; + let pool_path = shielded_credit_pool_path(); + + let params_bytes = drive.grove_get_raw_item( + (&pool_path).into(), + &[SHIELDED_PARAMS_KEY], + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )?; + let (params, _): (ShieldedPoolParams, _) = + bincode::decode_from_slice(¶ms_bytes, bincode::config::standard()) + .map_err(|e| { + Error::Protocol( + dpp::ProtocolError::DecodingError(format!( + "could not decode shielded pool params: {e}" + )), + ) + })?; + let current_checkpoint_id = params.checkpoint_id_counter; + + let current_total_balance = drive + .grove_get_raw_value_u64_from_encoded_var_vec( + (&pool_path).into(), + &[SHIELDED_TOTAL_BALANCE_KEY], + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )? + .unwrap_or(0); + + // Verify the anchor exists in the recorded anchors tree + let anchors_path = shielded_anchors_credit_pool_path(); + let anchor_exists = drive.grove_has_raw( + (&anchors_path).into(), + &anchor, + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )?; + + if !anchor_exists { + return Ok(ConsensusValidationResult::new_with_error( + StateError::InvalidAnchorError(InvalidAnchorError::new(anchor)).into(), + )); + } + + // Check that no nullifier has already been spent + let nullifiers_path = shielded_credit_pool_nullifiers_path(); + for nullifier in &nullifiers { + let exists = drive.grove_has_raw( + (&nullifiers_path).into(), + nullifier, + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )?; + + if exists { + return Ok(ConsensusValidationResult::new_with_error( + StateError::NullifierAlreadySpentError( + NullifierAlreadySpentError::new(*nullifier), + ) + .into(), + )); + } + } + + // Verify the ZK proof + let (st_actions, st_flags, st_value_balance, st_proof, st_binding_sig) = match self { + ShieldedTransferTransition::V0(v0) => ( + &v0.actions, + v0.flags, + v0.value_balance, + v0.proof.as_slice(), + v0.binding_signature.as_slice(), + ), + }; - // TODO: Verify the anchor exists in the commitment tree before proceeding. + if let Err(e) = reconstruct_and_verify_bundle( + st_actions, + st_flags, + st_value_balance, + &anchor, + st_proof, + st_binding_sig, + ) { + return Ok(ConsensusValidationResult::new_with_error( + StateError::InvalidShieldedProofError(e).into(), + )); + } let result = ShieldedTransferTransitionAction::try_from_transition( self, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/mod.rs index 91eb04921c1..35f2394e8d9 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/mod.rs @@ -2,6 +2,7 @@ mod transform_into_action; use dpp::state_transition::unshield_transition::UnshieldTransition; use dpp::validation::ConsensusValidationResult; +use drive::grovedb::TransactionArg; use drive::state_transition_action::StateTransitionAction; use crate::error::execution::ExecutionError; @@ -18,6 +19,7 @@ pub trait StateTransitionUnshieldTransitionActionTransformer { fn transform_into_action_for_unshield_transition( &self, platform: &PlatformRef, + tx: TransactionArg, ) -> Result, Error>; } @@ -25,6 +27,7 @@ impl StateTransitionUnshieldTransitionActionTransformer for UnshieldTransition { fn transform_into_action_for_unshield_transition( &self, platform: &PlatformRef, + tx: TransactionArg, ) -> Result, Error> { let platform_version = platform.state.current_platform_version()?; @@ -35,7 +38,7 @@ impl StateTransitionUnshieldTransitionActionTransformer for UnshieldTransition { .unshield_state_transition .transform_into_action { - 0 => self.transform_into_action_v0(platform_version), + 0 => self.transform_into_action_v0(platform.drive, tx, platform_version), version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { method: "unshield transition: transform_into_action".to_string(), known_versions: vec![0], diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs index 96833110508..cc84ed59ad7 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs @@ -1,15 +1,28 @@ use crate::error::Error; -use dpp::fee::Credits; +use crate::execution::validation::state_transition::state_transitions::shielded_common::reconstruct_and_verify_bundle; +use dpp::consensus::state::shielded::invalid_anchor_error::InvalidAnchorError; +use dpp::consensus::state::shielded::nullifier_already_spent_error::NullifierAlreadySpentError; +use dpp::consensus::state::state_error::StateError; use dpp::prelude::ConsensusValidationResult; +use dpp::shielded::ShieldedPoolParams; use dpp::state_transition::unshield_transition::UnshieldTransition; use dpp::version::PlatformVersion; +use drive::drive::shielded::paths::{ + shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, + shielded_credit_pool_path, SHIELDED_PARAMS_KEY, SHIELDED_TOTAL_BALANCE_KEY, +}; +use drive::drive::Drive; +use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::unshield::UnshieldTransitionAction; use drive::state_transition_action::StateTransitionAction; +use drive::util::grove_operations::DirectQueryType; pub(in crate::execution::validation::state_transition::state_transitions::unshield) trait UnshieldStateTransitionTransformIntoActionValidationV0 { fn transform_into_action_v0( &self, + drive: &Drive, + transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result, Error>; } @@ -17,7 +30,9 @@ pub(in crate::execution::validation::state_transition::state_transitions::unshie impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransition { fn transform_into_action_v0( &self, - _platform_version: &PlatformVersion, + drive: &Drive, + transaction: TransactionArg, + platform_version: &PlatformVersion, ) -> Result, Error> { // Extract nullifiers, note commitments, and encrypted notes from serialized actions let nullifiers: Vec<[u8; 32]> = match self { @@ -37,15 +52,102 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti UnshieldTransition::V0(v0) => v0.anchor, }; - // TODO: Read current shielded pool state from GroveDB. - // These should be fetched from the shielded pool tree in GroveDB: - // - current_checkpoint_id: the latest checkpoint epoch ID - // - current_total_balance: the running total balance of the shielded pool - // For now, use default values until the GroveDB API for shielded pool is available. - let current_checkpoint_id: u64 = 0; - let current_total_balance: Credits = 0; + // Read current shielded pool state from GroveDB + let mut drive_operations = vec![]; + let pool_path = shielded_credit_pool_path(); + + let params_bytes = drive.grove_get_raw_item( + (&pool_path).into(), + &[SHIELDED_PARAMS_KEY], + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )?; + let (params, _): (ShieldedPoolParams, _) = + bincode::decode_from_slice(¶ms_bytes, bincode::config::standard()) + .map_err(|e| { + Error::Protocol( + dpp::ProtocolError::DecodingError(format!( + "could not decode shielded pool params: {e}" + )), + ) + })?; + let current_checkpoint_id = params.checkpoint_id_counter; + + let current_total_balance = drive + .grove_get_raw_value_u64_from_encoded_var_vec( + (&pool_path).into(), + &[SHIELDED_TOTAL_BALANCE_KEY], + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )? + .unwrap_or(0); + + // Verify the anchor exists in the recorded anchors tree + let anchors_path = shielded_anchors_credit_pool_path(); + let anchor_exists = drive.grove_has_raw( + (&anchors_path).into(), + &anchor, + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )?; + + if !anchor_exists { + return Ok(ConsensusValidationResult::new_with_error( + StateError::InvalidAnchorError(InvalidAnchorError::new(anchor)).into(), + )); + } + + // Check that no nullifier has already been spent + let nullifiers_path = shielded_credit_pool_nullifiers_path(); + for nullifier in &nullifiers { + let exists = drive.grove_has_raw( + (&nullifiers_path).into(), + nullifier, + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )?; + + if exists { + return Ok(ConsensusValidationResult::new_with_error( + StateError::NullifierAlreadySpentError( + NullifierAlreadySpentError::new(*nullifier), + ) + .into(), + )); + } + } + + // Verify the ZK proof + let (st_actions, st_flags, st_value_balance, st_proof, st_binding_sig) = match self { + UnshieldTransition::V0(v0) => ( + &v0.actions, + v0.flags, + v0.value_balance, + v0.proof.as_slice(), + v0.binding_signature.as_slice(), + ), + }; - // TODO: Verify the anchor exists in the commitment tree before proceeding. + if let Err(e) = reconstruct_and_verify_bundle( + st_actions, + st_flags, + st_value_balance, + &anchor, + st_proof, + st_binding_sig, + ) { + return Ok(ConsensusValidationResult::new_with_error( + StateError::InvalidShieldedProofError(e).into(), + )); + } let result = UnshieldTransitionAction::try_from_transition( self, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs index 2a959e5a850..b9653f46b45 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs @@ -242,13 +242,14 @@ impl StateTransitionActionTransformer for StateTransition { st.transform_into_action_for_shield_transition( platform, remaining_address_input_balances.clone(), + tx, ) } StateTransition::ShieldedTransfer(st) => { - st.transform_into_action_for_shielded_transfer_transition(platform) + st.transform_into_action_for_shielded_transfer_transition(platform, tx) } StateTransition::Unshield(st) => { - st.transform_into_action_for_unshield_transition(platform) + st.transform_into_action_for_unshield_transition(platform, tx) } } } diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs index 9a26559541f..2fa45f0869d 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs @@ -9,6 +9,7 @@ use crate::state_transition_action::shielded::shield::ShieldTransitionAction; use crate::state_transition_action::shielded::shielded_transfer::ShieldedTransferTransitionAction; use crate::state_transition_action::shielded::unshield::UnshieldTransitionAction; use crate::util::batch::drive_op_batch::AddressFundsOperationType; +use crate::util::batch::drive_op_batch::finalize_task::DriveOperationFinalizeTask; use crate::util::batch::DriveOperation; use dpp::block::epoch::Epoch; use dpp::shielded::ShieldedPoolParams; @@ -95,7 +96,10 @@ impl DriveHighLevelOperationConverter for ShieldTransitionAction { ), )); - // TODO: Record anchor after batch is applied (needs post-batch semantics) + // Record anchor after batch is applied (finalization task) + ops.push(DriveOperation::FinalizeOperation( + DriveOperationFinalizeTask::RecordShieldedAnchor, + )); Ok(ops) } @@ -186,7 +190,10 @@ impl DriveHighLevelOperationConverter for ShieldedTransferTransitionAction { ), )); - // TODO: Record anchor after batch is applied (needs post-batch semantics) + // Record anchor after batch is applied (finalization task) + ops.push(DriveOperation::FinalizeOperation( + DriveOperationFinalizeTask::RecordShieldedAnchor, + )); Ok(ops) } @@ -286,7 +293,10 @@ impl DriveHighLevelOperationConverter for UnshieldTransitionAction { ), )); - // TODO: Record anchor after batch is applied (needs post-batch semantics) + // Record anchor after batch is applied (finalization task) + ops.push(DriveOperation::FinalizeOperation( + DriveOperationFinalizeTask::RecordShieldedAnchor, + )); Ok(ops) } diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/drive_methods/apply_drive_operations/v0/mod.rs b/packages/rs-drive/src/util/batch/drive_op_batch/drive_methods/apply_drive_operations/v0/mod.rs index 0f707af00b8..f5a1ada1a2d 100644 --- a/packages/rs-drive/src/util/batch/drive_op_batch/drive_methods/apply_drive_operations/v0/mod.rs +++ b/packages/rs-drive/src/util/batch/drive_op_batch/drive_methods/apply_drive_operations/v0/mod.rs @@ -84,7 +84,7 @@ impl Drive { // Execute drive operation callbacks after updating state for task in finalize_tasks { - task.execute(self, platform_version); + task.execute(self, transaction, platform_version)?; } Drive::calculate_fee( diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs b/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs index b45d7c154d6..81db640f2ee 100644 --- a/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs +++ b/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs @@ -1,10 +1,17 @@ +use crate::drive::shielded::paths::{ + shielded_anchors_credit_pool_path, shielded_credit_pool_path, SHIELDED_COMMITMENTS_KEY, +}; use crate::drive::Drive; use crate::error::Error; use dpp::prelude::Identifier; use dpp::version::PlatformVersion; +use grovedb::{Element, TransactionArg}; +#[derive(Clone, Debug)] pub enum DriveOperationFinalizeTask { RemoveDataContractFromCache { contract_id: Identifier }, + /// Record the current commitment tree root hash as a new anchor + RecordShieldedAnchor, } /// Enable callbacks for drive operations that will be called after successful execution @@ -17,10 +24,47 @@ pub trait DriveOperationFinalizationTasks { } impl DriveOperationFinalizeTask { - pub fn execute(self, drive: &Drive, _platform_version: &PlatformVersion) { + pub fn execute( + self, + drive: &Drive, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { match self { DriveOperationFinalizeTask::RemoveDataContractFromCache { contract_id } => { drive.cache.data_contracts.remove(contract_id.to_buffer()); + Ok(()) + } + DriveOperationFinalizeTask::RecordShieldedAnchor => { + let grove_version = &platform_version.drive.grove_version; + + // Get the current root hash of the commitment tree + let root_hash = drive + .grove + .commitment_tree_root_hash( + &shielded_credit_pool_path(), + &[SHIELDED_COMMITMENTS_KEY], + transaction, + grove_version, + ) + .unwrap() + .map_err(Error::from)?; + + // Insert the root hash as an empty Item into the anchors tree + drive + .grove + .insert( + &shielded_anchors_credit_pool_path(), + &root_hash, + Element::Item(vec![], None), + None, + transaction, + grove_version, + ) + .unwrap() + .map_err(Error::from)?; + + Ok(()) } } } diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/mod.rs b/packages/rs-drive/src/util/batch/drive_op_batch/mod.rs index e3703034296..fe5e2f79e45 100644 --- a/packages/rs-drive/src/util/batch/drive_op_batch/mod.rs +++ b/packages/rs-drive/src/util/batch/drive_op_batch/mod.rs @@ -2,7 +2,7 @@ mod address_funds; mod contract; mod document; mod drive_methods; -mod finalize_task; +pub(crate) mod finalize_task; mod group; mod identity; mod prefunded_specialized_balance; @@ -94,6 +94,8 @@ pub enum DriveOperation<'a> { GroveDBOperation(QualifiedGroveDbOp), /// Multiple low level groveDB operations GroveDBOpBatch(GroveDbOpBatch), + /// An operation that only produces finalization tasks (no low-level ops) + FinalizeOperation(DriveOperationFinalizeTask), } impl DriveLowLevelOperationConverter for DriveOperation<'_> { @@ -190,6 +192,7 @@ impl DriveLowLevelOperationConverter for DriveOperation<'_> { platform_version, ) } + DriveOperation::FinalizeOperation(_) => Ok(vec![]), } } } @@ -223,6 +226,7 @@ impl DriveOperation<'_> { ) -> Result>, Error> { match self { DriveOperation::DataContractOperation(o) => o.finalization_tasks(platform_version), + DriveOperation::FinalizeOperation(task) => Ok(Some(vec![task.clone()])), _ => Ok(None), } } From f27fe8e60c231122f1b324a0a6495762a0c4c80d Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 10 Feb 2026 07:25:41 +0000 Subject: [PATCH 04/40] more work --- .../state_transitions/shield/tests.rs | 14 ++++++----- .../shield/transform_into_action/v0/mod.rs | 25 +++++++++++++++++-- .../shielded_transfer/mod.rs | 3 +++ .../state_transitions/unshield/mod.rs | 3 +++ .../transformer.rs | 23 +++++++++++++++++ .../v0/transformer.rs | 18 +++++++++++++ .../drive_abci_validation_versions/mod.rs | 2 ++ .../drive_abci_validation_versions/v1.rs | 1 + .../drive_abci_validation_versions/v2.rs | 1 + .../drive_abci_validation_versions/v3.rs | 1 + .../drive_abci_validation_versions/v4.rs | 1 + .../drive_abci_validation_versions/v5.rs | 1 + .../drive_abci_validation_versions/v6.rs | 1 + .../drive_abci_validation_versions/v7.rs | 1 + 14 files changed, 87 insertions(+), 8 deletions(-) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs index 919abf8ced8..d10d092fc06 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs @@ -924,9 +924,10 @@ mod tests { // at the actual proof verification step. assert_matches!( processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) - )] + [StateTransitionExecutionResult::PaidConsensusError { + error: ConsensusError::StateError(StateError::InvalidShieldedProofError(_)), + .. + }] ); } @@ -970,9 +971,10 @@ mod tests { // which runs during transform_into_action after all prior validations pass. assert_matches!( processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) - )] + [StateTransitionExecutionResult::PaidConsensusError { + error: ConsensusError::StateError(StateError::InvalidShieldedProofError(_)), + .. + }] ); } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs index abb57553c4a..8f6742a7704 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs @@ -13,6 +13,7 @@ use drive::drive::shielded::paths::{ use drive::drive::Drive; use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::shield::ShieldTransitionAction; +use drive::state_transition_action::system::bump_address_input_nonces_action::BumpAddressInputNoncesAction; use drive::state_transition_action::StateTransitionAction; use drive::util::grove_operations::DirectQueryType; use std::collections::BTreeMap; @@ -105,8 +106,28 @@ impl ShieldStateTransitionTransformIntoActionValidationV0 for ShieldTransition { proof, binding_signature, ) { - return Ok(ConsensusValidationResult::new_with_error( - StateError::InvalidShieldedProofError(e).into(), + let penalty = platform_version + .drive_abci + .validation_and_processing + .penalties + .shielded_proof_verification_failure; + + let (fee_strategy, user_fee_increase) = match self { + ShieldTransition::V0(v0) => (&v0.fee_strategy, v0.user_fee_increase), + }; + + let bump_action = StateTransitionAction::BumpAddressInputNoncesAction( + BumpAddressInputNoncesAction::from_inputs_with_remaining_balance( + &inputs_with_remaining_balance, + fee_strategy, + penalty, + user_fee_increase, + ), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + bump_action, + vec![StateError::InvalidShieldedProofError(e).into()], )); } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/mod.rs index 102ae541f55..4aa62c80362 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/mod.rs @@ -1,5 +1,8 @@ mod transform_into_action; +#[cfg(test)] +mod tests; + use dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition; use dpp::validation::ConsensusValidationResult; use drive::grovedb::TransactionArg; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/mod.rs index 35f2394e8d9..e798a9037c9 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/mod.rs @@ -1,5 +1,8 @@ mod transform_into_action; +#[cfg(test)] +mod tests; + use dpp::state_transition::unshield_transition::UnshieldTransition; use dpp::validation::ConsensusValidationResult; use drive::grovedb::TransactionArg; diff --git a/packages/rs-drive/src/state_transition_action/system/bump_address_input_nonces_action/transformer.rs b/packages/rs-drive/src/state_transition_action/system/bump_address_input_nonces_action/transformer.rs index cb4dc11153e..a21fd9ceed6 100644 --- a/packages/rs-drive/src/state_transition_action/system/bump_address_input_nonces_action/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/system/bump_address_input_nonces_action/transformer.rs @@ -4,12 +4,35 @@ use crate::state_transition_action::identity::identity_topup_from_addresses::Ide use crate::state_transition_action::system::bump_address_input_nonces_action::{ BumpAddressInputNoncesAction, BumpAddressInputNoncesActionV0, }; +use dpp::address_funds::fee_strategy::AddressFundsFeeStrategy; +use dpp::address_funds::PlatformAddress; use dpp::fee::Credits; +use dpp::prelude::{AddressNonce, UserFeeIncrease}; use dpp::state_transition::state_transitions::address_funds::address_funds_transfer_transition::AddressFundsTransferTransition; use dpp::state_transition::state_transitions::identity::identity_create_from_addresses_transition::IdentityCreateFromAddressesTransition; use dpp::state_transition::state_transitions::identity::identity_topup_from_addresses_transition::IdentityTopUpFromAddressesTransition; +use std::collections::BTreeMap; impl BumpAddressInputNoncesAction { + // Generic constructor from pre-computed inputs + + /// from inputs with remaining balance (used by shield transitions where + /// the remaining balances are computed by the processing pipeline) + pub fn from_inputs_with_remaining_balance( + inputs_with_remaining_balance: &BTreeMap, + fee_strategy: &AddressFundsFeeStrategy, + penalty_credits: Credits, + user_fee_increase: UserFeeIncrease, + ) -> Self { + BumpAddressInputNoncesActionV0::from_inputs_with_remaining_balance( + inputs_with_remaining_balance, + fee_strategy, + penalty_credits, + user_fee_increase, + ) + .into() + } + // IdentityCreateFromAddresses transformers /// from IdentityCreateFromAddresses transition diff --git a/packages/rs-drive/src/state_transition_action/system/bump_address_input_nonces_action/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/system/bump_address_input_nonces_action/v0/transformer.rs index 1c2aa1d91ff..17b41e0a4c2 100644 --- a/packages/rs-drive/src/state_transition_action/system/bump_address_input_nonces_action/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/system/bump_address_input_nonces_action/v0/transformer.rs @@ -77,6 +77,24 @@ impl BumpAddressInputNoncesActionV0 { } } + // Generic constructor from pre-computed inputs + + /// from inputs with remaining balance (used by shield transitions where + /// the remaining balances are computed by the processing pipeline) + pub fn from_inputs_with_remaining_balance( + inputs_with_remaining_balance: &BTreeMap, + fee_strategy: &AddressFundsFeeStrategy, + penalty_credits: Credits, + user_fee_increase: UserFeeIncrease, + ) -> Self { + Self::new_with_penalty( + inputs_with_remaining_balance, + fee_strategy, + penalty_credits, + user_fee_increase, + ) + } + // IdentityCreateFromAddresses transformers /// from borrowed IdentityCreateFromAddresses transition 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 decad09ad4f..cd1be732674 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 @@ -87,6 +87,8 @@ pub struct PenaltyAmounts { pub validation_of_added_keys_proof_of_possession_failure: u64, /// Penalty for address funding with insufficient funds for outputs pub address_funds_insufficient_balance: u64, + /// Penalty for submitting a shield transition with an invalid ZK proof + pub shielded_proof_verification_failure: u64, } #[derive(Clone, Copy, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs index 2f2cb5e3bfc..0b919b3ba6e 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs @@ -236,6 +236,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V1: DriveAbciValidationVersions = validation_of_added_keys_structure_failure: 10000000, validation_of_added_keys_proof_of_possession_failure: 50000000, address_funds_insufficient_balance: 10000000, + shielded_proof_verification_failure: 50000000, }, event_constants: DriveAbciValidationConstants { maximum_vote_polls_to_process: 2, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs index e9682304d7e..7f07ee00a91 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs @@ -236,6 +236,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V2: DriveAbciValidationVersions = validation_of_added_keys_structure_failure: 10000000, validation_of_added_keys_proof_of_possession_failure: 50000000, address_funds_insufficient_balance: 10000000, + shielded_proof_verification_failure: 50000000, }, event_constants: DriveAbciValidationConstants { maximum_vote_polls_to_process: 2, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs index 5803d5c492c..a4beaa2fb87 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs @@ -236,6 +236,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V3: DriveAbciValidationVersions = validation_of_added_keys_structure_failure: 10000000, validation_of_added_keys_proof_of_possession_failure: 50000000, address_funds_insufficient_balance: 10000000, + shielded_proof_verification_failure: 50000000, }, event_constants: DriveAbciValidationConstants { maximum_vote_polls_to_process: 2, 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 74ccf1c3735..228a3c3d8bc 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 @@ -239,6 +239,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V4: DriveAbciValidationVersions = validation_of_added_keys_structure_failure: 10000000, validation_of_added_keys_proof_of_possession_failure: 50000000, address_funds_insufficient_balance: 10000000, + shielded_proof_verification_failure: 50000000, }, event_constants: DriveAbciValidationConstants { maximum_vote_polls_to_process: 2, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs index aea4c18ce6f..0aa70e5f460 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs @@ -240,6 +240,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V5: DriveAbciValidationVersions = validation_of_added_keys_structure_failure: 10000000, validation_of_added_keys_proof_of_possession_failure: 50000000, address_funds_insufficient_balance: 10000000, + shielded_proof_verification_failure: 50000000, }, event_constants: DriveAbciValidationConstants { maximum_vote_polls_to_process: 2, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs index d4c07ee6082..78c31aefa9c 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs @@ -243,6 +243,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V6: DriveAbciValidationVersions = validation_of_added_keys_structure_failure: 10000000, validation_of_added_keys_proof_of_possession_failure: 50000000, address_funds_insufficient_balance: 10000000, + shielded_proof_verification_failure: 50000000, }, event_constants: DriveAbciValidationConstants { maximum_vote_polls_to_process: 2, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs index da426ac0c1a..f5d4ea5e209 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs @@ -237,6 +237,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V7: DriveAbciValidationVersions = validation_of_added_keys_structure_failure: 10000000, validation_of_added_keys_proof_of_possession_failure: 50000000, address_funds_insufficient_balance: 10000000, + shielded_proof_verification_failure: 50000000, }, event_constants: DriveAbciValidationConstants { maximum_vote_polls_to_process: 2, From 0a833eff62c7c01cef5907ffc2e93facf77a28c7 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 10 Feb 2026 07:26:14 +0000 Subject: [PATCH 05/40] more work --- .../state/shielded/invalid_anchor_error.rs | 5 +- .../state_transitions/shield/tests.rs | 181 ++---- .../shield/transform_into_action/v0/mod.rs | 23 +- .../state_transitions/shielded_common/mod.rs | 26 +- .../shielded_transfer/tests.rs | 473 ++++++++++++++ .../transform_into_action/v0/mod.rs | 37 +- .../state_transitions/unshield/tests.rs | 581 ++++++++++++++++++ .../unshield/transform_into_action/v0/mod.rs | 29 +- .../shielded/mod.rs | 6 +- .../batch/drive_op_batch/finalize_task.rs | 4 +- 10 files changed, 1169 insertions(+), 196 deletions(-) create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs diff --git a/packages/rs-dpp/src/errors/consensus/state/shielded/invalid_anchor_error.rs b/packages/rs-dpp/src/errors/consensus/state/shielded/invalid_anchor_error.rs index 59ce4e3bb5f..f0839902d57 100644 --- a/packages/rs-dpp/src/errors/consensus/state/shielded/invalid_anchor_error.rs +++ b/packages/rs-dpp/src/errors/consensus/state/shielded/invalid_anchor_error.rs @@ -9,7 +9,10 @@ use thiserror::Error; Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, )] #[platform_serialize(unversioned)] -#[error("Anchor not found in the recorded anchors tree: {}", hex::encode(anchor))] +#[error( + "Anchor not found in the recorded anchors tree: {}", + hex::encode(anchor) +)] pub struct InvalidAnchorError { /* diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs index d10d092fc06..245d15f25e7 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs @@ -18,12 +18,12 @@ mod tests { use dpp::consensus::ConsensusError; use dpp::dash_to_credits; use dpp::fee::Credits; - use dpp::prelude::AddressNonce; use dpp::identity::signer::Signer; + use dpp::prelude::AddressNonce; use dpp::serialization::{PlatformSerializable, Signable}; use dpp::shielded::SerializedAction; - use dpp::state_transition::shield_transition::ShieldTransition; use dpp::state_transition::shield_transition::v0::ShieldTransitionV0; + use dpp::state_transition::shield_transition::ShieldTransition; use dpp::state_transition::StateTransition; use platform_version::version::PlatformVersion; use std::collections::BTreeMap; @@ -58,9 +58,8 @@ mod tests { fee_strategy: AddressFundsFeeStrategy, witness_count: usize, ) -> StateTransition { - let witnesses: Vec = (0..witness_count) - .map(|_| create_dummy_witness()) - .collect(); + let witnesses: Vec = + (0..witness_count).map(|_| create_dummy_witness()).collect(); StateTransition::Shield(ShieldTransition::V0(ShieldTransitionV0 { inputs, actions, @@ -205,12 +204,7 @@ mod tests { // witness and address validation let mut signer = TestAddressSigner::new(); let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance( - &mut platform, - input_address, - 0, - dash_to_credits!(1.0), - ); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); let mut inputs = BTreeMap::new(); inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); @@ -223,9 +217,9 @@ mod tests { -1000, vec![0u8; 100], vec![0u8; 64], - AddressFundsFeeStrategy::from(vec![ - AddressFundsFeeStrategyStep::DeductFromInput(0), - ]), + AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( + 0, + )]), ); let processing_result = process_transition(&platform, transition, platform_version); @@ -251,9 +245,9 @@ mod tests { -1000, vec![0u8; 100], vec![0u8; 64], - AddressFundsFeeStrategy::from(vec![ - AddressFundsFeeStrategyStep::DeductFromInput(0), - ]), + AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( + 0, + )]), 0, // 0 witnesses to match 0 inputs ); @@ -274,12 +268,7 @@ mod tests { let mut signer = TestAddressSigner::new(); let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance( - &mut platform, - input_address, - 0, - dash_to_credits!(1.0), - ); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); // Create a properly signed transition (1 input, 1 valid witness) let mut transition = create_default_signed_shield_transition( @@ -315,12 +304,7 @@ mod tests { let mut signer = TestAddressSigner::new(); let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance( - &mut platform, - input_address, - 0, - dash_to_credits!(1.0), - ); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); let mut inputs = BTreeMap::new(); inputs.insert(input_address, (1 as AddressNonce, 1)); // 1 credit — below minimum @@ -333,9 +317,9 @@ mod tests { -1, vec![0u8; 100], vec![0u8; 64], - AddressFundsFeeStrategy::from(vec![ - AddressFundsFeeStrategyStep::DeductFromInput(0), - ]), + AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( + 0, + )]), ); let processing_result = process_transition(&platform, transition, platform_version); @@ -355,12 +339,7 @@ mod tests { let mut signer = TestAddressSigner::new(); let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance( - &mut platform, - input_address, - 0, - dash_to_credits!(1.0), - ); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); let mut inputs = BTreeMap::new(); inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); @@ -373,9 +352,9 @@ mod tests { 1000, // Positive — invalid for shield (must be negative) vec![0u8; 100], vec![0u8; 64], - AddressFundsFeeStrategy::from(vec![ - AddressFundsFeeStrategyStep::DeductFromInput(0), - ]), + AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( + 0, + )]), ); let processing_result = process_transition(&platform, transition, platform_version); @@ -395,12 +374,7 @@ mod tests { let mut signer = TestAddressSigner::new(); let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance( - &mut platform, - input_address, - 0, - dash_to_credits!(1.0), - ); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); let mut inputs = BTreeMap::new(); inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); @@ -413,9 +387,9 @@ mod tests { 0, // Zero — invalid for shield (must be negative) vec![0u8; 100], vec![0u8; 64], - AddressFundsFeeStrategy::from(vec![ - AddressFundsFeeStrategyStep::DeductFromInput(0), - ]), + AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( + 0, + )]), ); let processing_result = process_transition(&platform, transition, platform_version); @@ -435,12 +409,7 @@ mod tests { let mut signer = TestAddressSigner::new(); let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance( - &mut platform, - input_address, - 0, - dash_to_credits!(1.0), - ); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); let mut inputs = BTreeMap::new(); inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); @@ -453,9 +422,9 @@ mod tests { -1000, vec![], // Empty proof — invalid vec![0u8; 64], - AddressFundsFeeStrategy::from(vec![ - AddressFundsFeeStrategyStep::DeductFromInput(0), - ]), + AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( + 0, + )]), ); let processing_result = process_transition(&platform, transition, platform_version); @@ -475,12 +444,7 @@ mod tests { let mut signer = TestAddressSigner::new(); let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance( - &mut platform, - input_address, - 0, - dash_to_credits!(1.0), - ); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); let mut inputs = BTreeMap::new(); inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); @@ -493,9 +457,9 @@ mod tests { -1000, vec![0u8; 100], vec![0u8; 32], // 32 bytes instead of 64 — invalid - AddressFundsFeeStrategy::from(vec![ - AddressFundsFeeStrategyStep::DeductFromInput(0), - ]), + AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( + 0, + )]), ); let processing_result = process_transition(&platform, transition, platform_version); @@ -515,12 +479,7 @@ mod tests { let mut signer = TestAddressSigner::new(); let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance( - &mut platform, - input_address, - 0, - dash_to_credits!(1.0), - ); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); let mut inputs = BTreeMap::new(); inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); @@ -536,9 +495,9 @@ mod tests { -1000, vec![0u8; 100], vec![0u8; 64], - AddressFundsFeeStrategy::from(vec![ - AddressFundsFeeStrategyStep::DeductFromInput(0), - ]), + AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( + 0, + )]), ); let processing_result = process_transition(&platform, transition, platform_version); @@ -558,12 +517,7 @@ mod tests { let mut signer = TestAddressSigner::new(); let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance( - &mut platform, - input_address, - 0, - dash_to_credits!(1.0), - ); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); let mut inputs = BTreeMap::new(); inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); @@ -596,12 +550,7 @@ mod tests { let mut signer = TestAddressSigner::new(); let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance( - &mut platform, - input_address, - 0, - dash_to_credits!(1.0), - ); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); let mut inputs = BTreeMap::new(); inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); @@ -641,12 +590,7 @@ mod tests { let mut signer = TestAddressSigner::new(); let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance( - &mut platform, - input_address, - 0, - dash_to_credits!(1.0), - ); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); let mut inputs = BTreeMap::new(); inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); @@ -690,12 +634,7 @@ mod tests { let mut signer = TestAddressSigner::new(); let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance( - &mut platform, - input_address, - 0, - dash_to_credits!(1.0), - ); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); // Create properly signed transition, then tamper with the witness let mut transition = create_default_signed_shield_transition( @@ -736,12 +675,7 @@ mod tests { let mut signer = TestAddressSigner::new(); let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance( - &mut platform, - input_address, - 0, - dash_to_credits!(1.0), - ); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); // Create a second signer with different key let mut wrong_signer = TestAddressSigner::new(); @@ -760,9 +694,9 @@ mod tests { -1000, vec![0u8; 100], vec![0u8; 64], - AddressFundsFeeStrategy::from(vec![ - AddressFundsFeeStrategyStep::DeductFromInput(0), - ]), + AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( + 0, + )]), ); // Replace the valid witness with one signed by a different key @@ -831,12 +765,7 @@ mod tests { let mut signer = TestAddressSigner::new(); let input_address = signer.add_p2pkh([1u8; 32]); // Set up address with nonce 0 - setup_address_with_balance( - &mut platform, - input_address, - 0, - dash_to_credits!(1.0), - ); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); // Create transition with nonce 5 (expected nonce is 1) let transition = create_default_signed_shield_transition( @@ -899,12 +828,7 @@ mod tests { let mut signer = TestAddressSigner::new(); let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance( - &mut platform, - input_address, - 0, - dash_to_credits!(1.0), - ); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); // This transition is structurally valid but has random ZK proof data. // It should pass structure validation, witness validation, and address validation @@ -938,12 +862,7 @@ mod tests { let mut signer = TestAddressSigner::new(); let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance( - &mut platform, - input_address, - 0, - dash_to_credits!(1.0), - ); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); // Create action with wrong encrypted_note size let mut bad_action = create_dummy_serialized_action(); @@ -960,9 +879,9 @@ mod tests { -1000, vec![0u8; 100], vec![0u8; 64], - AddressFundsFeeStrategy::from(vec![ - AddressFundsFeeStrategyStep::DeductFromInput(0), - ]), + AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( + 0, + )]), ); let processing_result = process_transition(&platform, transition, platform_version); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs index 8f6742a7704..5dddfbf2c76 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs @@ -42,9 +42,11 @@ impl ShieldStateTransitionTransformIntoActionValidationV0 for ShieldTransition { ShieldTransition::V0(v0) => v0.actions.iter().map(|a| a.cmx).collect(), }; let encrypted_notes: Vec> = match self { - ShieldTransition::V0(v0) => { - v0.actions.iter().map(|a| a.encrypted_note.clone()).collect() - } + ShieldTransition::V0(v0) => v0 + .actions + .iter() + .map(|a| a.encrypted_note.clone()) + .collect(), }; // The value_balance is negative for shield (funds flowing into the pool) @@ -65,14 +67,13 @@ impl ShieldStateTransitionTransformIntoActionValidationV0 for ShieldTransition { &platform_version.drive, )?; let (params, _): (ShieldedPoolParams, _) = - bincode::decode_from_slice(¶ms_bytes, bincode::config::standard()) - .map_err(|e| { - Error::Protocol( - dpp::ProtocolError::DecodingError(format!( - "could not decode shielded pool params: {e}" - )), - ) - })?; + bincode::decode_from_slice(¶ms_bytes, bincode::config::standard()).map_err( + |e| { + Error::Protocol(dpp::ProtocolError::DecodingError(format!( + "could not decode shielded pool params: {e}" + ))) + }, + )?; let current_checkpoint_id = params.checkpoint_id_counter; let current_total_balance = drive diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs index ef3397ecf7b..268f420f943 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs @@ -59,10 +59,8 @@ pub fn reconstruct_and_verify_bundle( .try_into() .unwrap(); - let nullifier: Nullifier = - Option::from(Nullifier::from_bytes(&a.nullifier)).ok_or_else(|| { - InvalidShieldedProofError::new("invalid nullifier bytes".to_string()) - })?; + let nullifier: Nullifier = Option::from(Nullifier::from_bytes(&a.nullifier)) + .ok_or_else(|| InvalidShieldedProofError::new("invalid nullifier bytes".to_string()))?; let rk = redpallas::VerificationKey::try_from(a.rk).map_err(|e| { InvalidShieldedProofError::new(format!("invalid spend validating key: {e}")) @@ -73,8 +71,8 @@ pub fn reconstruct_and_verify_bundle( InvalidShieldedProofError::new("invalid note commitment bytes".to_string()) })?; - let cv_net: ValueCommitment = - Option::from(ValueCommitment::from_bytes(&a.cv_net)).ok_or_else(|| { + let cv_net: ValueCommitment = Option::from(ValueCommitment::from_bytes(&a.cv_net)) + .ok_or_else(|| { InvalidShieldedProofError::new("invalid value commitment bytes".to_string()) })?; @@ -119,13 +117,11 @@ pub fn reconstruct_and_verify_bundle( InvalidShieldedProofError::new(format!("invalid bundle flags byte: {flags:#04x}")) })?; - let orchard_anchor = Option::from(Anchor::from_bytes(*anchor)).ok_or_else(|| { - InvalidShieldedProofError::new("invalid anchor bytes".to_string()) - })?; + let orchard_anchor = Option::from(Anchor::from_bytes(*anchor)) + .ok_or_else(|| InvalidShieldedProofError::new("invalid anchor bytes".to_string()))?; - let actions_nonempty = nonempty::NonEmpty::from_vec(orchard_actions).ok_or_else(|| { - InvalidShieldedProofError::new("bundle has no actions".to_string()) - })?; + let actions_nonempty = nonempty::NonEmpty::from_vec(orchard_actions) + .ok_or_else(|| InvalidShieldedProofError::new("bundle has no actions".to_string()))?; let bundle = Bundle::from_parts( actions_nonempty, @@ -136,9 +132,9 @@ pub fn reconstruct_and_verify_bundle( ); // Verify the Halo 2 proof - bundle.verify_proof(vk).map_err(|e| { - InvalidShieldedProofError::new(format!("proof verification failed: {e}")) - })?; + bundle + .verify_proof(vk) + .map_err(|e| InvalidShieldedProofError::new(format!("proof verification failed: {e}")))?; Ok(()) } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs new file mode 100644 index 00000000000..0f35a6f9e74 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs @@ -0,0 +1,473 @@ +#[cfg(test)] +mod tests { + use crate::config::{PlatformConfig, PlatformTestConfig}; + use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; + use crate::test::helpers::setup::TestPlatformBuilder; + use assert_matches::assert_matches; + use dpp::block::block_info::BlockInfo; + use dpp::consensus::basic::BasicError; + use dpp::consensus::state::state_error::StateError; + use dpp::consensus::ConsensusError; + use dpp::serialization::PlatformSerializable; + use dpp::shielded::SerializedAction; + use dpp::state_transition::shielded_transfer_transition::v0::ShieldedTransferTransitionV0; + use dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition; + use dpp::state_transition::StateTransition; + use drive::drive::shielded::paths::{ + shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, + }; + use drive::grovedb::Element; + use platform_version::version::PlatformVersion; + + // ========================================== + // Helper Functions + // ========================================== + + /// Create a `SerializedAction` with syntactically valid sizes but meaningless crypto data. + /// Passes structure validation (correct field sizes) but will fail ZK proof verification. + fn create_dummy_serialized_action() -> SerializedAction { + SerializedAction { + nullifier: [1u8; 32], + rk: [2u8; 32], + cmx: [3u8; 32], + encrypted_note: vec![4u8; 692], // epk(32) + enc(580) + out(80) + cv_net: [5u8; 32], + spend_auth_sig: vec![6u8; 64], + } + } + + /// Builds a `ShieldedTransferTransition` state transition. + /// No signing needed since shielded transfers have no witnesses. + fn create_shielded_transfer_transition( + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: Vec, + user_fee_increase: u16, + ) -> StateTransition { + StateTransition::ShieldedTransfer(ShieldedTransferTransition::V0( + ShieldedTransferTransitionV0 { + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + user_fee_increase, + }, + )) + } + + /// Shorthand for creating a structurally valid (but cryptographically invalid) shielded + /// transfer transition. Has a non-zero anchor, valid field sizes, but random data. + fn create_default_shielded_transfer_transition() -> StateTransition { + create_shielded_transfer_transition( + vec![create_dummy_serialized_action()], + 0x03, // spends_enabled | outputs_enabled + 0, // zero fee + [42u8; 32], // non-zero anchor + vec![0u8; 100], // dummy proof bytes + vec![0u8; 64], // dummy binding signature + 0, + ) + } + + /// Insert a fake anchor into the shielded anchors tree via GroveDB. + fn insert_anchor_into_state( + platform: &crate::test::helpers::setup::TempPlatform, + anchor: &[u8; 32], + ) { + let platform_version = PlatformVersion::latest(); + let grove_version = &platform_version.drive.grove_version; + let transaction = platform.drive.grove.start_transaction(); + let anchors_path = shielded_anchors_credit_pool_path(); + + platform + .drive + .grove + .insert( + &anchors_path, + anchor, + Element::Item(vec![], None), + None, + Some(&transaction), + grove_version, + ) + .unwrap() + .expect("should insert anchor"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("should commit transaction"); + } + + /// Insert a nullifier into the nullifiers tree via GroveDB. + fn insert_nullifier_into_state( + platform: &crate::test::helpers::setup::TempPlatform, + nullifier: &[u8; 32], + ) { + let platform_version = PlatformVersion::latest(); + let grove_version = &platform_version.drive.grove_version; + let transaction = platform.drive.grove.start_transaction(); + let nullifiers_path = shielded_credit_pool_nullifiers_path(); + + platform + .drive + .grove + .insert( + &nullifiers_path, + nullifier, + Element::Item(vec![], None), + None, + Some(&transaction), + grove_version, + ) + .unwrap() + .expect("should insert nullifier"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("should commit transaction"); + } + + /// Standard platform setup for tests. + fn setup_platform( + ) -> crate::test::helpers::setup::TempPlatform { + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + TestPlatformBuilder::new() + .with_config(platform_config) + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state() + } + + /// Execute a state transition through the full processing pipeline and return the result. + fn process_transition( + platform: &crate::test::helpers::setup::TempPlatform, + transition: StateTransition, + platform_version: &PlatformVersion, + ) -> crate::platform_types::state_transitions_processing_result::StateTransitionsProcessingResult + { + let transition_bytes = transition + .serialize_to_bytes() + .expect("should serialize transition"); + let platform_state = platform.state.load(); + let transaction = platform.drive.grove.start_transaction(); + + platform + .platform + .process_raw_state_transitions( + &vec![transition_bytes], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition") + } + + // ========================================== + // STRUCTURE VALIDATION TESTS (BasicError) + // ========================================== + + mod structure_validation { + use super::*; + + #[test] + fn test_empty_actions_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_shielded_transfer_transition( + vec![], // Empty actions — invalid + 0x03, + 0, + [42u8; 32], + vec![0u8; 100], + vec![0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_negative_value_balance_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_shielded_transfer_transition( + vec![create_dummy_serialized_action()], + 0x03, + -1000, // Negative — invalid for shielded transfer (must be >= 0) + [42u8; 32], + vec![0u8; 100], + vec![0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_empty_proof_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_shielded_transfer_transition( + vec![create_dummy_serialized_action()], + 0x03, + 0, + [42u8; 32], + vec![], // Empty proof — invalid + vec![0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_wrong_binding_sig_length_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_shielded_transfer_transition( + vec![create_dummy_serialized_action()], + 0x03, + 0, + [42u8; 32], + vec![0u8; 100], + vec![0u8; 32], // 32 bytes instead of 64 — invalid + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_wrong_spend_auth_sig_length_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let mut bad_action = create_dummy_serialized_action(); + bad_action.spend_auth_sig = vec![0u8; 32]; // 32 bytes instead of 64 + + let transition = create_shielded_transfer_transition( + vec![bad_action], + 0x03, + 0, + [42u8; 32], + vec![0u8; 100], + vec![0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_zero_anchor_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_shielded_transfer_transition( + vec![create_dummy_serialized_action()], + 0x03, + 0, + [0u8; 32], // All zeros — invalid + vec![0u8; 100], + vec![0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + } + + // ========================================== + // ANCHOR VALIDATION TESTS (StateError) + // ========================================== + + mod anchor_validation { + use super::*; + + #[test] + fn test_invalid_anchor_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + // Non-zero anchor that doesn't exist in state + let transition = create_default_shielded_transfer_transition(); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidAnchorError(_)) + )] + ); + } + } + + // ========================================== + // NULLIFIER DOUBLE-SPEND TESTS (StateError) + // ========================================== + + mod nullifier_validation { + use super::*; + + #[test] + fn test_nullifier_already_spent_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let anchor = [42u8; 32]; + let nullifier = [1u8; 32]; // Same as create_dummy_serialized_action().nullifier + + // Insert the anchor so anchor validation passes + insert_anchor_into_state(&platform, &anchor); + + // Insert the nullifier so it appears already spent + insert_nullifier_into_state(&platform, &nullifier); + + let transition = create_default_shielded_transfer_transition(); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::NullifierAlreadySpentError(_)) + )] + ); + } + } + + // ========================================== + // ZK PROOF VERIFICATION TESTS (InvalidShieldedProofError) + // ========================================== + + mod proof_verification { + use super::*; + + #[test] + fn test_invalid_proof_returns_shielded_proof_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let anchor = [42u8; 32]; + + // Insert the anchor so anchor validation passes + insert_anchor_into_state(&platform, &anchor); + + // This transition is structurally valid and has a valid anchor, + // but has random ZK proof data. It should pass structure validation + // and anchor validation but fail at proof verification. + let transition = create_default_shielded_transfer_transition(); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + + #[test] + fn test_wrong_encrypted_note_size_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let anchor = [42u8; 32]; + + // Insert the anchor so anchor validation passes + insert_anchor_into_state(&platform, &anchor); + + // Create action with wrong encrypted_note size + let mut bad_action = create_dummy_serialized_action(); + bad_action.encrypted_note = vec![0u8; 100]; // 100 bytes instead of 692 + + let transition = create_shielded_transfer_transition( + vec![bad_action], + 0x03, + 0, + anchor, + vec![0u8; 100], + vec![0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs index 7ddb9439949..acc700f31fa 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs @@ -28,9 +28,7 @@ pub(in crate::execution::validation::state_transition::state_transitions::shield ) -> Result, Error>; } -impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 - for ShieldedTransferTransition -{ +impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 for ShieldedTransferTransition { fn transform_into_action_v0( &self, drive: &Drive, @@ -39,17 +37,17 @@ impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 ) -> Result, Error> { // Extract nullifiers, note commitments, and encrypted notes from serialized actions let nullifiers: Vec<[u8; 32]> = match self { - ShieldedTransferTransition::V0(v0) => { - v0.actions.iter().map(|a| a.nullifier).collect() - } + ShieldedTransferTransition::V0(v0) => v0.actions.iter().map(|a| a.nullifier).collect(), }; let note_commitments: Vec<[u8; 32]> = match self { ShieldedTransferTransition::V0(v0) => v0.actions.iter().map(|a| a.cmx).collect(), }; let encrypted_notes: Vec> = match self { - ShieldedTransferTransition::V0(v0) => { - v0.actions.iter().map(|a| a.encrypted_note.clone()).collect() - } + ShieldedTransferTransition::V0(v0) => v0 + .actions + .iter() + .map(|a| a.encrypted_note.clone()) + .collect(), }; // The anchor from the transition (Merkle root of commitment tree) @@ -75,14 +73,13 @@ impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 &platform_version.drive, )?; let (params, _): (ShieldedPoolParams, _) = - bincode::decode_from_slice(¶ms_bytes, bincode::config::standard()) - .map_err(|e| { - Error::Protocol( - dpp::ProtocolError::DecodingError(format!( - "could not decode shielded pool params: {e}" - )), - ) - })?; + bincode::decode_from_slice(¶ms_bytes, bincode::config::standard()).map_err( + |e| { + Error::Protocol(dpp::ProtocolError::DecodingError(format!( + "could not decode shielded pool params: {e}" + ))) + }, + )?; let current_checkpoint_id = params.checkpoint_id_counter; let current_total_balance = drive @@ -127,9 +124,9 @@ impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 if exists { return Ok(ConsensusValidationResult::new_with_error( - StateError::NullifierAlreadySpentError( - NullifierAlreadySpentError::new(*nullifier), - ) + StateError::NullifierAlreadySpentError(NullifierAlreadySpentError::new( + *nullifier, + )) .into(), )); } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs new file mode 100644 index 00000000000..53bb8a8343a --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs @@ -0,0 +1,581 @@ +#[cfg(test)] +mod tests { + use crate::config::{PlatformConfig, PlatformTestConfig}; + use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; + use crate::test::helpers::setup::TestPlatformBuilder; + use assert_matches::assert_matches; + use dpp::address_funds::PlatformAddress; + use dpp::block::block_info::BlockInfo; + use dpp::consensus::basic::BasicError; + use dpp::consensus::state::state_error::StateError; + use dpp::consensus::ConsensusError; + use dpp::serialization::PlatformSerializable; + use dpp::shielded::SerializedAction; + use dpp::state_transition::unshield_transition::v0::UnshieldTransitionV0; + use dpp::state_transition::unshield_transition::UnshieldTransition; + use dpp::state_transition::StateTransition; + use drive::drive::shielded::paths::{ + shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, + }; + use drive::grovedb::Element; + use platform_version::version::PlatformVersion; + + // ========================================== + // Helper Functions + // ========================================== + + /// Create a `SerializedAction` with syntactically valid sizes but meaningless crypto data. + /// Passes structure validation (correct field sizes) but will fail ZK proof verification. + fn create_dummy_serialized_action() -> SerializedAction { + SerializedAction { + nullifier: [1u8; 32], + rk: [2u8; 32], + cmx: [3u8; 32], + encrypted_note: vec![4u8; 692], // epk(32) + enc(580) + out(80) + cv_net: [5u8; 32], + spend_auth_sig: vec![6u8; 64], + } + } + + /// Create a dummy PlatformAddress for the output. + fn create_output_address() -> PlatformAddress { + let mut hash = [0u8; 20]; + hash[0] = 42; + hash[19] = 42; + PlatformAddress::P2pkh(hash) + } + + /// Builds an `UnshieldTransition` state transition. + /// No signing needed since unshield transitions have no witnesses. + fn create_unshield_transition( + output_address: PlatformAddress, + amount: u64, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: Vec, + user_fee_increase: u16, + ) -> StateTransition { + StateTransition::Unshield(UnshieldTransition::V0(UnshieldTransitionV0 { + output_address, + amount, + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + user_fee_increase, + })) + } + + /// Shorthand for creating a structurally valid (but cryptographically invalid) unshield + /// transition. Has a non-zero anchor, valid field sizes, positive amount and value_balance. + fn create_default_unshield_transition() -> StateTransition { + create_unshield_transition( + create_output_address(), + 1000, // amount being unshielded + vec![create_dummy_serialized_action()], + 0x03, // spends_enabled | outputs_enabled + 1000, // value_balance = amount (no fee for simplicity) + [42u8; 32], // non-zero anchor + vec![0u8; 100], // dummy proof bytes + vec![0u8; 64], // dummy binding signature + 0, + ) + } + + /// Insert a fake anchor into the shielded anchors tree via GroveDB. + fn insert_anchor_into_state( + platform: &crate::test::helpers::setup::TempPlatform, + anchor: &[u8; 32], + ) { + let platform_version = PlatformVersion::latest(); + let grove_version = &platform_version.drive.grove_version; + let transaction = platform.drive.grove.start_transaction(); + let anchors_path = shielded_anchors_credit_pool_path(); + + platform + .drive + .grove + .insert( + &anchors_path, + anchor, + Element::Item(vec![], None), + None, + Some(&transaction), + grove_version, + ) + .unwrap() + .expect("should insert anchor"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("should commit transaction"); + } + + /// Insert a nullifier into the nullifiers tree via GroveDB. + fn insert_nullifier_into_state( + platform: &crate::test::helpers::setup::TempPlatform, + nullifier: &[u8; 32], + ) { + let platform_version = PlatformVersion::latest(); + let grove_version = &platform_version.drive.grove_version; + let transaction = platform.drive.grove.start_transaction(); + let nullifiers_path = shielded_credit_pool_nullifiers_path(); + + platform + .drive + .grove + .insert( + &nullifiers_path, + nullifier, + Element::Item(vec![], None), + None, + Some(&transaction), + grove_version, + ) + .unwrap() + .expect("should insert nullifier"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("should commit transaction"); + } + + /// Standard platform setup for tests. + fn setup_platform( + ) -> crate::test::helpers::setup::TempPlatform { + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + TestPlatformBuilder::new() + .with_config(platform_config) + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state() + } + + /// Execute a state transition through the full processing pipeline and return the result. + fn process_transition( + platform: &crate::test::helpers::setup::TempPlatform, + transition: StateTransition, + platform_version: &PlatformVersion, + ) -> crate::platform_types::state_transitions_processing_result::StateTransitionsProcessingResult + { + let transition_bytes = transition + .serialize_to_bytes() + .expect("should serialize transition"); + let platform_state = platform.state.load(); + let transaction = platform.drive.grove.start_transaction(); + + platform + .platform + .process_raw_state_transitions( + &vec![transition_bytes], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition") + } + + // ========================================== + // STRUCTURE VALIDATION TESTS (BasicError) + // ========================================== + + mod structure_validation { + use super::*; + + #[test] + fn test_empty_actions_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_unshield_transition( + create_output_address(), + 1000, + vec![], // Empty actions — invalid + 0x03, + 1000, + [42u8; 32], + vec![0u8; 100], + vec![0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_zero_amount_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_unshield_transition( + create_output_address(), + 0, // Zero amount — invalid + vec![create_dummy_serialized_action()], + 0x03, + 1000, + [42u8; 32], + vec![0u8; 100], + vec![0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_non_positive_value_balance_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_unshield_transition( + create_output_address(), + 1000, + vec![create_dummy_serialized_action()], + 0x03, + 0, // Zero value_balance — invalid (must be positive) + [42u8; 32], + vec![0u8; 100], + vec![0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_negative_value_balance_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_unshield_transition( + create_output_address(), + 1000, + vec![create_dummy_serialized_action()], + 0x03, + -1000, // Negative value_balance — invalid + [42u8; 32], + vec![0u8; 100], + vec![0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_value_balance_less_than_amount_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_unshield_transition( + create_output_address(), + 2000, // amount = 2000 + vec![create_dummy_serialized_action()], + 0x03, + 1000, // value_balance = 1000 < amount — invalid + [42u8; 32], + vec![0u8; 100], + vec![0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_empty_proof_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_unshield_transition( + create_output_address(), + 1000, + vec![create_dummy_serialized_action()], + 0x03, + 1000, + [42u8; 32], + vec![], // Empty proof — invalid + vec![0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_wrong_binding_sig_length_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_unshield_transition( + create_output_address(), + 1000, + vec![create_dummy_serialized_action()], + 0x03, + 1000, + [42u8; 32], + vec![0u8; 100], + vec![0u8; 32], // 32 bytes instead of 64 — invalid + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_wrong_spend_auth_sig_length_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let mut bad_action = create_dummy_serialized_action(); + bad_action.spend_auth_sig = vec![0u8; 32]; // 32 bytes instead of 64 + + let transition = create_unshield_transition( + create_output_address(), + 1000, + vec![bad_action], + 0x03, + 1000, + [42u8; 32], + vec![0u8; 100], + vec![0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + + #[test] + fn test_zero_anchor_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_unshield_transition( + create_output_address(), + 1000, + vec![create_dummy_serialized_action()], + 0x03, + 1000, + [0u8; 32], // All zeros — invalid + vec![0u8; 100], + vec![0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::OverflowError(_)) + )] + ); + } + } + + // ========================================== + // ANCHOR VALIDATION TESTS (StateError) + // ========================================== + + mod anchor_validation { + use super::*; + + #[test] + fn test_invalid_anchor_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + // Non-zero anchor that doesn't exist in state + let transition = create_default_unshield_transition(); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidAnchorError(_)) + )] + ); + } + } + + // ========================================== + // NULLIFIER DOUBLE-SPEND TESTS (StateError) + // ========================================== + + mod nullifier_validation { + use super::*; + + #[test] + fn test_nullifier_already_spent_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let anchor = [42u8; 32]; + let nullifier = [1u8; 32]; // Same as create_dummy_serialized_action().nullifier + + // Insert the anchor so anchor validation passes + insert_anchor_into_state(&platform, &anchor); + + // Insert the nullifier so it appears already spent + insert_nullifier_into_state(&platform, &nullifier); + + let transition = create_default_unshield_transition(); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::NullifierAlreadySpentError(_)) + )] + ); + } + } + + // ========================================== + // ZK PROOF VERIFICATION TESTS (InvalidShieldedProofError) + // ========================================== + + mod proof_verification { + use super::*; + + #[test] + fn test_invalid_proof_returns_shielded_proof_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let anchor = [42u8; 32]; + + // Insert the anchor so anchor validation passes + insert_anchor_into_state(&platform, &anchor); + + // This transition is structurally valid and has a valid anchor, + // but has random ZK proof data. It should pass structure validation + // and anchor validation but fail at proof verification. + let transition = create_default_unshield_transition(); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + + #[test] + fn test_wrong_encrypted_note_size_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let anchor = [42u8; 32]; + + // Insert the anchor so anchor validation passes + insert_anchor_into_state(&platform, &anchor); + + // Create action with wrong encrypted_note size + let mut bad_action = create_dummy_serialized_action(); + bad_action.encrypted_note = vec![0u8; 100]; // 100 bytes instead of 692 + + let transition = create_unshield_transition( + create_output_address(), + 1000, + vec![bad_action], + 0x03, + 1000, + anchor, + vec![0u8; 100], + vec![0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs index cc84ed59ad7..de31ca3db0d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs @@ -42,9 +42,11 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti UnshieldTransition::V0(v0) => v0.actions.iter().map(|a| a.cmx).collect(), }; let encrypted_notes: Vec> = match self { - UnshieldTransition::V0(v0) => { - v0.actions.iter().map(|a| a.encrypted_note.clone()).collect() - } + UnshieldTransition::V0(v0) => v0 + .actions + .iter() + .map(|a| a.encrypted_note.clone()) + .collect(), }; // The anchor from the transition (Merkle root of commitment tree) @@ -65,14 +67,13 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti &platform_version.drive, )?; let (params, _): (ShieldedPoolParams, _) = - bincode::decode_from_slice(¶ms_bytes, bincode::config::standard()) - .map_err(|e| { - Error::Protocol( - dpp::ProtocolError::DecodingError(format!( - "could not decode shielded pool params: {e}" - )), - ) - })?; + bincode::decode_from_slice(¶ms_bytes, bincode::config::standard()).map_err( + |e| { + Error::Protocol(dpp::ProtocolError::DecodingError(format!( + "could not decode shielded pool params: {e}" + ))) + }, + )?; let current_checkpoint_id = params.checkpoint_id_counter; let current_total_balance = drive @@ -117,9 +118,9 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti if exists { return Ok(ConsensusValidationResult::new_with_error( - StateError::NullifierAlreadySpentError( - NullifierAlreadySpentError::new(*nullifier), - ) + StateError::NullifierAlreadySpentError(NullifierAlreadySpentError::new( + *nullifier, + )) .into(), )); } diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs index 2fa45f0869d..4e35523544b 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs @@ -1,15 +1,15 @@ use crate::drive::shielded::paths::{ shielded_credit_pool_commitments_path_vec, shielded_credit_pool_encrypted_notes_path_vec, - shielded_credit_pool_nullifiers_path_vec, shielded_credit_pool_path_vec, - SHIELDED_PARAMS_KEY, SHIELDED_TOTAL_BALANCE_KEY, + shielded_credit_pool_nullifiers_path_vec, shielded_credit_pool_path_vec, SHIELDED_PARAMS_KEY, + SHIELDED_TOTAL_BALANCE_KEY, }; use crate::error::Error; use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; use crate::state_transition_action::shielded::shield::ShieldTransitionAction; use crate::state_transition_action::shielded::shielded_transfer::ShieldedTransferTransitionAction; use crate::state_transition_action::shielded::unshield::UnshieldTransitionAction; -use crate::util::batch::drive_op_batch::AddressFundsOperationType; use crate::util::batch::drive_op_batch::finalize_task::DriveOperationFinalizeTask; +use crate::util::batch::drive_op_batch::AddressFundsOperationType; use crate::util::batch::DriveOperation; use dpp::block::epoch::Epoch; use dpp::shielded::ShieldedPoolParams; diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs b/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs index 81db640f2ee..9d5b87c13f7 100644 --- a/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs +++ b/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs @@ -9,7 +9,9 @@ use grovedb::{Element, TransactionArg}; #[derive(Clone, Debug)] pub enum DriveOperationFinalizeTask { - RemoveDataContractFromCache { contract_id: Identifier }, + RemoveDataContractFromCache { + contract_id: Identifier, + }, /// Record the current commitment tree root hash as a new anchor RecordShieldedAnchor, } From cf9fafaf04a6b877699556285525ad393b88c4c7 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 10 Feb 2026 12:03:02 +0000 Subject: [PATCH 06/40] more work --- Cargo.lock | 11 - packages/rs-drive-abci/Cargo.toml | 2 +- .../execution/types/execution_event/mod.rs | 38 ++ .../state_transitions/shield/tests.rs | 308 +++++++++++++ .../shield/transform_into_action/v0/mod.rs | 52 ++- .../state_transitions/shielded_common/mod.rs | 45 +- .../shielded_transfer/tests.rs | 435 ++++++++++++++++++ .../transform_into_action/v0/mod.rs | 22 +- .../state_transitions/unshield/tests.rs | 410 +++++++++++++++++ .../unshield/transform_into_action/v0/mod.rs | 22 +- packages/rs-drive/Cargo.toml | 12 +- .../src/drive/shielded/estimated_costs.rs | 117 +++++ packages/rs-drive/src/drive/shielded/mod.rs | 4 + .../shielded/mod.rs | 133 ++---- .../shielded/shield/transformer.rs | 2 - .../shielded/shield/v0/mod.rs | 2 - .../shielded/shield/v0/transformer.rs | 2 - .../shielded/shielded_transfer/transformer.rs | 2 - .../shielded/shielded_transfer/v0/mod.rs | 2 - .../shielded_transfer/v0/transformer.rs | 2 - .../shielded/unshield/transformer.rs | 2 - .../shielded/unshield/v0/mod.rs | 2 - .../shielded/unshield/v0/transformer.rs | 2 - .../batch/drive_op_batch/finalize_task.rs | 81 +++- .../src/util/batch/drive_op_batch/mod.rs | 8 + packages/rs-platform-version/Cargo.toml | 2 +- scripts/grovedb_version_switcher.py | 12 +- 27 files changed, 1521 insertions(+), 211 deletions(-) create mode 100644 packages/rs-drive/src/drive/shielded/estimated_costs.rs diff --git a/Cargo.lock b/Cargo.lock index c04f2faff3c..78a75ae0925 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2585,7 +2585,6 @@ dependencies = [ [[package]] name = "grovedb" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "axum 0.8.8", "bincode", @@ -2619,7 +2618,6 @@ dependencies = [ [[package]] name = "grovedb-commitment-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "incrementalmerkletree", "orchard", @@ -2631,7 +2629,6 @@ dependencies = [ [[package]] name = "grovedb-costs" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "integer-encoding", "intmap", @@ -2641,7 +2638,6 @@ dependencies = [ [[package]] name = "grovedb-element" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "bincode", "bincode_derive", @@ -2656,7 +2652,6 @@ dependencies = [ [[package]] name = "grovedb-epoch-based-storage-flags" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "grovedb-costs", "hex", @@ -2668,7 +2663,6 @@ dependencies = [ [[package]] name = "grovedb-merk" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "bincode", "bincode_derive", @@ -2693,7 +2687,6 @@ dependencies = [ [[package]] name = "grovedb-path" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "hex", ] @@ -2701,7 +2694,6 @@ dependencies = [ [[package]] name = "grovedb-storage" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "blake3", "grovedb-costs", @@ -2720,7 +2712,6 @@ dependencies = [ [[package]] name = "grovedb-version" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "thiserror 2.0.17", "versioned-feature-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2729,7 +2720,6 @@ dependencies = [ [[package]] name = "grovedb-visualize" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "hex", "itertools 0.14.0", @@ -2738,7 +2728,6 @@ dependencies = [ [[package]] name = "grovedbg-types" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=219ba2e73f08a9f428c9427f7ab5c73907d670bf#219ba2e73f08a9f428c9427f7ab5c73907d670bf" dependencies = [ "serde", "serde_with 3.16.1", diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index 228de1fb5dd..ae08247b314 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -82,7 +82,7 @@ derive_more = { version = "1.0", features = ["from", "deref", "deref_mut"] } async-trait = "0.1.77" console-subscriber = { version = "0.4", optional = true } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f", optional = true } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "219ba2e73f08a9f428c9427f7ab5c73907d670bf" } +grovedb-commitment-tree = { path = "../../../grovedb/grovedb-commitment-tree" } orchard = "0.12" nonempty = "0.11" diff --git a/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs b/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs index f6126ccc10e..f30af0628f0 100644 --- a/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs +++ b/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs @@ -19,6 +19,9 @@ use crate::execution::types::state_transition_execution_context::{ StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0, }; use drive::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; +use drive::state_transition_action::shielded::shield::ShieldTransitionAction; +use drive::state_transition_action::shielded::shielded_transfer::ShieldedTransferTransitionAction; +use drive::state_transition_action::shielded::unshield::UnshieldTransitionAction; use drive::state_transition_action::system::bump_address_input_nonces_action::BumpAddressInputNonceActionAccessorsV0; use drive::state_transition_action::system::partially_use_asset_lock_action::PartiallyUseAssetLockActionAccessorsV0; use drive::util::batch::DriveOperation; @@ -442,6 +445,41 @@ impl ExecutionEvent<'_> { ))) } } + StateTransitionAction::ShieldAction(shield_action) => { + let user_fee_increase = shield_action.user_fee_increase(); + let input_current_balances = + shield_action.inputs_with_remaining_balance().clone(); + let added_to_balance_outputs = BTreeMap::new(); + let fee_strategy = shield_action.fee_strategy().clone(); + let operations = + action.into_high_level_drive_operations(epoch, platform_version)?; + Ok(ExecutionEvent::PaidFromAddressInputs { + input_current_balances, + added_to_balance_outputs, + fee_strategy, + operations, + execution_operations: execution_context.operations_consume(), + additional_fixed_fee_cost: None, + user_fee_increase, + }) + } + StateTransitionAction::ShieldedTransferAction(shielded_transfer_action) => { + let fee_amount = shielded_transfer_action.fee_amount(); + let operations = + action.into_high_level_drive_operations(epoch, platform_version)?; + Ok(ExecutionEvent::PaidFixedCost { + operations, + fees_to_add_to_pool: fee_amount, + }) + } + StateTransitionAction::UnshieldAction(_unshield_action) => { + let operations = + action.into_high_level_drive_operations(epoch, platform_version)?; + Ok(ExecutionEvent::PaidFixedCost { + operations, + fees_to_add_to_pool: 0, + }) + } _ => { let user_fee_increase = action.user_fee_increase(); let operations = diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs index 245d15f25e7..60dce515a4a 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs @@ -25,8 +25,14 @@ mod tests { use dpp::state_transition::shield_transition::v0::ShieldTransitionV0; use dpp::state_transition::shield_transition::ShieldTransition; use dpp::state_transition::StateTransition; + use grovedb_commitment_tree::{ + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + Flags as OrchardFlags, FullViewingKey, NoteValue, ProvingKey, Scope, SpendingKey, + }; use platform_version::version::PlatformVersion; + use rand::rngs::OsRng; use std::collections::BTreeMap; + use std::sync::OnceLock; // ========================================== // Helper Functions @@ -188,6 +194,51 @@ mod tests { .expect("expected to process state transition") } + // ========================================== + // Orchard Proving Key (cached, ~30s to build) + // ========================================== + + static TEST_PROVING_KEY: OnceLock = OnceLock::new(); + fn get_proving_key() -> &'static ProvingKey { + TEST_PROVING_KEY.get_or_init(ProvingKey::build) + } + + /// Extract serialized fields from an authorized Orchard bundle into the + /// platform-compatible format: (actions, flags, value_balance, anchor, proof, binding_sig). + fn serialize_authorized_bundle( + bundle: &Bundle, + ) -> (Vec, u8, i64, [u8; 32], Vec, Vec) { + let actions: Vec = bundle + .actions() + .iter() + .map(|action| { + let enc = action.encrypted_note(); + let mut encrypted_note = Vec::with_capacity(692); + encrypted_note.extend_from_slice(&enc.epk_bytes); + encrypted_note.extend_from_slice(&enc.enc_ciphertext); + encrypted_note.extend_from_slice(&enc.out_ciphertext); + + SerializedAction { + nullifier: action.nullifier().to_bytes(), + rk: <[u8; 32]>::from(action.rk()), + cmx: action.cmx().to_bytes(), + encrypted_note, + cv_net: action.cv_net().to_bytes(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()).to_vec(), + } + }) + .collect(); + + let flags = bundle.flags().to_byte(); + let value_balance = *bundle.value_balance(); + let anchor = bundle.anchor().to_bytes(); + let proof = bundle.authorization().proof().as_ref().to_vec(); + let binding_sig = + <[u8; 64]>::from(bundle.authorization().binding_signature()).to_vec(); + + (actions, flags, value_balance, anchor, proof, binding_sig) + } + // ========================================== // STRUCTURE VALIDATION TESTS (BasicError) // ========================================== @@ -855,6 +906,110 @@ mod tests { ); } + #[test] + fn test_valid_shield_proof_succeeds() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + // --- Set up input address with enough balance --- + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + setup_address_with_balance( + &mut platform, + input_address, + 0, + dash_to_credits!(1.0), + ); + + // --- Build valid Orchard bundle (shield = outputs only) --- + let mut rng = OsRng; + let pk = get_proving_key(); + + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + + let anchor = Anchor::empty_tree(); + let mut builder = Builder::new( + BundleType::Transactional { + flags: OrchardFlags::SPENDS_DISABLED, + bundle_required: false, + }, + anchor, + ); + + let shield_value = 5000u64; + builder + .add_output( + None, + recipient, + NoteValue::from_raw(shield_value), + [0u8; 512], + ) + .unwrap(); + + let (unauthorized, _) = + builder.build::(&mut rng).unwrap().unwrap(); + let sighash = unauthorized.commitment().into(); + let proven = unauthorized + .create_proof(pk, &mut rng) + .unwrap(); + let bundle = proven + .apply_signatures(rng, sighash, &[]) + .unwrap(); + + // --- Extract serialized fields from the authorized bundle --- + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + + // value_balance should be negative for shield (money going into pool) + assert!(value_balance < 0); + let shield_amount = (-value_balance) as u64; + + // --- Build and sign the shield transition --- + let mut inputs = BTreeMap::new(); + inputs.insert( + input_address, + (1 as AddressNonce, shield_amount + dash_to_credits!(0.01)), + ); + + let mut st = StateTransition::Shield(ShieldTransition::V0(ShieldTransitionV0 { + inputs: inputs.clone(), + actions, + flags, + value_balance, + anchor: anchor_bytes, + proof: proof_bytes, + binding_signature: binding_sig, + fee_strategy: AddressFundsFeeStrategy::from(vec![ + AddressFundsFeeStrategyStep::DeductFromInput(0), + ]), + user_fee_increase: 0, + input_witnesses: vec![], + })); + + let signable_bytes = st.signable_bytes().expect("should compute signable bytes"); + let witnesses: Vec = inputs + .keys() + .map(|address| { + signer + .sign_create_witness(address, &signable_bytes) + .expect("should sign") + }) + .collect(); + + if let StateTransition::Shield(ShieldTransition::V0(ref mut v0)) = st { + v0.input_witnesses = witnesses; + } + + let processing_result = process_transition(&platform, st, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution { .. }] + ); + } + #[test] fn test_wrong_encrypted_note_size_returns_error() { let platform_version = PlatformVersion::latest(); @@ -897,4 +1052,157 @@ mod tests { ); } } + + // ========================================== + // SECURITY AUDIT TESTS + // ========================================== + + mod security_audit { + use super::*; + + /// AUDIT FIX VERIFICATION: `value_balance = i64::MIN` no longer panics. + /// + /// Previously, `(-v0.value_balance) as u64` with i64::MIN caused an + /// overflow panic. Now uses `checked_neg()` which returns a consensus + /// error instead. + #[test] + fn test_value_balance_i64_min_returns_consensus_error() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); + + let mut inputs = BTreeMap::new(); + inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); + + let transition = create_signed_shield_transition( + &signer, + inputs, + vec![create_dummy_serialized_action()], + 0x03, + i64::MIN, // -9223372036854775808 — would overflow on negation + vec![0u8; 100], + vec![0u8; 64], + AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( + 0, + )]), + ); + + // Should return a consensus error, not panic + let processing_result = process_transition(&platform, transition, platform_version); + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + + /// AUDIT FIX VERIFICATION: Mutated value_balance is now rejected. + /// + /// Previously, the binding signature was not verified so mutating + /// value_balance from -5000 to -100000 was accepted. Now with + /// BatchValidator, the changed value_balance produces a different + /// bundle commitment (sighash), causing signature verification to fail. + #[test] + fn test_valid_proof_with_mutated_value_balance_is_rejected() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + setup_address_with_balance( + &mut platform, + input_address, + 0, + dash_to_credits!(1.0), + ); + + let mut rng = OsRng; + let pk = get_proving_key(); + + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + + let anchor = Anchor::empty_tree(); + let mut builder = Builder::new( + BundleType::Transactional { + flags: OrchardFlags::SPENDS_DISABLED, + bundle_required: false, + }, + anchor, + ); + + builder + .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 512]) + .unwrap(); + + let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); + let sighash = unauthorized.commitment().into(); + let proven = unauthorized.create_proof(pk, &mut rng).unwrap(); + let bundle = proven.apply_signatures(rng, sighash, &[]).unwrap(); + + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + + assert!(value_balance < 0); + let honest_shield_amount = (-value_balance) as u64; + assert_eq!(honest_shield_amount, 5_000); + + // ATTACK: Mutate value_balance to claim shielding 100,000 instead of 5,000 + let mutated_value_balance = -100_000i64; + + // Input only provides enough for a small amount, but shield_amount + // comes from value_balance, not from inputs + let mut inputs = BTreeMap::new(); + inputs.insert( + input_address, + (1 as AddressNonce, honest_shield_amount + dash_to_credits!(0.01)), + ); + + let mut st = StateTransition::Shield(ShieldTransition::V0(ShieldTransitionV0 { + inputs: inputs.clone(), + actions, + flags, + value_balance: mutated_value_balance, // MUTATED + anchor: anchor_bytes, // Must match the proof's anchor (circuit instance) + proof: proof_bytes, + binding_signature: binding_sig, + fee_strategy: AddressFundsFeeStrategy::from(vec![ + AddressFundsFeeStrategyStep::DeductFromInput(0), + ]), + user_fee_increase: 0, + input_witnesses: vec![], + })); + + let signable_bytes = st.signable_bytes().expect("should compute signable bytes"); + let witnesses: Vec = inputs + .keys() + .map(|address| { + signer + .sign_create_witness(address, &signable_bytes) + .expect("should sign") + }) + .collect(); + + if let StateTransition::Shield(ShieldTransition::V0(ref mut v0)) = st { + v0.input_witnesses = witnesses; + } + + let processing_result = process_transition(&platform, st, platform_version); + + // FIXED: BatchValidator now verifies binding signature and spend auth sigs. + // Mutated value_balance changes the sighash, causing signature verification to fail. + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::PaidConsensusError { + error: ConsensusError::StateError(StateError::InvalidShieldedProofError(_)), + .. + }] + ); + } + } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs index 5dddfbf2c76..fa2837b3e68 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs @@ -1,14 +1,14 @@ use crate::error::Error; use crate::execution::validation::state_transition::state_transitions::shielded_common::reconstruct_and_verify_bundle; use dpp::address_funds::PlatformAddress; +use dpp::consensus::state::shielded::invalid_shielded_proof_error::InvalidShieldedProofError; use dpp::consensus::state::state_error::StateError; use dpp::fee::Credits; use dpp::prelude::{AddressNonce, ConsensusValidationResult}; -use dpp::shielded::ShieldedPoolParams; use dpp::state_transition::shield_transition::ShieldTransition; use dpp::version::PlatformVersion; use drive::drive::shielded::paths::{ - shielded_credit_pool_path, SHIELDED_PARAMS_KEY, SHIELDED_TOTAL_BALANCE_KEY, + shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY, }; use drive::drive::Drive; use drive::grovedb::TransactionArg; @@ -49,33 +49,38 @@ impl ShieldStateTransitionTransformIntoActionValidationV0 for ShieldTransition { .collect(), }; - // The value_balance is negative for shield (funds flowing into the pool) - let shield_amount = match self { - ShieldTransition::V0(v0) => (-v0.value_balance) as u64, + // The value_balance must be negative for shield (funds flowing into the pool). + // Safely negate to get the shield amount, guarding against overflow (i64::MIN). + let shield_amount: Credits = match self { + ShieldTransition::V0(v0) => { + if v0.value_balance >= 0 { + return Ok(ConsensusValidationResult::new_with_error( + StateError::InvalidShieldedProofError(InvalidShieldedProofError::new( + "shield value_balance must be negative".to_string(), + )) + .into(), + )); + } + match v0.value_balance.checked_neg() { + Some(positive) => positive as u64, + None => { + return Ok(ConsensusValidationResult::new_with_error( + StateError::InvalidShieldedProofError( + InvalidShieldedProofError::new( + "shield value_balance overflow (i64::MIN)".to_string(), + ), + ) + .into(), + )); + } + } + } }; // Read current shielded pool state from GroveDB let mut drive_operations = vec![]; let pool_path = shielded_credit_pool_path(); - let params_bytes = drive.grove_get_raw_item( - (&pool_path).into(), - &[SHIELDED_PARAMS_KEY], - DirectQueryType::StatefulDirectQuery, - transaction, - &mut drive_operations, - &platform_version.drive, - )?; - let (params, _): (ShieldedPoolParams, _) = - bincode::decode_from_slice(¶ms_bytes, bincode::config::standard()).map_err( - |e| { - Error::Protocol(dpp::ProtocolError::DecodingError(format!( - "could not decode shielded pool params: {e}" - ))) - }, - )?; - let current_checkpoint_id = params.checkpoint_id_counter; - let current_total_balance = drive .grove_get_raw_value_u64_from_encoded_var_vec( (&pool_path).into(), @@ -138,7 +143,6 @@ impl ShieldStateTransitionTransformIntoActionValidationV0 for ShieldTransition { shield_amount, note_commitments, encrypted_notes, - current_checkpoint_id, current_total_balance, ); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs index 268f420f943..d95685d4c92 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs @@ -1,8 +1,8 @@ use dpp::consensus::state::shielded::invalid_shielded_proof_error::InvalidShieldedProofError; use dpp::shielded::SerializedAction; use grovedb_commitment_tree::{ - Action, Anchor, Authorized, Bundle, ExtractedNoteCommitment, Flags, Nullifier, Proof, - VerifyingKey, + Action, Anchor, Authorized, BatchValidator, Bundle, ExtractedNoteCommitment, Flags, Nullifier, + Proof, VerifyingKey, }; use orchard::note::TransmittedNoteCiphertext; use orchard::primitives::redpallas; @@ -25,10 +25,20 @@ const OUT_CIPHERTEXT_SIZE: usize = 80; const ENCRYPTED_NOTE_SIZE: usize = EPK_SIZE + ENC_CIPHERTEXT_SIZE + OUT_CIPHERTEXT_SIZE; // 692 /// Reconstructs an orchard `Bundle` from the serialized fields -/// of a shielded state transition and verifies the Halo 2 ZK proof. +/// of a shielded state transition and verifies the Halo 2 ZK proof along with +/// all RedPallas signatures (spend auth + binding). /// -/// Returns `Ok(())` if the proof is valid, or an `InvalidShieldedProofError` -/// wrapped in `Error` if reconstruction or verification fails. +/// Uses `BatchValidator` which verifies: +/// 1. The Halo 2 circuit proof (zero-knowledge proof of spend validity) +/// 2. Spend authorization signatures (proves the spender controls the spending key) +/// 3. The binding signature (binds value_balance to value commitments, preventing manipulation) +/// +/// The sighash used for signature verification is derived from `bundle.commitment()`, +/// which is the Orchard bundle commitment (BLAKE2b-256 hash of the bundle's non-authorization +/// data per ZIP-244). This same value must be used when signing the bundle on the client side. +/// +/// Returns `Ok(())` if all verification passes, or an `InvalidShieldedProofError` +/// if reconstruction or any verification step fails. pub fn reconstruct_and_verify_bundle( actions: &[SerializedAction], flags: u8, @@ -131,10 +141,27 @@ pub fn reconstruct_and_verify_bundle( authorized, ); - // Verify the Halo 2 proof - bundle - .verify_proof(vk) - .map_err(|e| InvalidShieldedProofError::new(format!("proof verification failed: {e}")))?; + // Compute the sighash from the bundle's non-authorization data. + // This uses the Orchard BundleCommitment (BLAKE2b-256 per ZIP-244), + // covering: flags, value_balance, anchor, and all action fields + // (nullifier, rk, cmx, cv_net, encrypted_note) — but NOT the signatures or proof. + let sighash: [u8; 32] = bundle.commitment().into(); + + // Verify the Halo 2 proof AND all RedPallas signatures (spend auth + binding) + // using BatchValidator. This is the correct Orchard verification flow, ensuring: + // - The ZK circuit proof is valid + // - Each spend auth signature is valid for (rk, sighash) + // - The binding signature is valid for (binding_validating_key, sighash) + let mut batch = BatchValidator::new(); + batch.add_bundle(&bundle, sighash); + + let mut rng = rand::rngs::OsRng; + if !batch.validate(vk, &mut rng) { + return Err(InvalidShieldedProofError::new( + "bundle verification failed: proof, spend auth signatures, or binding signature invalid" + .to_string(), + )); + } Ok(()) } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs index 0f35a6f9e74..ce131e911e8 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs @@ -15,6 +15,7 @@ mod tests { use dpp::state_transition::StateTransition; use drive::drive::shielded::paths::{ shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, + shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY, }; use drive::grovedb::Element; use platform_version::version::PlatformVersion; @@ -138,6 +139,38 @@ mod tests { .expect("should commit transaction"); } + /// Set the shielded pool total balance in GroveDB. + fn set_pool_total_balance( + platform: &crate::test::helpers::setup::TempPlatform, + balance: u64, + ) { + let platform_version = PlatformVersion::latest(); + let grove_version = &platform_version.drive.grove_version; + let transaction = platform.drive.grove.start_transaction(); + let pool_path = shielded_credit_pool_path(); + + platform + .drive + .grove + .insert( + &pool_path, + &[SHIELDED_TOTAL_BALANCE_KEY], + Element::new_sum_item(balance as i64), + None, + Some(&transaction), + grove_version, + ) + .unwrap() + .expect("should set total balance"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("should commit transaction"); + } + /// Standard platform setup for tests. fn setup_platform( ) -> crate::test::helpers::setup::TempPlatform { @@ -410,6 +443,51 @@ mod tests { mod proof_verification { use super::*; + use grovedb_commitment_tree::{ + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + CommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, + NoteValue, Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, + SpendingKey, new_memory_store, + }; + use orchard::note::RandomSeed; + use rand::rngs::OsRng; + use std::sync::OnceLock; + + static TEST_PROVING_KEY: OnceLock = OnceLock::new(); + fn get_proving_key() -> &'static ProvingKey { + TEST_PROVING_KEY.get_or_init(ProvingKey::build) + } + + fn serialize_authorized_bundle( + bundle: &Bundle, + ) -> (Vec, u8, i64, [u8; 32], Vec, Vec) { + let actions: Vec = bundle + .actions() + .iter() + .map(|action| { + let enc = action.encrypted_note(); + let mut encrypted_note = Vec::with_capacity(692); + encrypted_note.extend_from_slice(&enc.epk_bytes); + encrypted_note.extend_from_slice(&enc.enc_ciphertext); + encrypted_note.extend_from_slice(&enc.out_ciphertext); + SerializedAction { + nullifier: action.nullifier().to_bytes(), + rk: <[u8; 32]>::from(action.rk()), + cmx: action.cmx().to_bytes(), + encrypted_note, + cv_net: action.cv_net().to_bytes(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()).to_vec(), + } + }) + .collect(); + let flags = bundle.flags().to_byte(); + let value_balance = *bundle.value_balance(); + let anchor = bundle.anchor().to_bytes(); + let proof = bundle.authorization().proof().as_ref().to_vec(); + let binding_sig = + <[u8; 64]>::from(bundle.authorization().binding_signature()).to_vec(); + (actions, flags, value_balance, anchor, proof, binding_sig) + } #[test] fn test_invalid_proof_returns_shielded_proof_error() { @@ -436,6 +514,84 @@ mod tests { ); } + #[test] + fn test_valid_shielded_transfer_proof_succeeds() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + let mut rng = OsRng; + let pk = get_proving_key(); + + // --- Create keys --- + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + let ask = SpendAuthorizingKey::from(&sk); + + // --- Create a spendable note --- + let rho_bytes: [u8; 32] = { + let mut b = [0u8; 32]; + b[0] = 1; // Non-zero valid Pallas field element + b + }; + let rho = Rho::from_bytes(&rho_bytes).unwrap(); + let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); + let note = Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed) + .unwrap(); + + // --- Build commitment tree and get anchor + merkle path --- + let cmx = ExtractedNoteCommitment::from(note.commitment()); + let mut tree = CommitmentTree::new(new_memory_store(), 100); + tree.append(cmx, Retention::Marked).unwrap(); + tree.checkpoint(0u32).unwrap(); + let anchor = tree.anchor().unwrap(); + let merkle_path = tree + .orchard_witness(Position::from(0u64)) + .unwrap() + .unwrap(); + + // --- Build bundle: spend 10_000 → output 10_000 (value_balance = 0) --- + let mut builder = Builder::new(BundleType::DEFAULT, anchor); + builder + .add_spend(fvk.clone(), note, merkle_path) + .unwrap(); + builder + .add_output(None, recipient, NoteValue::from_raw(10_000), [0u8; 512]) + .unwrap(); + + let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); + let sighash = unauthorized.commitment().into(); + let proven = unauthorized.create_proof(pk, &mut rng).unwrap(); + let bundle = proven.apply_signatures(rng, sighash, &[ask]).unwrap(); + + // --- Extract serialized fields --- + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + + // value_balance should be 0 (equal spend and output) + assert_eq!(value_balance, 0); + + // --- Insert anchor into platform state --- + insert_anchor_into_state(&platform, &anchor_bytes); + + // --- Create and process transition --- + let transition = create_shielded_transfer_transition( + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution { .. }] + ); + } + #[test] fn test_wrong_encrypted_note_size_returns_error() { let platform_version = PlatformVersion::latest(); @@ -470,4 +626,283 @@ mod tests { ); } } + + // ========================================== + // SECURITY AUDIT TESTS + // ========================================== + // + // These tests verify vulnerabilities and edge cases discovered + // during a security audit of the shielded transaction system. + // Tests that demonstrate actual vulnerabilities are marked with + // "AUDIT FINDING" comments and document the expected correct behavior. + + mod security_audit { + use super::*; + use grovedb_commitment_tree::{ + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + CommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, + NoteValue, Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, + SpendingKey, new_memory_store, + }; + use orchard::note::RandomSeed; + use rand::rngs::OsRng; + use std::sync::OnceLock; + + static TEST_PROVING_KEY: OnceLock = OnceLock::new(); + fn get_proving_key() -> &'static ProvingKey { + TEST_PROVING_KEY.get_or_init(ProvingKey::build) + } + + fn serialize_authorized_bundle( + bundle: &Bundle, + ) -> (Vec, u8, i64, [u8; 32], Vec, Vec) { + let actions: Vec = bundle + .actions() + .iter() + .map(|action| { + let enc = action.encrypted_note(); + let mut encrypted_note = Vec::with_capacity(692); + encrypted_note.extend_from_slice(&enc.epk_bytes); + encrypted_note.extend_from_slice(&enc.enc_ciphertext); + encrypted_note.extend_from_slice(&enc.out_ciphertext); + SerializedAction { + nullifier: action.nullifier().to_bytes(), + rk: <[u8; 32]>::from(action.rk()), + cmx: action.cmx().to_bytes(), + encrypted_note, + cv_net: action.cv_net().to_bytes(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()).to_vec(), + } + }) + .collect(); + let flags = bundle.flags().to_byte(); + let value_balance = *bundle.value_balance(); + let anchor = bundle.anchor().to_bytes(); + let proof = bundle.authorization().proof().as_ref().to_vec(); + let binding_sig = + <[u8; 64]>::from(bundle.authorization().binding_signature()).to_vec(); + (actions, flags, value_balance, anchor, proof, binding_sig) + } + + /// Build a valid Orchard bundle for shielded transfer tests. + /// Returns (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig). + fn build_valid_shielded_transfer_bundle() -> (Vec, u8, i64, [u8; 32], Vec, Vec) { + let mut rng = OsRng; + let pk = get_proving_key(); + + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + let ask = SpendAuthorizingKey::from(&sk); + + let rho_bytes: [u8; 32] = { + let mut b = [0u8; 32]; + b[0] = 1; + b + }; + let rho = Rho::from_bytes(&rho_bytes).unwrap(); + let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); + let note = Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed) + .unwrap(); + + let cmx = ExtractedNoteCommitment::from(note.commitment()); + let mut tree = CommitmentTree::new(new_memory_store(), 100); + tree.append(cmx, Retention::Marked).unwrap(); + tree.checkpoint(0u32).unwrap(); + let anchor = tree.anchor().unwrap(); + let merkle_path = tree + .orchard_witness(Position::from(0u64)) + .unwrap() + .unwrap(); + + let mut builder = Builder::new(BundleType::DEFAULT, anchor); + builder + .add_spend(fvk.clone(), note, merkle_path) + .unwrap(); + builder + .add_output(None, recipient, NoteValue::from_raw(10_000), [0u8; 512]) + .unwrap(); + + let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); + let sighash = unauthorized.commitment().into(); + let proven = unauthorized.create_proof(pk, &mut rng).unwrap(); + let bundle = proven.apply_signatures(rng, sighash, &[ask]).unwrap(); + + serialize_authorized_bundle(&bundle) + } + + /// AUDIT REGRESSION: Mutating value_balance is now caught by BatchValidator. + /// + /// Previously, the code only called `bundle.verify_proof(vk)` which did not + /// check the binding signature. Now `BatchValidator` verifies the Halo 2 proof + /// AND the binding signature, which cryptographically binds value_balance to + /// the value commitments (cv_net). Mutating value_balance changes the bundle + /// commitment (sighash), causing signature verification to fail. + /// + /// Original severity: CRITICAL — now FIXED. + #[test] + fn test_valid_proof_with_mutated_value_balance_is_rejected() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + build_valid_shielded_transfer_bundle(); + assert_eq!(value_balance, 0); + + // ATTACK: Mutate value_balance from 0 to 5000 + let mutated_value_balance = 5000i64; + + // Set pool balance so fee deduction doesn't underflow + set_pool_total_balance(&platform, 10_000); + insert_anchor_into_state(&platform, &anchor_bytes); + + let transition = create_shielded_transfer_transition( + actions, + flags, + mutated_value_balance, // MUTATED: was 0, now 5000 + anchor_bytes, + proof_bytes, + binding_sig, + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // FIXED: BatchValidator detects the binding signature mismatch. + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + + /// AUDIT REGRESSION: Zeroed binding signature is now caught by BatchValidator. + /// + /// Previously accepted because only the Halo 2 proof was verified. + /// Now `BatchValidator` verifies the binding signature as well. + /// + /// Original severity: CRITICAL — now FIXED. + #[test] + fn test_valid_proof_with_zeroed_binding_sig_is_rejected() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let (actions, flags, value_balance, anchor_bytes, proof_bytes, _binding_sig) = + build_valid_shielded_transfer_bundle(); + + insert_anchor_into_state(&platform, &anchor_bytes); + + let transition = create_shielded_transfer_transition( + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + vec![0u8; 64], // ZEROED binding signature + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // FIXED: BatchValidator detects the invalid binding signature. + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + + /// AUDIT REGRESSION: Zeroed spend auth signatures are now caught by BatchValidator. + /// + /// Previously accepted because only the Halo 2 proof was verified. + /// Now `BatchValidator` verifies spend authorization signatures, proving + /// that the spender controls the spending key. + /// + /// Original severity: CRITICAL — now FIXED. + #[test] + fn test_valid_proof_with_zeroed_spend_auth_sig_is_rejected() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let (mut actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + build_valid_shielded_transfer_bundle(); + + // ATTACK: Zero out all spend auth signatures + for action in &mut actions { + action.spend_auth_sig = vec![0u8; 64]; + } + + insert_anchor_into_state(&platform, &anchor_bytes); + + let transition = create_shielded_transfer_transition( + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // FIXED: BatchValidator detects the invalid spend auth signatures. + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + + /// AUDIT FINDING: No intra-bundle duplicate nullifier check. + /// + /// The nullifier validation loop only checks the state database for + /// each nullifier. It does not check for duplicates within the same + /// bundle's action list. This is mitigated by the ZK proof (which + /// can't produce duplicate nullifiers from a valid circuit), and by + /// GroveDB's insert_only_op (which would fail on the second insert). + /// + /// Severity: LOW (defense-in-depth gap) + /// For a fabricated bundle with duplicate nullifiers, the proof + /// verification catches the invalid data. + #[test] + fn test_duplicate_nullifiers_in_same_bundle() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let anchor = [42u8; 32]; + insert_anchor_into_state(&platform, &anchor); + + // Two actions with the same nullifier but different cmx + let action1 = create_dummy_serialized_action(); + let mut action2 = create_dummy_serialized_action(); + action2.cmx = [99u8; 32]; // Different commitment + + let transition = create_shielded_transfer_transition( + vec![action1, action2], // Both have nullifier [1u8; 32] + 0x03, + 0, + anchor, + vec![0u8; 100], + vec![0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // The duplicate nullifiers are NOT caught by the application-level + // nullifier check (which only checks state). They are caught by + // proof verification (the fabricated data produces an invalid proof). + // Ideally, intra-bundle nullifier dedup should be added as defense-in-depth. + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs index acc700f31fa..3984f5e3d87 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs @@ -5,12 +5,11 @@ use dpp::consensus::state::shielded::nullifier_already_spent_error::NullifierAlr use dpp::consensus::state::state_error::StateError; use dpp::fee::Credits; use dpp::prelude::ConsensusValidationResult; -use dpp::shielded::ShieldedPoolParams; use dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition; use dpp::version::PlatformVersion; use drive::drive::shielded::paths::{ shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, - shielded_credit_pool_path, SHIELDED_PARAMS_KEY, SHIELDED_TOTAL_BALANCE_KEY, + shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY, }; use drive::drive::Drive; use drive::grovedb::TransactionArg; @@ -64,24 +63,6 @@ impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 for Shielded let mut drive_operations = vec![]; let pool_path = shielded_credit_pool_path(); - let params_bytes = drive.grove_get_raw_item( - (&pool_path).into(), - &[SHIELDED_PARAMS_KEY], - DirectQueryType::StatefulDirectQuery, - transaction, - &mut drive_operations, - &platform_version.drive, - )?; - let (params, _): (ShieldedPoolParams, _) = - bincode::decode_from_slice(¶ms_bytes, bincode::config::standard()).map_err( - |e| { - Error::Protocol(dpp::ProtocolError::DecodingError(format!( - "could not decode shielded pool params: {e}" - ))) - }, - )?; - let current_checkpoint_id = params.checkpoint_id_counter; - let current_total_balance = drive .grove_get_raw_value_u64_from_encoded_var_vec( (&pool_path).into(), @@ -163,7 +144,6 @@ impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 for Shielded encrypted_notes, anchor, fee_amount, - current_checkpoint_id, current_total_balance, ); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs index 53bb8a8343a..b84e3116693 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs @@ -16,6 +16,7 @@ mod tests { use dpp::state_transition::StateTransition; use drive::drive::shielded::paths::{ shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, + shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY, }; use drive::grovedb::Element; use platform_version::version::PlatformVersion; @@ -151,6 +152,38 @@ mod tests { .expect("should commit transaction"); } + /// Set the shielded pool total balance in GroveDB. + fn set_pool_total_balance( + platform: &crate::test::helpers::setup::TempPlatform, + balance: u64, + ) { + let platform_version = PlatformVersion::latest(); + let grove_version = &platform_version.drive.grove_version; + let transaction = platform.drive.grove.start_transaction(); + let pool_path = shielded_credit_pool_path(); + + platform + .drive + .grove + .insert( + &pool_path, + &[SHIELDED_TOTAL_BALANCE_KEY], + Element::new_sum_item(balance as i64), + None, + Some(&transaction), + grove_version, + ) + .unwrap() + .expect("should set total balance"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("should commit transaction"); + } + /// Standard platform setup for tests. fn setup_platform( ) -> crate::test::helpers::setup::TempPlatform { @@ -516,6 +549,51 @@ mod tests { mod proof_verification { use super::*; + use grovedb_commitment_tree::{ + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + CommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, + NoteValue, Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, + SpendingKey, new_memory_store, + }; + use orchard::note::RandomSeed; + use rand::rngs::OsRng; + use std::sync::OnceLock; + + static TEST_PROVING_KEY: OnceLock = OnceLock::new(); + fn get_proving_key() -> &'static ProvingKey { + TEST_PROVING_KEY.get_or_init(ProvingKey::build) + } + + fn serialize_authorized_bundle( + bundle: &Bundle, + ) -> (Vec, u8, i64, [u8; 32], Vec, Vec) { + let actions: Vec = bundle + .actions() + .iter() + .map(|action| { + let enc = action.encrypted_note(); + let mut encrypted_note = Vec::with_capacity(692); + encrypted_note.extend_from_slice(&enc.epk_bytes); + encrypted_note.extend_from_slice(&enc.enc_ciphertext); + encrypted_note.extend_from_slice(&enc.out_ciphertext); + SerializedAction { + nullifier: action.nullifier().to_bytes(), + rk: <[u8; 32]>::from(action.rk()), + cmx: action.cmx().to_bytes(), + encrypted_note, + cv_net: action.cv_net().to_bytes(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()).to_vec(), + } + }) + .collect(); + let flags = bundle.flags().to_byte(); + let value_balance = *bundle.value_balance(); + let anchor = bundle.anchor().to_bytes(); + let proof = bundle.authorization().proof().as_ref().to_vec(); + let binding_sig = + <[u8; 64]>::from(bundle.authorization().binding_signature()).to_vec(); + (actions, flags, value_balance, anchor, proof, binding_sig) + } #[test] fn test_invalid_proof_returns_shielded_proof_error() { @@ -542,6 +620,91 @@ mod tests { ); } + #[test] + fn test_valid_unshield_proof_succeeds() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + let mut rng = OsRng; + let pk = get_proving_key(); + + // --- Create keys --- + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + let ask = SpendAuthorizingKey::from(&sk); + + // --- Create a spendable note with value 10,000 --- + let rho_bytes: [u8; 32] = { + let mut b = [0u8; 32]; + b[0] = 1; + b + }; + let rho = Rho::from_bytes(&rho_bytes).unwrap(); + let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); + let note = Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed) + .unwrap(); + + // --- Build commitment tree and get anchor + merkle path --- + let cmx = ExtractedNoteCommitment::from(note.commitment()); + let mut tree = CommitmentTree::new(new_memory_store(), 100); + tree.append(cmx, Retention::Marked).unwrap(); + tree.checkpoint(0u32).unwrap(); + let anchor = tree.anchor().unwrap(); + let merkle_path = tree + .orchard_witness(Position::from(0u64)) + .unwrap() + .unwrap(); + + // --- Build bundle: spend 10,000 → output 5,000 (value_balance = 5,000) --- + let mut builder = Builder::new(BundleType::DEFAULT, anchor); + builder + .add_spend(fvk.clone(), note, merkle_path) + .unwrap(); + builder + .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 512]) + .unwrap(); + + let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); + let sighash = unauthorized.commitment().into(); + let proven = unauthorized.create_proof(pk, &mut rng).unwrap(); + let bundle = proven.apply_signatures(rng, sighash, &[ask]).unwrap(); + + // --- Extract serialized fields --- + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + + // value_balance should be 5000 (10,000 spent - 5,000 output) + assert_eq!(value_balance, 5_000); + + // --- Set up platform state --- + // Insert anchor so anchor validation passes + insert_anchor_into_state(&platform, &anchor_bytes); + + // Set pool total balance so the unshield has sufficient funds + set_pool_total_balance(&platform, 10_000); + + // --- Create and process transition --- + // amount = value_balance (no fee difference) + let transition = create_unshield_transition( + create_output_address(), + value_balance as u64, // amount = 5000 + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution { .. }] + ); + } + #[test] fn test_wrong_encrypted_note_size_returns_error() { let platform_version = PlatformVersion::latest(); @@ -578,4 +741,251 @@ mod tests { ); } } + + // ========================================== + // SECURITY AUDIT TESTS + // ========================================== + + mod security_audit { + use super::*; + use grovedb_commitment_tree::{ + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + CommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, + NoteValue, Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, + SpendingKey, new_memory_store, + }; + use orchard::note::RandomSeed; + use rand::rngs::OsRng; + use std::sync::OnceLock; + + static TEST_PROVING_KEY: OnceLock = OnceLock::new(); + fn get_proving_key() -> &'static ProvingKey { + TEST_PROVING_KEY.get_or_init(ProvingKey::build) + } + + fn serialize_authorized_bundle( + bundle: &Bundle, + ) -> (Vec, u8, i64, [u8; 32], Vec, Vec) { + let actions: Vec = bundle + .actions() + .iter() + .map(|action| { + let enc = action.encrypted_note(); + let mut encrypted_note = Vec::with_capacity(692); + encrypted_note.extend_from_slice(&enc.epk_bytes); + encrypted_note.extend_from_slice(&enc.enc_ciphertext); + encrypted_note.extend_from_slice(&enc.out_ciphertext); + SerializedAction { + nullifier: action.nullifier().to_bytes(), + rk: <[u8; 32]>::from(action.rk()), + cmx: action.cmx().to_bytes(), + encrypted_note, + cv_net: action.cv_net().to_bytes(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()).to_vec(), + } + }) + .collect(); + let flags = bundle.flags().to_byte(); + let value_balance = *bundle.value_balance(); + let anchor = bundle.anchor().to_bytes(); + let proof = bundle.authorization().proof().as_ref().to_vec(); + let binding_sig = + <[u8; 64]>::from(bundle.authorization().binding_signature()).to_vec(); + (actions, flags, value_balance, anchor, proof, binding_sig) + } + + /// Build a valid Orchard bundle for unshield tests (spend > output). + /// Returns (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig). + fn build_valid_unshield_bundle() -> (Vec, u8, i64, [u8; 32], Vec, Vec) { + let mut rng = OsRng; + let pk = get_proving_key(); + + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + let ask = SpendAuthorizingKey::from(&sk); + + let rho_bytes: [u8; 32] = { + let mut b = [0u8; 32]; + b[0] = 1; + b + }; + let rho = Rho::from_bytes(&rho_bytes).unwrap(); + let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); + let note = Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed) + .unwrap(); + + let cmx = ExtractedNoteCommitment::from(note.commitment()); + let mut tree = CommitmentTree::new(new_memory_store(), 100); + tree.append(cmx, Retention::Marked).unwrap(); + tree.checkpoint(0u32).unwrap(); + let anchor = tree.anchor().unwrap(); + let merkle_path = tree + .orchard_witness(Position::from(0u64)) + .unwrap() + .unwrap(); + + // Spend 10,000 → output 5,000 → value_balance = 5,000 + let mut builder = Builder::new(BundleType::DEFAULT, anchor); + builder + .add_spend(fvk.clone(), note, merkle_path) + .unwrap(); + builder + .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 512]) + .unwrap(); + + let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); + let sighash = unauthorized.commitment().into(); + let proven = unauthorized.create_proof(pk, &mut rng).unwrap(); + let bundle = proven.apply_signatures(rng, sighash, &[ask]).unwrap(); + + serialize_authorized_bundle(&bundle) + } + + /// AUDIT REGRESSION: Mutating value_balance is now caught by BatchValidator. + /// + /// Previously, the code only called `bundle.verify_proof(vk)` which did not + /// check the binding signature. Now `BatchValidator` verifies the Halo 2 proof + /// AND the binding signature, which cryptographically binds value_balance to + /// the value commitments (cv_net). Mutating value_balance changes the bundle + /// commitment (sighash), causing signature verification to fail. + /// + /// Original severity: CRITICAL — now FIXED. + #[test] + fn test_valid_proof_with_mutated_value_balance_is_rejected() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + build_valid_unshield_bundle(); + assert_eq!(value_balance, 5_000); + + // ATTACK: Inflate value_balance from 5000 to 9000 + let mutated_value_balance = 9_000i64; + + // Set pool balance high enough for the inflated amount + set_pool_total_balance(&platform, 20_000); + insert_anchor_into_state(&platform, &anchor_bytes); + + let transition = create_unshield_transition( + create_output_address(), + mutated_value_balance as u64, // amount = 9000 (inflated) + actions, + flags, + mutated_value_balance, // MUTATED: was 5000, now 9000 + anchor_bytes, + proof_bytes, + binding_sig, + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // FIXED: BatchValidator detects the binding signature mismatch. + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + + /// AUDIT FINDING (STILL OPEN): Transparent fields (output_address, amount) + /// are not bound to the Orchard bundle via sighash. + /// + /// An attacker who observes a valid unshield bundle can create a new + /// unshield transition with a different output_address, redirecting + /// funds to their own address. The nullifiers prevent double-spending, + /// but this enables front-running: the attacker's transaction (with + /// their address) could be included before the victim's. + /// + /// Note: The binding and spend auth signature fixes (BatchValidator) do + /// NOT fix this — the output_address is outside the Orchard bundle, so + /// changing it does not affect the sighash or any signatures. The bundle + /// remains cryptographically valid with a different output_address. + /// + /// Mitigation requires binding transparent fields to the sighash + /// (e.g., including them in the bundle commitment computation). + /// + /// Severity: HIGH (requires separate fix) + #[test] + fn test_different_output_address_with_same_valid_bundle_is_accepted() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + build_valid_unshield_bundle(); + assert_eq!(value_balance, 5_000); + + set_pool_total_balance(&platform, 20_000); + insert_anchor_into_state(&platform, &anchor_bytes); + + // ATTACK: Use a completely different output address + let attacker_address = PlatformAddress::P2pkh([0xAA; 20]); + + let transition = create_unshield_transition( + attacker_address, // ATTACKER's address, not the original recipient + value_balance as u64, + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // VULNERABILITY: Succeeds because the output_address is not bound + // to the Orchard bundle via sighash or any other mechanism. + // The attacker redirects the unshielded funds to their own address. + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution { .. }] + ); + } + + /// AUDIT FINDING: No intra-bundle duplicate nullifier check. + /// + /// Same as the shielded_transfer finding. The nullifier check only + /// queries state, not checking for duplicates within the bundle itself. + /// + /// Severity: LOW (defense-in-depth gap, caught by ZK proof verification) + #[test] + fn test_duplicate_nullifiers_in_same_bundle() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let anchor = [42u8; 32]; + insert_anchor_into_state(&platform, &anchor); + set_pool_total_balance(&platform, 10_000); + + let action1 = create_dummy_serialized_action(); + let mut action2 = create_dummy_serialized_action(); + action2.cmx = [99u8; 32]; + + let transition = create_unshield_transition( + create_output_address(), + 1000, + vec![action1, action2], // Both have nullifier [1u8; 32] + 0x03, + 1000, + anchor, + vec![0u8; 100], + vec![0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // Caught by proof verification, not by application-level dedup + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs index de31ca3db0d..f808af740b1 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs @@ -4,12 +4,11 @@ use dpp::consensus::state::shielded::invalid_anchor_error::InvalidAnchorError; use dpp::consensus::state::shielded::nullifier_already_spent_error::NullifierAlreadySpentError; use dpp::consensus::state::state_error::StateError; use dpp::prelude::ConsensusValidationResult; -use dpp::shielded::ShieldedPoolParams; use dpp::state_transition::unshield_transition::UnshieldTransition; use dpp::version::PlatformVersion; use drive::drive::shielded::paths::{ shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, - shielded_credit_pool_path, SHIELDED_PARAMS_KEY, SHIELDED_TOTAL_BALANCE_KEY, + shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY, }; use drive::drive::Drive; use drive::grovedb::TransactionArg; @@ -58,24 +57,6 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti let mut drive_operations = vec![]; let pool_path = shielded_credit_pool_path(); - let params_bytes = drive.grove_get_raw_item( - (&pool_path).into(), - &[SHIELDED_PARAMS_KEY], - DirectQueryType::StatefulDirectQuery, - transaction, - &mut drive_operations, - &platform_version.drive, - )?; - let (params, _): (ShieldedPoolParams, _) = - bincode::decode_from_slice(¶ms_bytes, bincode::config::standard()).map_err( - |e| { - Error::Protocol(dpp::ProtocolError::DecodingError(format!( - "could not decode shielded pool params: {e}" - ))) - }, - )?; - let current_checkpoint_id = params.checkpoint_id_counter; - let current_total_balance = drive .grove_get_raw_value_u64_from_encoded_var_vec( (&pool_path).into(), @@ -156,7 +137,6 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti note_commitments, encrypted_notes, anchor, - current_checkpoint_id, current_total_balance, ); diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index 6693456791b..ad41153e4e2 100644 --- a/packages/rs-drive/Cargo.toml +++ b/packages/rs-drive/Cargo.toml @@ -52,12 +52,12 @@ enum-map = { version = "2.0.3", optional = true } intmap = { version = "3.0.1", features = ["serde"], optional = true } chrono = { version = "0.4.35", optional = true } itertools = { version = "0.13", optional = true } -grovedb = { git = "https://github.com/dashpay/grovedb", rev = "219ba2e73f08a9f428c9427f7ab5c73907d670bf", optional = true, default-features = false } -grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "219ba2e73f08a9f428c9427f7ab5c73907d670bf", optional = true } -grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "219ba2e73f08a9f428c9427f7ab5c73907d670bf" } -grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "219ba2e73f08a9f428c9427f7ab5c73907d670bf", optional = true } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "219ba2e73f08a9f428c9427f7ab5c73907d670bf" } -grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "219ba2e73f08a9f428c9427f7ab5c73907d670bf" } +grovedb = { path = "../../../grovedb/grovedb", optional = true, default-features = false } +grovedb-costs = { path = "../../../grovedb/costs", optional = true } +grovedb-path = { path = "../../../grovedb/path" } +grovedb-storage = { path = "../../../grovedb/storage", optional = true } +grovedb-version = { path = "../../../grovedb/grovedb-version" } +grovedb-epoch-based-storage-flags = { path = "../../../grovedb/grovedb-epoch-based-storage-flags" } [dev-dependencies] criterion = "0.5" diff --git a/packages/rs-drive/src/drive/shielded/estimated_costs.rs b/packages/rs-drive/src/drive/shielded/estimated_costs.rs new file mode 100644 index 00000000000..30570c0b2c5 --- /dev/null +++ b/packages/rs-drive/src/drive/shielded/estimated_costs.rs @@ -0,0 +1,117 @@ +use crate::drive::shielded::paths::{ + shielded_anchors_credit_pool_path, shielded_anchors_path, shielded_credit_pool_commitments_path, + shielded_credit_pool_encrypted_notes_path, shielded_credit_pool_nullifiers_path, + shielded_credit_pool_path, +}; +use crate::drive::Drive; +use grovedb::batch::KeyInfoPath; +use grovedb::EstimatedLayerCount::EstimatedLevel; +use grovedb::EstimatedLayerSizes::{AllItems, AllSubtrees, Mix}; +use grovedb::EstimatedSumTrees::{NoSumTrees, SomeSumTrees}; +use grovedb::{EstimatedLayerInformation, TreeType}; +use std::collections::HashMap; + +/// Average size of an encrypted note (~692 bytes: 32 epk + 580 enc + 80 out) +const AVERAGE_ENCRYPTED_NOTE_SIZE: u32 = 692; + +/// Size of a commitment or nullifier key (32 bytes) +const COMMITMENT_KEY_SIZE: u8 = 32; + +/// Size of an anchor key (32 bytes) +const ANCHOR_KEY_SIZE: u8 = 32; + +impl Drive { + /// Adds estimation costs for shielded pool operations. + /// + /// Registers all shielded pool tree paths in the estimation cache so that + /// the fee estimation system can calculate costs for shielded operations. + pub(crate) fn add_estimation_costs_for_shielded_pool_operations( + estimated_costs_only_with_layer_info: &mut HashMap, + ) { + // Shielded credit pool: [AddressBalances, "s"] + // SumTree containing: commitments tree (CommitmentTree), nullifiers tree (NormalTree), + // encrypted notes tree (NormalTree), params item, total balance sum item + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(shielded_credit_pool_path()), + EstimatedLayerInformation { + tree_type: TreeType::SumTree, + estimated_layer_count: EstimatedLevel(5, false), + estimated_layer_sizes: Mix { + subtrees_size: Some(( + 1, + SomeSumTrees { + sum_trees_weight: 0, + big_sum_trees_weight: 0, + count_trees_weight: 0, + count_sum_trees_weight: 0, + non_sum_trees_weight: 3, + }, + None, + 3, // 3 subtrees: commitments, nullifiers, encrypted notes + )), + items_size: Some((1, 100, None, 2)), // 2 items: params and total balance + references_size: None, + }, + }, + ); + + // Commitments tree: [AddressBalances, "s", 1] + // CommitmentTree - stores Orchard note commitments + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(shielded_credit_pool_commitments_path()), + EstimatedLayerInformation { + tree_type: TreeType::CommitmentTree, + estimated_layer_count: EstimatedLevel(10, false), + estimated_layer_sizes: AllItems(COMMITMENT_KEY_SIZE, 32, None), + }, + ); + + // Nullifiers tree: [AddressBalances, "s", 2] + // NormalTree - stores spent nullifiers (32-byte key → empty item) + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(shielded_credit_pool_nullifiers_path()), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: EstimatedLevel(10, false), + estimated_layer_sizes: AllItems(COMMITMENT_KEY_SIZE, 0, None), + }, + ); + + // Encrypted notes tree: [AddressBalances, "s", 3] + // NormalTree - stores encrypted notes (32-byte key → ~692-byte item) + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(shielded_credit_pool_encrypted_notes_path()), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: EstimatedLevel(10, false), + estimated_layer_sizes: AllItems( + COMMITMENT_KEY_SIZE, + AVERAGE_ENCRYPTED_NOTE_SIZE, + None, + ), + }, + ); + + // Anchors tree: [AddressBalances, "a"] + // NormalTree - contains subtrees per pool type + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(shielded_anchors_path()), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: EstimatedLevel(1, false), + estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), + }, + ); + + // Anchors credit pool tree: [AddressBalances, "a", "s"] + // NormalTree - stores anchor hashes (32-byte key → empty item) + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path(shielded_anchors_credit_pool_path()), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: EstimatedLevel(10, false), + estimated_layer_sizes: AllItems(ANCHOR_KEY_SIZE, 0, None), + }, + ); + } +} diff --git a/packages/rs-drive/src/drive/shielded/mod.rs b/packages/rs-drive/src/drive/shielded/mod.rs index 774df92744d..5b1d638eb1f 100644 --- a/packages/rs-drive/src/drive/shielded/mod.rs +++ b/packages/rs-drive/src/drive/shielded/mod.rs @@ -1,3 +1,7 @@ /// Shielded pool paths and constants #[cfg(any(feature = "server", feature = "verify"))] pub mod paths; + +/// Estimation costs for shielded pool operations +#[cfg(feature = "server")] +pub(crate) mod estimated_costs; diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs index 4e35523544b..31602de7245 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs @@ -1,6 +1,6 @@ use crate::drive::shielded::paths::{ - shielded_credit_pool_commitments_path_vec, shielded_credit_pool_encrypted_notes_path_vec, - shielded_credit_pool_nullifiers_path_vec, shielded_credit_pool_path_vec, SHIELDED_PARAMS_KEY, + shielded_credit_pool_encrypted_notes_path_vec, shielded_credit_pool_nullifiers_path_vec, + shielded_credit_pool_path_vec, SHIELDED_COMMITMENTS_KEY, SHIELDED_TOTAL_BALANCE_KEY, }; use crate::error::Error; @@ -12,7 +12,6 @@ use crate::util::batch::drive_op_batch::finalize_task::DriveOperationFinalizeTas use crate::util::batch::drive_op_batch::AddressFundsOperationType; use crate::util::batch::DriveOperation; use dpp::block::epoch::Epoch; -use dpp::shielded::ShieldedPoolParams; use dpp::version::PlatformVersion; use grovedb::batch::QualifiedGroveDbOp; use grovedb::Element; @@ -38,22 +37,16 @@ impl DriveHighLevelOperationConverter for ShieldTransitionAction { )); } - let commitments_path = shielded_credit_pool_commitments_path_vec(); let encrypted_notes_path = shielded_credit_pool_encrypted_notes_path_vec(); let pool_path = shielded_credit_pool_path_vec(); - // We start with the current checkpoint_id and increment for each commitment - let mut next_checkpoint_id = v0.current_checkpoint_id; - // 2. Append each note commitment to the commitment tree for cmx in v0.note_commitments.iter() { - next_checkpoint_id += 1; - ops.push(DriveOperation::GroveDBOperation( + ops.push(DriveOperation::ShieldedPoolOperation( QualifiedGroveDbOp::commitment_tree_append_op( - commitments_path.clone(), - vec![], // key is empty for commitment tree append + pool_path.clone(), + vec![SHIELDED_COMMITMENTS_KEY], *cmx, - next_checkpoint_id, ), )); } @@ -62,7 +55,7 @@ impl DriveHighLevelOperationConverter for ShieldTransitionAction { for (cmx, encrypted_note) in v0.note_commitments.iter().zip(v0.encrypted_notes.iter()) { - ops.push(DriveOperation::GroveDBOperation( + ops.push(DriveOperation::ShieldedPoolOperation( QualifiedGroveDbOp::insert_only_op( encrypted_notes_path.clone(), cmx.to_vec(), @@ -72,31 +65,21 @@ impl DriveHighLevelOperationConverter for ShieldTransitionAction { } // 4. Update total balance SumItem: current_total_balance + shield_amount - let new_total_balance = v0.current_total_balance + v0.shield_amount; - ops.push(DriveOperation::GroveDBOperation( + let new_total_balance = v0.current_total_balance.checked_add(v0.shield_amount) + .ok_or_else(|| Error::Drive( + crate::error::drive::DriveError::CorruptedDriveState( + "shielded pool total balance overflow when adding shield amount".to_string(), + ), + ))?; + ops.push(DriveOperation::ShieldedPoolOperation( QualifiedGroveDbOp::insert_or_replace_op( - pool_path.clone(), + pool_path, vec![SHIELDED_TOTAL_BALANCE_KEY], Element::new_sum_item(new_total_balance as i64), ), )); - // 5. Update params with incremented checkpoint_id_counter - let new_params = ShieldedPoolParams { - checkpoint_id_counter: next_checkpoint_id, - }; - let encoded_params = - bincode::encode_to_vec(&new_params, bincode::config::standard()) - .expect("expected to encode shielded pool params"); - ops.push(DriveOperation::GroveDBOperation( - QualifiedGroveDbOp::insert_or_replace_op( - pool_path, - vec![SHIELDED_PARAMS_KEY], - Element::new_item(encoded_params), - ), - )); - - // Record anchor after batch is applied (finalization task) + // Checkpoint the commitment tree and record anchor after batch is applied ops.push(DriveOperation::FinalizeOperation( DriveOperationFinalizeTask::RecordShieldedAnchor, )); @@ -118,13 +101,12 @@ impl DriveHighLevelOperationConverter for ShieldedTransferTransitionAction { let mut ops: Vec> = Vec::new(); let nullifiers_path = shielded_credit_pool_nullifiers_path_vec(); - let commitments_path = shielded_credit_pool_commitments_path_vec(); let encrypted_notes_path = shielded_credit_pool_encrypted_notes_path_vec(); let pool_path = shielded_credit_pool_path_vec(); // 1. Insert each nullifier (empty Item, InsertOnly to prevent double-spend) for nullifier in v0.nullifiers.iter() { - ops.push(DriveOperation::GroveDBOperation( + ops.push(DriveOperation::ShieldedPoolOperation( QualifiedGroveDbOp::insert_only_op( nullifiers_path.clone(), nullifier.to_vec(), @@ -133,18 +115,13 @@ impl DriveHighLevelOperationConverter for ShieldedTransferTransitionAction { )); } - // We start with the current checkpoint_id and increment for each commitment - let mut next_checkpoint_id = v0.current_checkpoint_id; - // 2. Append each note commitment to the commitment tree for cmx in v0.note_commitments.iter() { - next_checkpoint_id += 1; - ops.push(DriveOperation::GroveDBOperation( + ops.push(DriveOperation::ShieldedPoolOperation( QualifiedGroveDbOp::commitment_tree_append_op( - commitments_path.clone(), - vec![], + pool_path.clone(), + vec![SHIELDED_COMMITMENTS_KEY], *cmx, - next_checkpoint_id, ), )); } @@ -153,7 +130,7 @@ impl DriveHighLevelOperationConverter for ShieldedTransferTransitionAction { for (cmx, encrypted_note) in v0.note_commitments.iter().zip(v0.encrypted_notes.iter()) { - ops.push(DriveOperation::GroveDBOperation( + ops.push(DriveOperation::ShieldedPoolOperation( QualifiedGroveDbOp::insert_only_op( encrypted_notes_path.clone(), cmx.to_vec(), @@ -166,31 +143,20 @@ impl DriveHighLevelOperationConverter for ShieldedTransferTransitionAction { let new_total_balance = v0 .current_total_balance .checked_sub(v0.fee_amount) - .expect("total balance must be >= fee_amount"); - ops.push(DriveOperation::GroveDBOperation( + .ok_or_else(|| Error::Drive( + crate::error::drive::DriveError::CorruptedDriveState( + "shielded pool total balance underflow when subtracting fee_amount".to_string(), + ), + ))?; + ops.push(DriveOperation::ShieldedPoolOperation( QualifiedGroveDbOp::insert_or_replace_op( - pool_path.clone(), + pool_path, vec![SHIELDED_TOTAL_BALANCE_KEY], Element::new_sum_item(new_total_balance as i64), ), )); - // 5. Update params with incremented checkpoint_id_counter - let new_params = ShieldedPoolParams { - checkpoint_id_counter: next_checkpoint_id, - }; - let encoded_params = - bincode::encode_to_vec(&new_params, bincode::config::standard()) - .expect("expected to encode shielded pool params"); - ops.push(DriveOperation::GroveDBOperation( - QualifiedGroveDbOp::insert_or_replace_op( - pool_path, - vec![SHIELDED_PARAMS_KEY], - Element::new_item(encoded_params), - ), - )); - - // Record anchor after batch is applied (finalization task) + // Checkpoint the commitment tree and record anchor after batch is applied ops.push(DriveOperation::FinalizeOperation( DriveOperationFinalizeTask::RecordShieldedAnchor, )); @@ -212,13 +178,12 @@ impl DriveHighLevelOperationConverter for UnshieldTransitionAction { let mut ops: Vec> = Vec::new(); let nullifiers_path = shielded_credit_pool_nullifiers_path_vec(); - let commitments_path = shielded_credit_pool_commitments_path_vec(); let encrypted_notes_path = shielded_credit_pool_encrypted_notes_path_vec(); let pool_path = shielded_credit_pool_path_vec(); // 1. Insert each nullifier (empty Item, InsertOnly to prevent double-spend) for nullifier in v0.nullifiers.iter() { - ops.push(DriveOperation::GroveDBOperation( + ops.push(DriveOperation::ShieldedPoolOperation( QualifiedGroveDbOp::insert_only_op( nullifiers_path.clone(), nullifier.to_vec(), @@ -235,18 +200,13 @@ impl DriveHighLevelOperationConverter for UnshieldTransitionAction { }, )); - // We start with the current checkpoint_id and increment for each commitment - let mut next_checkpoint_id = v0.current_checkpoint_id; - // 3. Append each note commitment (change outputs) to the commitment tree for cmx in v0.note_commitments.iter() { - next_checkpoint_id += 1; - ops.push(DriveOperation::GroveDBOperation( + ops.push(DriveOperation::ShieldedPoolOperation( QualifiedGroveDbOp::commitment_tree_append_op( - commitments_path.clone(), - vec![], + pool_path.clone(), + vec![SHIELDED_COMMITMENTS_KEY], *cmx, - next_checkpoint_id, ), )); } @@ -255,7 +215,7 @@ impl DriveHighLevelOperationConverter for UnshieldTransitionAction { for (cmx, encrypted_note) in v0.note_commitments.iter().zip(v0.encrypted_notes.iter()) { - ops.push(DriveOperation::GroveDBOperation( + ops.push(DriveOperation::ShieldedPoolOperation( QualifiedGroveDbOp::insert_only_op( encrypted_notes_path.clone(), cmx.to_vec(), @@ -269,31 +229,20 @@ impl DriveHighLevelOperationConverter for UnshieldTransitionAction { let new_total_balance = v0 .current_total_balance .checked_sub(v0.amount) - .expect("total balance must be >= unshield amount"); - ops.push(DriveOperation::GroveDBOperation( + .ok_or_else(|| Error::Drive( + crate::error::drive::DriveError::CorruptedDriveState( + "shielded pool total balance underflow when subtracting unshield amount".to_string(), + ), + ))?; + ops.push(DriveOperation::ShieldedPoolOperation( QualifiedGroveDbOp::insert_or_replace_op( - pool_path.clone(), + pool_path, vec![SHIELDED_TOTAL_BALANCE_KEY], Element::new_sum_item(new_total_balance as i64), ), )); - // 6. Update params with incremented checkpoint_id_counter - let new_params = ShieldedPoolParams { - checkpoint_id_counter: next_checkpoint_id, - }; - let encoded_params = - bincode::encode_to_vec(&new_params, bincode::config::standard()) - .expect("expected to encode shielded pool params"); - ops.push(DriveOperation::GroveDBOperation( - QualifiedGroveDbOp::insert_or_replace_op( - pool_path, - vec![SHIELDED_PARAMS_KEY], - Element::new_item(encoded_params), - ), - )); - - // Record anchor after batch is applied (finalization task) + // Checkpoint the commitment tree and record anchor after batch is applied ops.push(DriveOperation::FinalizeOperation( DriveOperationFinalizeTask::RecordShieldedAnchor, )); diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs index 2af560e126e..65ca2c5c246 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs @@ -14,7 +14,6 @@ impl ShieldTransitionAction { shield_amount: Credits, note_commitments: Vec<[u8; 32]>, encrypted_notes: Vec>, - current_checkpoint_id: u64, current_total_balance: Credits, ) -> ConsensusValidationResult { match value { @@ -25,7 +24,6 @@ impl ShieldTransitionAction { shield_amount, note_commitments, encrypted_notes, - current_checkpoint_id, current_total_balance, ); result.map(|action| action.into()) diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs index 43e27a99bc2..72845049af8 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs @@ -20,8 +20,6 @@ pub struct ShieldTransitionActionV0 { pub fee_strategy: AddressFundsFeeStrategy, /// fee multiplier pub user_fee_increase: UserFeeIncrease, - /// Current checkpoint ID counter read from shielded pool params - pub current_checkpoint_id: u64, /// Current total balance of the shielded pool pub current_total_balance: Credits, } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs index 7ceb8a65cba..95858478302 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs @@ -13,7 +13,6 @@ impl ShieldTransitionActionV0 { shield_amount: Credits, note_commitments: Vec<[u8; 32]>, encrypted_notes: Vec>, - current_checkpoint_id: u64, current_total_balance: Credits, ) -> ConsensusValidationResult { ConsensusValidationResult::new_with_data(ShieldTransitionActionV0 { @@ -23,7 +22,6 @@ impl ShieldTransitionActionV0 { encrypted_notes, fee_strategy: value.fee_strategy.clone(), user_fee_increase: value.user_fee_increase, - current_checkpoint_id, current_total_balance, }) } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/transformer.rs index b782b21f009..9f893364aa1 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/transformer.rs @@ -13,7 +13,6 @@ impl ShieldedTransferTransitionAction { encrypted_notes: Vec>, anchor: [u8; 32], fee_amount: Credits, - current_checkpoint_id: u64, current_total_balance: Credits, ) -> ConsensusValidationResult { match value { @@ -25,7 +24,6 @@ impl ShieldedTransferTransitionAction { encrypted_notes, anchor, fee_amount, - current_checkpoint_id, current_total_balance, ); result.map(|action| action.into()) diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs index 9c9ab122ece..55baa9c4a80 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs @@ -18,8 +18,6 @@ pub struct ShieldedTransferTransitionActionV0 { pub fee_amount: Credits, /// fee multiplier pub user_fee_increase: UserFeeIncrease, - /// Current checkpoint ID counter read from shielded pool params - pub current_checkpoint_id: u64, /// Current total balance of the shielded pool pub current_total_balance: Credits, } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs index ff971278375..32010f40835 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs @@ -12,7 +12,6 @@ impl ShieldedTransferTransitionActionV0 { encrypted_notes: Vec>, anchor: [u8; 32], fee_amount: Credits, - current_checkpoint_id: u64, current_total_balance: Credits, ) -> ConsensusValidationResult { ConsensusValidationResult::new_with_data(ShieldedTransferTransitionActionV0 { @@ -22,7 +21,6 @@ impl ShieldedTransferTransitionActionV0 { anchor, fee_amount, user_fee_increase: value.user_fee_increase, - current_checkpoint_id, current_total_balance, }) } diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/transformer.rs index c45b3306092..228658f03a3 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/unshield/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/transformer.rs @@ -12,7 +12,6 @@ impl UnshieldTransitionAction { note_commitments: Vec<[u8; 32]>, encrypted_notes: Vec>, anchor: [u8; 32], - current_checkpoint_id: u64, current_total_balance: Credits, ) -> ConsensusValidationResult { match value { @@ -23,7 +22,6 @@ impl UnshieldTransitionAction { note_commitments, encrypted_notes, anchor, - current_checkpoint_id, current_total_balance, ); result.map(|action| action.into()) diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs index 4b69433748a..0d11bebc68c 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs @@ -21,8 +21,6 @@ pub struct UnshieldTransitionActionV0 { pub anchor: [u8; 32], /// fee multiplier pub user_fee_increase: UserFeeIncrease, - /// Current checkpoint ID counter read from shielded pool params - pub current_checkpoint_id: u64, /// Current total balance of the shielded pool pub current_total_balance: Credits, } diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs index af80bf2e002..3611a4e9ab6 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs @@ -11,7 +11,6 @@ impl UnshieldTransitionActionV0 { note_commitments: Vec<[u8; 32]>, encrypted_notes: Vec>, anchor: [u8; 32], - current_checkpoint_id: u64, current_total_balance: Credits, ) -> ConsensusValidationResult { ConsensusValidationResult::new_with_data(UnshieldTransitionActionV0 { @@ -22,7 +21,6 @@ impl UnshieldTransitionActionV0 { encrypted_notes, anchor, user_fee_increase: value.user_fee_increase, - current_checkpoint_id, current_total_balance, }) } diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs b/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs index 9d5b87c13f7..361a3fc5f64 100644 --- a/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs +++ b/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs @@ -1,9 +1,11 @@ use crate::drive::shielded::paths::{ shielded_anchors_credit_pool_path, shielded_credit_pool_path, SHIELDED_COMMITMENTS_KEY, + SHIELDED_PARAMS_KEY, }; use crate::drive::Drive; use crate::error::Error; use dpp::prelude::Identifier; +use dpp::shielded::ShieldedPoolParams; use dpp::version::PlatformVersion; use grovedb::{Element, TransactionArg}; @@ -39,12 +41,59 @@ impl DriveOperationFinalizeTask { } DriveOperationFinalizeTask::RecordShieldedAnchor => { let grove_version = &platform_version.drive.grove_version; + let pool_path = shielded_credit_pool_path(); - // Get the current root hash of the commitment tree + // Read current checkpoint_id_counter from ShieldedPoolParams + let params_element = drive + .grove + .get( + &pool_path, + &[SHIELDED_PARAMS_KEY], + transaction, + grove_version, + ) + .unwrap() + .map_err(Error::from)?; + + let params_bytes = match ¶ms_element { + Element::Item(data, _) => data.as_slice(), + _ => { + return Err(Error::Drive( + crate::error::drive::DriveError::CorruptedElementType( + "shielded pool params should be an Item", + ), + )) + } + }; + + let (params, _): (ShieldedPoolParams, _) = + bincode::decode_from_slice(params_bytes, bincode::config::standard()) + .map_err(|e| { + Error::Drive(crate::error::drive::DriveError::CorruptedSerialization( + format!("could not decode shielded pool params: {e}"), + )) + })?; + + let new_checkpoint_id = params.checkpoint_id_counter + 1; + + // Create a checkpoint in the commitment tree + drive + .grove + .commitment_tree_checkpoint( + &pool_path, + &[SHIELDED_COMMITMENTS_KEY], + new_checkpoint_id, + transaction, + grove_version, + ) + .unwrap() + .map_err(Error::from)?; + + // Get the current root hash (anchor) of the commitment tree let root_hash = drive .grove .commitment_tree_root_hash( - &shielded_credit_pool_path(), + &pool_path, &[SHIELDED_COMMITMENTS_KEY], transaction, grove_version, @@ -66,6 +115,34 @@ impl DriveOperationFinalizeTask { .unwrap() .map_err(Error::from)?; + // Update ShieldedPoolParams with new checkpoint_id_counter + let new_params = ShieldedPoolParams { + checkpoint_id_counter: new_checkpoint_id, + }; + let encoded_params = + bincode::encode_to_vec(&new_params, bincode::config::standard()).map_err( + |e| { + Error::Drive( + crate::error::drive::DriveError::CorruptedSerialization(format!( + "could not encode shielded pool params: {e}" + )), + ) + }, + )?; + + drive + .grove + .insert( + &pool_path, + &[SHIELDED_PARAMS_KEY], + Element::new_item(encoded_params), + None, + transaction, + grove_version, + ) + .unwrap() + .map_err(Error::from)?; + Ok(()) } } diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/mod.rs b/packages/rs-drive/src/util/batch/drive_op_batch/mod.rs index fe5e2f79e45..0957d9c8f8e 100644 --- a/packages/rs-drive/src/util/batch/drive_op_batch/mod.rs +++ b/packages/rs-drive/src/util/batch/drive_op_batch/mod.rs @@ -90,6 +90,8 @@ pub enum DriveOperation<'a> { GroupOperation(GroupOperationType), /// An address funds operation AddressFundsOperation(AddressFundsOperationType), + /// A shielded pool operation (groveDB op with estimation cost registration) + ShieldedPoolOperation(QualifiedGroveDbOp), /// A single low level groveDB operation GroveDBOperation(QualifiedGroveDbOp), /// Multiple low level groveDB operations @@ -161,6 +163,12 @@ impl DriveLowLevelOperationConverter for DriveOperation<'_> { transaction, platform_version, ), + DriveOperation::ShieldedPoolOperation(op) => { + if let Some(ref mut estimated_costs) = estimated_costs_only_with_layer_info { + Drive::add_estimation_costs_for_shielded_pool_operations(estimated_costs); + } + Ok(vec![GroveOperation(op)]) + } DriveOperation::GroveDBOperation(op) => Ok(vec![GroveOperation(op)]), DriveOperation::GroveDBOpBatch(operations) => Ok(operations .operations diff --git a/packages/rs-platform-version/Cargo.toml b/packages/rs-platform-version/Cargo.toml index f2932c88232..01cae57e095 100644 --- a/packages/rs-platform-version/Cargo.toml +++ b/packages/rs-platform-version/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT" thiserror = { version = "2.0.12" } bincode = { version = "=2.0.1" } versioned-feature-core = { git = "https://github.com/dashpay/versioned-feature-core", version = "1.0.0" } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "219ba2e73f08a9f428c9427f7ab5c73907d670bf" } +grovedb-version = { path = "../../../grovedb/grovedb-version" } [features] mock-versions = [] diff --git a/scripts/grovedb_version_switcher.py b/scripts/grovedb_version_switcher.py index f2bf1f7258e..e1347de7e33 100644 --- a/scripts/grovedb_version_switcher.py +++ b/scripts/grovedb_version_switcher.py @@ -30,13 +30,15 @@ GROVEDB_DEPS = { "grovedb": "../../../grovedb/grovedb", - "grovedb-costs": "../../../grovedb/grovedb-costs", - "grovedb-merk": "../../../grovedb/grovedb-merk", - "grovedb-path": "../../../grovedb/grovedb-path", - "grovedb-storage": "../../../grovedb/grovedb-storage", + "grovedb-costs": "../../../grovedb/costs", + "grovedb-merk": "../../../grovedb/merk", + "grovedb-path": "../../../grovedb/path", + "grovedb-storage": "../../../grovedb/storage", "grovedb-version": "../../../grovedb/grovedb-version", - "grovedb-visualize": "../../../grovedb/grovedb-visualize", + "grovedb-visualize": "../../../grovedb/visualize", "grovedb-epoch-based-storage-flags": "../../../grovedb/grovedb-epoch-based-storage-flags", + "grovedb-commitment-tree": "../../../grovedb/grovedb-commitment-tree", + "grovedb-element": "../../../grovedb/grovedb-element", } From ce10a556c53517b59ded06135332204c93666fac Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 10 Feb 2026 12:25:09 +0000 Subject: [PATCH 07/40] more work --- Cargo.lock | 1 + packages/rs-drive-abci/Cargo.toml | 1 + .../state_transitions/shield/tests.rs | 7 +- .../shield/transform_into_action/v0/mod.rs | 1 + .../state_transitions/shielded_common/mod.rs | 45 +++++++++-- .../shielded_transfer/tests.rs | 7 +- .../transform_into_action/v0/mod.rs | 1 + .../state_transitions/unshield/tests.rs | 76 +++++++++++-------- .../unshield/transform_into_action/v0/mod.rs | 13 +++- 9 files changed, 110 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 78a75ae0925..23d7c0ec3d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1977,6 +1977,7 @@ dependencies = [ "rust_decimal_macros", "serde", "serde_json", + "sha2", "simple-signer", "strategy-tests", "tempfile", diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index ae08247b314..b1ae6974d6e 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -84,6 +84,7 @@ console-subscriber = { version = "0.4", optional = true } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f", optional = true } grovedb-commitment-tree = { path = "../../../grovedb/grovedb-commitment-tree" } orchard = "0.12" +sha2 = "0.10" nonempty = "0.11" [dev-dependencies] diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs index 60dce515a4a..65595fe3c97 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs @@ -1,6 +1,7 @@ #[cfg(test)] mod tests { use crate::config::{PlatformConfig, PlatformTestConfig}; + use crate::execution::validation::state_transition::state_transitions::shielded_common::compute_platform_sighash; use crate::execution::validation::state_transition::state_transitions::test_helpers::{ create_dummy_witness, create_platform_address, setup_address_with_balance, TestAddressSigner, @@ -950,7 +951,8 @@ mod tests { let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); - let sighash = unauthorized.commitment().into(); + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &[]); let proven = unauthorized .create_proof(pk, &mut rng) .unwrap(); @@ -1141,7 +1143,8 @@ mod tests { .unwrap(); let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); - let sighash = unauthorized.commitment().into(); + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &[]); let proven = unauthorized.create_proof(pk, &mut rng).unwrap(); let bundle = proven.apply_signatures(rng, sighash, &[]).unwrap(); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs index fa2837b3e68..069f19da38c 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs @@ -111,6 +111,7 @@ impl ShieldStateTransitionTransformIntoActionValidationV0 for ShieldTransition { anchor, proof, binding_signature, + &[], // No transparent fields to bind for shield ) { let penalty = platform_version .drive_abci diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs index d95685d4c92..4a3c9b7efda 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs @@ -7,6 +7,7 @@ use grovedb_commitment_tree::{ use orchard::note::TransmittedNoteCiphertext; use orchard::primitives::redpallas; use orchard::value::ValueCommitment; +use sha2::{Digest, Sha256}; use std::sync::OnceLock; /// Cached verifying key for shielded proof verification. @@ -24,6 +25,30 @@ const ENC_CIPHERTEXT_SIZE: usize = 580; const OUT_CIPHERTEXT_SIZE: usize = 80; const ENCRYPTED_NOTE_SIZE: usize = EPK_SIZE + ENC_CIPHERTEXT_SIZE + OUT_CIPHERTEXT_SIZE; // 692 +/// Domain separator for Platform sighash computation. +const SIGHASH_DOMAIN: &[u8] = b"DashPlatformSighash"; + +/// Computes the platform sighash from an Orchard bundle commitment and optional +/// transparent field data. +/// +/// The sighash is computed as: +/// `SHA-256(SIGHASH_DOMAIN || bundle_commitment || extra_data)` +/// +/// This binds transparent state transition fields (like `output_address` and `amount` +/// in unshield transitions) to the Orchard signatures, preventing replay attacks +/// where an attacker substitutes transparent fields while reusing a valid Orchard bundle. +/// +/// The same computation must be used on both the signing (client) and verification +/// (platform) sides. For transitions without transparent fields (shield and +/// shielded_transfer), `extra_data` is empty. +pub fn compute_platform_sighash(bundle_commitment: &[u8; 32], extra_data: &[u8]) -> [u8; 32] { + let mut hasher = Sha256::new(); + hasher.update(SIGHASH_DOMAIN); + hasher.update(bundle_commitment); + hasher.update(extra_data); + hasher.finalize().into() +} + /// Reconstructs an orchard `Bundle` from the serialized fields /// of a shielded state transition and verifies the Halo 2 ZK proof along with /// all RedPallas signatures (spend auth + binding). @@ -33,9 +58,14 @@ const ENCRYPTED_NOTE_SIZE: usize = EPK_SIZE + ENC_CIPHERTEXT_SIZE + OUT_CIPHERTE /// 2. Spend authorization signatures (proves the spender controls the spending key) /// 3. The binding signature (binds value_balance to value commitments, preventing manipulation) /// -/// The sighash used for signature verification is derived from `bundle.commitment()`, -/// which is the Orchard bundle commitment (BLAKE2b-256 hash of the bundle's non-authorization -/// data per ZIP-244). This same value must be used when signing the bundle on the client side. +/// The sighash is computed via `compute_platform_sighash()`, which hashes the +/// Orchard bundle commitment together with `extra_sighash_data` (transparent fields). +/// The same computation must be used when signing the bundle on the client side. +/// +/// `extra_sighash_data` binds transparent fields to the Orchard signatures: +/// - Shield: empty (no transparent outputs) +/// - Shielded transfer: empty (no transparent fields) +/// - Unshield: `output_address.to_bytes() || amount.to_le_bytes()` /// /// Returns `Ok(())` if all verification passes, or an `InvalidShieldedProofError` /// if reconstruction or any verification step fails. @@ -46,6 +76,7 @@ pub fn reconstruct_and_verify_bundle( anchor: &[u8; 32], proof: &[u8], binding_signature: &[u8], + extra_sighash_data: &[u8], ) -> Result<(), InvalidShieldedProofError> { let vk = get_verifying_key(); @@ -141,11 +172,13 @@ pub fn reconstruct_and_verify_bundle( authorized, ); - // Compute the sighash from the bundle's non-authorization data. - // This uses the Orchard BundleCommitment (BLAKE2b-256 per ZIP-244), + // Compute the platform sighash: SHA-256(domain || bundle_commitment || extra_data). + // The bundle commitment is the Orchard BundleCommitment (BLAKE2b-256 per ZIP-244), // covering: flags, value_balance, anchor, and all action fields // (nullifier, rk, cmx, cv_net, encrypted_note) — but NOT the signatures or proof. - let sighash: [u8; 32] = bundle.commitment().into(); + // The extra_sighash_data binds transparent fields (e.g., output_address for unshield). + let bundle_commitment: [u8; 32] = bundle.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, extra_sighash_data); // Verify the Halo 2 proof AND all RedPallas signatures (spend auth + binding) // using BatchValidator. This is the correct Orchard verification flow, ensuring: diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs index ce131e911e8..379ec66978e 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs @@ -1,6 +1,7 @@ #[cfg(test)] mod tests { use crate::config::{PlatformConfig, PlatformTestConfig}; + use crate::execution::validation::state_transition::state_transitions::shielded_common::compute_platform_sighash; use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; use crate::test::helpers::setup::TestPlatformBuilder; use assert_matches::assert_matches; @@ -559,7 +560,8 @@ mod tests { .unwrap(); let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); - let sighash = unauthorized.commitment().into(); + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &[]); let proven = unauthorized.create_proof(pk, &mut rng).unwrap(); let bundle = proven.apply_signatures(rng, sighash, &[ask]).unwrap(); @@ -724,7 +726,8 @@ mod tests { .unwrap(); let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); - let sighash = unauthorized.commitment().into(); + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &[]); let proven = unauthorized.create_proof(pk, &mut rng).unwrap(); let bundle = proven.apply_signatures(rng, sighash, &[ask]).unwrap(); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs index 3984f5e3d87..1a580c5461e 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs @@ -131,6 +131,7 @@ impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 for Shielded &anchor, st_proof, st_binding_sig, + &[], // No transparent fields to bind for shielded transfer ) { return Ok(ConsensusValidationResult::new_with_error( StateError::InvalidShieldedProofError(e).into(), diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs index b84e3116693..9e7968b13cc 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs @@ -1,6 +1,7 @@ #[cfg(test)] mod tests { use crate::config::{PlatformConfig, PlatformTestConfig}; + use crate::execution::validation::state_transition::state_transitions::shielded_common::compute_platform_sighash; use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; use crate::test::helpers::setup::TestPlatformBuilder; use assert_matches::assert_matches; @@ -665,7 +666,15 @@ mod tests { .unwrap(); let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); - let sighash = unauthorized.commitment().into(); + + // Compute platform sighash binding transparent fields (output_address, amount) + let output_address = create_output_address(); + let amount = 5_000u64; // = value_balance (no fee difference) + let mut extra_sighash_data = output_address.to_bytes(); + extra_sighash_data.extend_from_slice(&amount.to_le_bytes()); + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &extra_sighash_data); + let proven = unauthorized.create_proof(pk, &mut rng).unwrap(); let bundle = proven.apply_signatures(rng, sighash, &[ask]).unwrap(); @@ -686,8 +695,8 @@ mod tests { // --- Create and process transition --- // amount = value_balance (no fee difference) let transition = create_unshield_transition( - create_output_address(), - value_balance as u64, // amount = 5000 + output_address, + amount, // amount = 5000 actions, flags, value_balance, @@ -795,8 +804,10 @@ mod tests { } /// Build a valid Orchard bundle for unshield tests (spend > output). + /// The `output_address` and `amount` are bound to the sighash so that + /// the resulting bundle can only be used with those specific transparent fields. /// Returns (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig). - fn build_valid_unshield_bundle() -> (Vec, u8, i64, [u8; 32], Vec, Vec) { + fn build_valid_unshield_bundle(output_address: &PlatformAddress, amount: u64) -> (Vec, u8, i64, [u8; 32], Vec, Vec) { let mut rng = OsRng; let pk = get_proving_key(); @@ -835,7 +846,13 @@ mod tests { .unwrap(); let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); - let sighash = unauthorized.commitment().into(); + + // Bind transparent fields (output_address, amount) to the sighash + let mut extra_sighash_data = output_address.to_bytes(); + extra_sighash_data.extend_from_slice(&amount.to_le_bytes()); + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &extra_sighash_data); + let proven = unauthorized.create_proof(pk, &mut rng).unwrap(); let bundle = proven.apply_signatures(rng, sighash, &[ask]).unwrap(); @@ -856,8 +873,11 @@ mod tests { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + // Bundle is signed for create_output_address() with amount = 5000 + let output_address = create_output_address(); + let signed_amount = 5_000u64; let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = - build_valid_unshield_bundle(); + build_valid_unshield_bundle(&output_address, signed_amount); assert_eq!(value_balance, 5_000); // ATTACK: Inflate value_balance from 5000 to 9000 @@ -868,7 +888,7 @@ mod tests { insert_anchor_into_state(&platform, &anchor_bytes); let transition = create_unshield_transition( - create_output_address(), + output_address, mutated_value_balance as u64, // amount = 9000 (inflated) actions, flags, @@ -890,31 +910,25 @@ mod tests { ); } - /// AUDIT FINDING (STILL OPEN): Transparent fields (output_address, amount) - /// are not bound to the Orchard bundle via sighash. + /// AUDIT REGRESSION: Different output_address is now caught by platform sighash. /// - /// An attacker who observes a valid unshield bundle can create a new - /// unshield transition with a different output_address, redirecting - /// funds to their own address. The nullifiers prevent double-spending, - /// but this enables front-running: the attacker's transaction (with - /// their address) could be included before the victim's. + /// Previously, the output_address was not bound to the Orchard bundle via + /// sighash, allowing an attacker to substitute a different address while + /// reusing a valid bundle. Now `compute_platform_sighash()` includes the + /// output_address and amount in the sighash, so changing the address causes + /// signature verification to fail. /// - /// Note: The binding and spend auth signature fixes (BatchValidator) do - /// NOT fix this — the output_address is outside the Orchard bundle, so - /// changing it does not affect the sighash or any signatures. The bundle - /// remains cryptographically valid with a different output_address. - /// - /// Mitigation requires binding transparent fields to the sighash - /// (e.g., including them in the bundle commitment computation). - /// - /// Severity: HIGH (requires separate fix) + /// Original severity: HIGH — now FIXED. #[test] - fn test_different_output_address_with_same_valid_bundle_is_accepted() { + fn test_different_output_address_with_same_valid_bundle_is_rejected() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + // Bundle is signed for the ORIGINAL address with amount = 5000 + let original_address = create_output_address(); + let amount = 5_000u64; let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = - build_valid_unshield_bundle(); + build_valid_unshield_bundle(&original_address, amount); assert_eq!(value_balance, 5_000); set_pool_total_balance(&platform, 20_000); @@ -925,7 +939,7 @@ mod tests { let transition = create_unshield_transition( attacker_address, // ATTACKER's address, not the original recipient - value_balance as u64, + amount, actions, flags, value_balance, @@ -937,12 +951,14 @@ mod tests { let processing_result = process_transition(&platform, transition, platform_version); - // VULNERABILITY: Succeeds because the output_address is not bound - // to the Orchard bundle via sighash or any other mechanism. - // The attacker redirects the unshielded funds to their own address. + // FIXED: Platform sighash includes output_address, so changing it + // causes the sighash to differ from the one used during signing, + // and signature verification fails. assert_matches!( processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::SuccessfulExecution { .. }] + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] ); } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs index f808af740b1..4789214599a 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs @@ -107,17 +107,25 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti } } - // Verify the ZK proof - let (st_actions, st_flags, st_value_balance, st_proof, st_binding_sig) = match self { + // Verify the ZK proof, binding transparent fields to the sighash + let (st_actions, st_flags, st_value_balance, st_proof, st_binding_sig, output_address, amount) = match self { UnshieldTransition::V0(v0) => ( &v0.actions, v0.flags, v0.value_balance, v0.proof.as_slice(), v0.binding_signature.as_slice(), + v0.output_address, + v0.amount, ), }; + // Serialize transparent fields to bind them to the Orchard sighash. + // This prevents an attacker from substituting a different output_address + // or amount while reusing a valid Orchard bundle. + let mut extra_sighash_data = output_address.to_bytes(); + extra_sighash_data.extend_from_slice(&amount.to_le_bytes()); + if let Err(e) = reconstruct_and_verify_bundle( st_actions, st_flags, @@ -125,6 +133,7 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti &anchor, st_proof, st_binding_sig, + &extra_sighash_data, ) { return Ok(ConsensusValidationResult::new_with_error( StateError::InvalidShieldedProofError(e).into(), From f2c238ac11754e63d84322db6ecde3bd95b02a9d Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 11 Feb 2026 00:23:08 +0000 Subject: [PATCH 08/40] more work --- packages/dapi-grpc/build.rs | 12 +- .../protos/platform/v0/platform.proto | 102 +++++ packages/rs-dapi-client/src/transport/grpc.rs | 36 ++ .../src/errors/consensus/basic/basic_error.rs | 28 +- .../consensus/basic/state_transition/mod.rs | 12 + .../shielded_empty_proof_error.rs | 37 ++ .../shielded_invalid_value_balance_error.rs | 36 ++ .../shielded_no_actions_error.rs | 37 ++ .../shielded_zero_anchor_error.rs | 37 ++ .../unshield_amount_zero_error.rs | 37 ++ ...shield_value_balance_below_amount_error.rs | 44 +++ packages/rs-dpp/src/errors/consensus/codes.rs | 6 + packages/rs-dpp/src/shielded/mod.rs | 77 +++- packages/rs-dpp/src/state_transition/mod.rs | 77 +++- .../state_transition_types.rs | 2 + .../state_transitions/shielded/mod.rs | 2 + .../shield_from_asset_lock_transition/mod.rs | 58 +++ .../proved.rs | 27 ++ ...ate_transition_estimated_fee_validation.rs | 22 ++ .../state_transition_like.rs | 77 ++++ .../state_transition_validation.rs | 15 + .../v0/mod.rs | 54 +++ .../v0/proved.rs | 18 + .../v0/state_transition_like.rs | 68 ++++ .../v0/state_transition_validation.rs | 43 +++ .../v0/types.rs | 16 + .../v0/version.rs | 9 + .../version.rs | 11 + .../shielded/shield_transition/v0/mod.rs | 10 +- .../v0/state_transition_validation.rs | 45 +-- .../shielded_transfer_transition/v0/mod.rs | 6 +- .../v0/state_transition_validation.rs | 51 +-- .../shielded_withdrawal_transition/mod.rs | 60 +++ ...ate_transition_estimated_fee_validation.rs | 16 + .../state_transition_like.rs | 47 +++ .../state_transition_validation.rs | 15 + .../shielded_withdrawal_transition/v0/mod.rs | 56 +++ .../v0/state_transition_like.rs | 51 +++ .../v0/state_transition_validation.rs | 68 ++++ .../v0/types.rs | 16 + .../v0/version.rs | 9 + .../shielded_withdrawal_transition/version.rs | 11 + .../shielded/unshield_transition/v0/mod.rs | 5 +- .../v0/state_transition_validation.rs | 61 +-- .../execution/types/execution_event/mod.rs | 21 ++ .../traits/address_balances_and_nonces.rs | 8 +- .../processor/traits/address_witnesses.rs | 8 +- .../traits/addresses_minimum_balance.rs | 8 +- .../processor/traits/basic_structure.rs | 10 +- .../processor/traits/identity_balance.rs | 4 +- .../traits/identity_based_signature.rs | 12 +- .../processor/traits/identity_nonces.rs | 8 +- .../processor/traits/is_allowed.rs | 8 +- .../processor/traits/state.rs | 14 +- .../state_transition/state_transitions/mod.rs | 4 + .../state_transitions/shield/tests.rs | 119 ++---- .../shield/transform_into_action/v0/mod.rs | 2 +- .../shield_from_asset_lock/mod.rs | 64 ++++ .../transform_into_action/mod.rs | 1 + .../transform_into_action/v0/mod.rs | 355 ++++++++++++++++++ .../state_transitions/shielded_common/mod.rs | 21 +- .../shielded_transfer/tests.rs | 97 ++--- .../transform_into_action/v0/mod.rs | 2 +- .../shielded_withdrawal/mod.rs | 51 +++ .../transform_into_action/mod.rs | 1 + .../transform_into_action/v0/mod.rs | 191 ++++++++++ .../state_transitions/unshield/tests.rs | 109 ++---- .../unshield/transform_into_action/v0/mod.rs | 2 +- .../state_transition/transformer/mod.rs | 19 + packages/rs-drive-abci/src/query/mod.rs | 1 + packages/rs-drive-abci/src/query/service.rs | 51 +++ .../src/query/shielded/anchors/mod.rs | 63 ++++ .../src/query/shielded/anchors/v0/mod.rs | 77 ++++ .../src/query/shielded/encrypted_notes/mod.rs | 65 ++++ .../query/shielded/encrypted_notes/v0/mod.rs | 121 ++++++ .../rs-drive-abci/src/query/shielded/mod.rs | 4 + .../src/query/shielded/nullifiers/mod.rs | 63 ++++ .../src/query/shielded/nullifiers/v0/mod.rs | 115 ++++++ .../src/query/shielded/pool_state/mod.rs | 63 ++++ .../src/query/shielded/pool_state/v0/mod.rs | 77 ++++ packages/rs-drive-proof-verifier/src/proof.rs | 173 +++++++++ packages/rs-drive-proof-verifier/src/types.rs | 87 +++++ .../prove/prove_state_transition/v0/mod.rs | 4 +- .../action_convert_to_operations/mod.rs | 8 + .../shielded/mod.rs | 192 +++++++++- .../src/state_transition_action/mod.rs | 12 + .../state_transition_action/shielded/mod.rs | 4 + .../shielded/shield_from_asset_lock/mod.rs | 67 ++++ .../shield_from_asset_lock/transformer.rs | 35 ++ .../shielded/shield_from_asset_lock/v0/mod.rs | 25 ++ .../shield_from_asset_lock/v0/transformer.rs | 29 ++ .../shielded/shielded_withdrawal/mod.rs | 92 +++++ .../shielded_withdrawal/transformer.rs | 33 ++ .../shielded/shielded_withdrawal/v0/mod.rs | 34 ++ .../shielded_withdrawal/v0/transformer.rs | 78 ++++ .../partially_use_asset_lock_action/mod.rs | 5 +- .../partially_use_asset_lock_action/v0/mod.rs | 1 + packages/rs-drive/src/verify/mod.rs | 2 + packages/rs-drive/src/verify/shielded/mod.rs | 8 + .../shielded/verify_shielded_anchors/mod.rs | 30 ++ .../verify_shielded_anchors/v0/mod.rs | 35 ++ .../verify_shielded_encrypted_notes/mod.rs | 39 ++ .../verify_shielded_encrypted_notes/v0/mod.rs | 58 +++ .../verify_shielded_nullifiers/mod.rs | 31 ++ .../verify_shielded_nullifiers/v0/mod.rs | 43 +++ .../verify_shielded_pool_state/mod.rs | 30 ++ .../verify_shielded_pool_state/v0/mod.rs | 58 +++ .../v0/mod.rs | 10 +- .../mod.rs | 2 + .../v1.rs | 10 + .../v2.rs | 10 + .../drive_abci_query_versions/mod.rs | 9 + .../drive_abci_query_versions/v1.rs | 28 +- .../drive_abci_validation_versions/mod.rs | 2 + .../drive_abci_validation_versions/v1.rs | 16 + .../drive_abci_validation_versions/v2.rs | 16 + .../drive_abci_validation_versions/v3.rs | 16 + .../drive_abci_validation_versions/v4.rs | 16 + .../drive_abci_validation_versions/v5.rs | 16 + .../drive_abci_validation_versions/v6.rs | 16 + .../drive_abci_validation_versions/v7.rs | 16 + .../drive_verify_method_versions/mod.rs | 9 + .../drive_verify_method_versions/v1.rs | 11 +- .../src/version/mocks/v2_test.rs | 28 +- packages/rs-sdk/src/mock/requests.rs | 11 +- packages/rs-sdk/src/platform/fetch.rs | 16 + packages/rs-sdk/src/platform/query.rs | 76 +++- packages/rs-sdk/src/platform/types.rs | 1 + .../rs-sdk/src/platform/types/shielded.rs | 70 ++++ 129 files changed, 4525 insertions(+), 459 deletions(-) create mode 100644 packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_empty_proof_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_invalid_value_balance_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_no_actions_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_zero_anchor_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/state_transition/unshield_amount_zero_error.rs create mode 100644 packages/rs-dpp/src/errors/consensus/basic/state_transition/unshield_value_balance_below_amount_error.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/proved.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/state_transition_estimated_fee_validation.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/state_transition_like.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/state_transition_validation.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/proved.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_like.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_validation.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/types.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/version.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/version.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/state_transition_estimated_fee_validation.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/state_transition_like.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/state_transition_validation.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_like.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_validation.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/types.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/version.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/version.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/query/shielded/anchors/mod.rs create mode 100644 packages/rs-drive-abci/src/query/shielded/anchors/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/query/shielded/encrypted_notes/mod.rs create mode 100644 packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/query/shielded/mod.rs create mode 100644 packages/rs-drive-abci/src/query/shielded/nullifiers/mod.rs create mode 100644 packages/rs-drive-abci/src/query/shielded/nullifiers/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/query/shielded/pool_state/mod.rs create mode 100644 packages/rs-drive-abci/src/query/shielded/pool_state/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/transformer.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/transformer.rs create mode 100644 packages/rs-drive/src/verify/shielded/mod.rs create mode 100644 packages/rs-drive/src/verify/shielded/verify_shielded_anchors/mod.rs create mode 100644 packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs create mode 100644 packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/mod.rs create mode 100644 packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs create mode 100644 packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/mod.rs create mode 100644 packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/v0/mod.rs create mode 100644 packages/rs-drive/src/verify/shielded/verify_shielded_pool_state/mod.rs create mode 100644 packages/rs-drive/src/verify/shielded/verify_shielded_pool_state/v0/mod.rs create mode 100644 packages/rs-sdk/src/platform/types/shielded.rs diff --git a/packages/dapi-grpc/build.rs b/packages/dapi-grpc/build.rs index c94bc77a59c..77431d20c8c 100644 --- a/packages/dapi-grpc/build.rs +++ b/packages/dapi-grpc/build.rs @@ -84,7 +84,7 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig { // Derive features for versioned messages // // "GetConsensusParamsRequest" is excluded as this message does not support proofs - const VERSIONED_REQUESTS: [&str; 48] = [ + const VERSIONED_REQUESTS: [&str; 52] = [ "GetDataContractHistoryRequest", "GetDataContractRequest", "GetDataContractsRequest", @@ -133,6 +133,10 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig { "GetAddressesInfosRequest", "GetRecentAddressBalanceChangesRequest", "GetRecentCompactedAddressBalanceChangesRequest", + "GetShieldedEncryptedNotesRequest", + "GetShieldedAnchorsRequest", + "GetShieldedPoolStateRequest", + "GetShieldedNullifiersRequest", ]; const PROOF_ONLY_VERSIONED_REQUESTS: [&str; 1] = ["GetAddressesTrunkStateRequest"]; @@ -147,7 +151,7 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig { // - "GetIdentityByNonUniquePublicKeyHashResponse" // // "GetEvonodesProposedEpochBlocksResponse" is used for 2 Requests - const VERSIONED_RESPONSES: [&str; 46] = [ + const VERSIONED_RESPONSES: [&str; 50] = [ "GetDataContractHistoryResponse", "GetDataContractResponse", "GetDataContractsResponse", @@ -194,6 +198,10 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig { "GetAddressesInfosResponse", "GetRecentAddressBalanceChangesResponse", "GetRecentCompactedAddressBalanceChangesResponse", + "GetShieldedEncryptedNotesResponse", + "GetShieldedAnchorsResponse", + "GetShieldedPoolStateResponse", + "GetShieldedNullifiersResponse", ]; const PROOF_ONLY_VERSIONED_RESPONSES: [&str; 1] = ["GetAddressesTrunkStateResponse"]; diff --git a/packages/dapi-grpc/protos/platform/v0/platform.proto b/packages/dapi-grpc/protos/platform/v0/platform.proto index 9e4bc8f5d48..2611acb8b39 100644 --- a/packages/dapi-grpc/protos/platform/v0/platform.proto +++ b/packages/dapi-grpc/protos/platform/v0/platform.proto @@ -116,6 +116,14 @@ service Platform { returns (GetRecentAddressBalanceChangesResponse); rpc getRecentCompactedAddressBalanceChanges(GetRecentCompactedAddressBalanceChangesRequest) returns (GetRecentCompactedAddressBalanceChangesResponse); + rpc getShieldedEncryptedNotes(GetShieldedEncryptedNotesRequest) + returns (GetShieldedEncryptedNotesResponse); + rpc getShieldedAnchors(GetShieldedAnchorsRequest) + returns (GetShieldedAnchorsResponse); + rpc getShieldedPoolState(GetShieldedPoolStateRequest) + returns (GetShieldedPoolStateResponse); + rpc getShieldedNullifiers(GetShieldedNullifiersRequest) + returns (GetShieldedNullifiersResponse); } // Proof message includes cryptographic proofs for validating responses @@ -2125,3 +2133,97 @@ message GetRecentCompactedAddressBalanceChangesResponse { } oneof version { GetRecentCompactedAddressBalanceChangesResponseV0 v0 = 1; } } + +// --- Shielded Pool Queries --- + +message GetShieldedEncryptedNotesRequest { + message GetShieldedEncryptedNotesRequestV0 { + bytes start_cmx = 1; + uint32 count = 2; + bool prove = 3; + } + oneof version { GetShieldedEncryptedNotesRequestV0 v0 = 1; } +} + +message GetShieldedEncryptedNotesResponse { + message GetShieldedEncryptedNotesResponseV0 { + message EncryptedNote { + bytes cmx = 1; + bytes encrypted_note = 2; + } + message EncryptedNotes { + repeated EncryptedNote entries = 1; + } + oneof result { + EncryptedNotes encrypted_notes = 1; + Proof proof = 2; + } + ResponseMetadata metadata = 3; + } + oneof version { GetShieldedEncryptedNotesResponseV0 v0 = 1; } +} + +message GetShieldedAnchorsRequest { + message GetShieldedAnchorsRequestV0 { + bool prove = 1; + } + oneof version { GetShieldedAnchorsRequestV0 v0 = 1; } +} + +message GetShieldedAnchorsResponse { + message GetShieldedAnchorsResponseV0 { + message Anchors { + repeated bytes anchors = 1; + } + oneof result { + Anchors anchors = 1; + Proof proof = 2; + } + ResponseMetadata metadata = 3; + } + oneof version { GetShieldedAnchorsResponseV0 v0 = 1; } +} + +message GetShieldedPoolStateRequest { + message GetShieldedPoolStateRequestV0 { + bool prove = 1; + } + oneof version { GetShieldedPoolStateRequestV0 v0 = 1; } +} + +message GetShieldedPoolStateResponse { + message GetShieldedPoolStateResponseV0 { + oneof result { + uint64 total_balance = 1 [jstype = JS_STRING]; + Proof proof = 2; + } + ResponseMetadata metadata = 3; + } + oneof version { GetShieldedPoolStateResponseV0 v0 = 1; } +} + +message GetShieldedNullifiersRequest { + message GetShieldedNullifiersRequestV0 { + repeated bytes nullifiers = 1; + bool prove = 2; + } + oneof version { GetShieldedNullifiersRequestV0 v0 = 1; } +} + +message GetShieldedNullifiersResponse { + message GetShieldedNullifiersResponseV0 { + message NullifierStatus { + bytes nullifier = 1; + bool is_spent = 2; + } + message NullifierStatuses { + repeated NullifierStatus entries = 1; + } + oneof result { + NullifierStatuses nullifier_statuses = 1; + Proof proof = 2; + } + ResponseMetadata metadata = 3; + } + oneof version { GetShieldedNullifiersResponseV0 v0 = 1; } +} diff --git a/packages/rs-dapi-client/src/transport/grpc.rs b/packages/rs-dapi-client/src/transport/grpc.rs index 56abd9241dd..61ba91046ad 100644 --- a/packages/rs-dapi-client/src/transport/grpc.rs +++ b/packages/rs-dapi-client/src/transport/grpc.rs @@ -452,6 +452,42 @@ impl_transport_request_grpc!( get_current_quorums_info ); +// rpc getShieldedEncryptedNotes(GetShieldedEncryptedNotesRequest) returns (GetShieldedEncryptedNotesResponse); +impl_transport_request_grpc!( + platform_proto::GetShieldedEncryptedNotesRequest, + platform_proto::GetShieldedEncryptedNotesResponse, + PlatformGrpcClient, + RequestSettings::default(), + get_shielded_encrypted_notes +); + +// rpc getShieldedAnchors(GetShieldedAnchorsRequest) returns (GetShieldedAnchorsResponse); +impl_transport_request_grpc!( + platform_proto::GetShieldedAnchorsRequest, + platform_proto::GetShieldedAnchorsResponse, + PlatformGrpcClient, + RequestSettings::default(), + get_shielded_anchors +); + +// rpc getShieldedPoolState(GetShieldedPoolStateRequest) returns (GetShieldedPoolStateResponse); +impl_transport_request_grpc!( + platform_proto::GetShieldedPoolStateRequest, + platform_proto::GetShieldedPoolStateResponse, + PlatformGrpcClient, + RequestSettings::default(), + get_shielded_pool_state +); + +// rpc getShieldedNullifiers(GetShieldedNullifiersRequest) returns (GetShieldedNullifiersResponse); +impl_transport_request_grpc!( + platform_proto::GetShieldedNullifiersRequest, + platform_proto::GetShieldedNullifiersResponse, + PlatformGrpcClient, + RequestSettings::default(), + get_shielded_nullifiers +); + // Link to each core gRPC request what client and method to use: impl_transport_request_grpc!( diff --git a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs index db5d518eb93..74732d4c69d 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs @@ -77,10 +77,12 @@ use crate::consensus::basic::state_transition::{ InputWitnessCountMismatchError, InputsNotLessThanOutputsError, InsufficientFundingAmountError, InvalidRemainderOutputCountError, InvalidStateTransitionTypeError, MissingStateTransitionTypeError, OutputAddressAlsoInputError, OutputBelowMinimumError, - OutputsNotGreaterThanInputsError, StateTransitionMaxSizeExceededError, - StateTransitionNotActiveError, TransitionNoInputsError, TransitionNoOutputsError, - TransitionOverMaxInputsError, TransitionOverMaxOutputsError, WithdrawalBalanceMismatchError, - WithdrawalBelowMinAmountError, + OutputsNotGreaterThanInputsError, ShieldedEmptyProofError, + ShieldedInvalidValueBalanceError, ShieldedNoActionsError, ShieldedZeroAnchorError, + StateTransitionMaxSizeExceededError, StateTransitionNotActiveError, TransitionNoInputsError, + TransitionNoOutputsError, TransitionOverMaxInputsError, TransitionOverMaxOutputsError, + UnshieldAmountZeroError, UnshieldValueBalanceBelowAmountError, + WithdrawalBalanceMismatchError, WithdrawalBelowMinAmountError, }; use crate::consensus::basic::{ IncompatibleProtocolVersionError, UnsupportedFeatureError, UnsupportedProtocolVersionError, @@ -657,6 +659,24 @@ pub enum BasicError { #[error(transparent)] OutputAddressAlsoInputError(OutputAddressAlsoInputError), + + #[error(transparent)] + ShieldedNoActionsError(ShieldedNoActionsError), + + #[error(transparent)] + ShieldedEmptyProofError(ShieldedEmptyProofError), + + #[error(transparent)] + ShieldedZeroAnchorError(ShieldedZeroAnchorError), + + #[error(transparent)] + ShieldedInvalidValueBalanceError(ShieldedInvalidValueBalanceError), + + #[error(transparent)] + UnshieldAmountZeroError(UnshieldAmountZeroError), + + #[error(transparent)] + UnshieldValueBalanceBelowAmountError(UnshieldValueBalanceBelowAmountError), } impl From for ConsensusError { diff --git a/packages/rs-dpp/src/errors/consensus/basic/state_transition/mod.rs b/packages/rs-dpp/src/errors/consensus/basic/state_transition/mod.rs index a7c02e2db76..210619362f6 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/state_transition/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/state_transition/mod.rs @@ -19,6 +19,12 @@ mod transition_no_inputs_error; mod transition_no_outputs_error; mod transition_over_max_inputs_error; mod transition_over_max_outputs_error; +mod shielded_empty_proof_error; +mod shielded_invalid_value_balance_error; +mod shielded_no_actions_error; +mod shielded_zero_anchor_error; +mod unshield_amount_zero_error; +mod unshield_value_balance_below_amount_error; mod withdrawal_balance_mismatch_error; mod withdrawal_below_min_amount_error; @@ -43,5 +49,11 @@ pub use transition_no_inputs_error::*; pub use transition_no_outputs_error::*; pub use transition_over_max_inputs_error::*; pub use transition_over_max_outputs_error::*; +pub use shielded_empty_proof_error::*; +pub use shielded_invalid_value_balance_error::*; +pub use shielded_no_actions_error::*; +pub use shielded_zero_anchor_error::*; +pub use unshield_amount_zero_error::*; +pub use unshield_value_balance_below_amount_error::*; pub use withdrawal_balance_mismatch_error::*; pub use withdrawal_below_min_amount_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_empty_proof_error.rs b/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_empty_proof_error.rs new file mode 100644 index 00000000000..93204cdd3bf --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_empty_proof_error.rs @@ -0,0 +1,37 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Shielded transition proof must not be empty")] +#[platform_serialize(unversioned)] +pub struct ShieldedEmptyProofError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ +} + +impl ShieldedEmptyProofError { + pub fn new() -> Self { + Self {} + } +} + +impl Default for ShieldedEmptyProofError { + fn default() -> Self { + Self::new() + } +} + +impl From for ConsensusError { + fn from(err: ShieldedEmptyProofError) -> Self { + Self::BasicError(BasicError::ShieldedEmptyProofError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_invalid_value_balance_error.rs b/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_invalid_value_balance_error.rs new file mode 100644 index 00000000000..ea73a426d46 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_invalid_value_balance_error.rs @@ -0,0 +1,36 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Invalid shielded value_balance: {message}")] +#[platform_serialize(unversioned)] +pub struct ShieldedInvalidValueBalanceError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + message: String, +} + +impl ShieldedInvalidValueBalanceError { + pub fn new(message: String) -> Self { + Self { message } + } + + pub fn message(&self) -> &str { + &self.message + } +} + +impl From for ConsensusError { + fn from(err: ShieldedInvalidValueBalanceError) -> Self { + Self::BasicError(BasicError::ShieldedInvalidValueBalanceError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_no_actions_error.rs b/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_no_actions_error.rs new file mode 100644 index 00000000000..c1ebe75b5f7 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_no_actions_error.rs @@ -0,0 +1,37 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Shielded transition must have at least one action")] +#[platform_serialize(unversioned)] +pub struct ShieldedNoActionsError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ +} + +impl ShieldedNoActionsError { + pub fn new() -> Self { + Self {} + } +} + +impl Default for ShieldedNoActionsError { + fn default() -> Self { + Self::new() + } +} + +impl From for ConsensusError { + fn from(err: ShieldedNoActionsError) -> Self { + Self::BasicError(BasicError::ShieldedNoActionsError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_zero_anchor_error.rs b/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_zero_anchor_error.rs new file mode 100644 index 00000000000..10761119e9c --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_zero_anchor_error.rs @@ -0,0 +1,37 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Shielded transition anchor must not be all zeros")] +#[platform_serialize(unversioned)] +pub struct ShieldedZeroAnchorError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ +} + +impl ShieldedZeroAnchorError { + pub fn new() -> Self { + Self {} + } +} + +impl Default for ShieldedZeroAnchorError { + fn default() -> Self { + Self::new() + } +} + +impl From for ConsensusError { + fn from(err: ShieldedZeroAnchorError) -> Self { + Self::BasicError(BasicError::ShieldedZeroAnchorError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/state_transition/unshield_amount_zero_error.rs b/packages/rs-dpp/src/errors/consensus/basic/state_transition/unshield_amount_zero_error.rs new file mode 100644 index 00000000000..4d0a618c73f --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/state_transition/unshield_amount_zero_error.rs @@ -0,0 +1,37 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Unshield transition amount must be greater than zero")] +#[platform_serialize(unversioned)] +pub struct UnshieldAmountZeroError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ +} + +impl UnshieldAmountZeroError { + pub fn new() -> Self { + Self {} + } +} + +impl Default for UnshieldAmountZeroError { + fn default() -> Self { + Self::new() + } +} + +impl From for ConsensusError { + fn from(err: UnshieldAmountZeroError) -> Self { + Self::BasicError(BasicError::UnshieldAmountZeroError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/basic/state_transition/unshield_value_balance_below_amount_error.rs b/packages/rs-dpp/src/errors/consensus/basic/state_transition/unshield_value_balance_below_amount_error.rs new file mode 100644 index 00000000000..910eea46de0 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/state_transition/unshield_value_balance_below_amount_error.rs @@ -0,0 +1,44 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error("Unshield value_balance ({value_balance}) must be >= amount ({amount})")] +#[platform_serialize(unversioned)] +pub struct UnshieldValueBalanceBelowAmountError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + value_balance: i64, + amount: u64, +} + +impl UnshieldValueBalanceBelowAmountError { + pub fn new(value_balance: i64, amount: u64) -> Self { + Self { + value_balance, + amount, + } + } + + pub fn value_balance(&self) -> i64 { + self.value_balance + } + + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl From for ConsensusError { + fn from(err: UnshieldValueBalanceBelowAmountError) -> Self { + Self::BasicError(BasicError::UnshieldValueBalanceBelowAmountError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/codes.rs b/packages/rs-dpp/src/errors/consensus/codes.rs index fe4f544a768..60e8086c1a8 100644 --- a/packages/rs-dpp/src/errors/consensus/codes.rs +++ b/packages/rs-dpp/src/errors/consensus/codes.rs @@ -232,6 +232,12 @@ impl ErrorWithCode for BasicError { Self::OutputAddressAlsoInputError(_) => 10816, Self::InvalidRemainderOutputCountError(_) => 10817, Self::WithdrawalBelowMinAmountError(_) => 10818, + Self::ShieldedNoActionsError(_) => 10819, + Self::ShieldedEmptyProofError(_) => 10820, + Self::ShieldedZeroAnchorError(_) => 10821, + Self::ShieldedInvalidValueBalanceError(_) => 10822, + Self::UnshieldAmountZeroError(_) => 10823, + Self::UnshieldValueBalanceBelowAmountError(_) => 10824, } } } diff --git a/packages/rs-dpp/src/shielded/mod.rs b/packages/rs-dpp/src/shielded/mod.rs index 3e3f765b905..d64dd1bea0a 100644 --- a/packages/rs-dpp/src/shielded/mod.rs +++ b/packages/rs-dpp/src/shielded/mod.rs @@ -2,6 +2,22 @@ use bincode::{Decode, Encode}; #[cfg(feature = "state-transition-serde-conversion")] use serde::{Deserialize, Serialize}; +/// Serde helper for `[u8; 64]` fields (serde only supports arrays up to 32). +#[cfg(feature = "state-transition-serde-conversion")] +pub(crate) mod serde_bytes_64 { + use serde::{Deserialize, Deserializer, Serializer}; + + pub fn serialize(bytes: &[u8; 64], serializer: S) -> Result { + serializer.serialize_bytes(bytes) + } + + pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<[u8; 64], D::Error> { + let vec = >::deserialize(deserializer)?; + vec.try_into() + .map_err(|v: Vec| serde::de::Error::custom(format!("expected 64 bytes, got {}", v.len()))) + } +} + /// Parameters for a shielded pool, stored as an Item in the pool's subtree #[derive(Debug, Clone, Encode, Decode, Default, PartialEq)] pub struct ShieldedPoolParams { @@ -11,9 +27,19 @@ pub struct ShieldedPoolParams { /// A serialized Orchard action extracted from a bundle. /// -/// Each action represents one spend-and-output pair. The fields are raw bytes -/// suitable for serialization. Validation code reconstructs orchard types from -/// these bytes using grovedb-commitment-tree re-exports. +/// Each Orchard action structurally contains one spend and one output. The spend +/// consumes a previously created note (revealing its nullifier), while the output +/// creates a new note (publishing its commitment). Although paired in the same struct, +/// observers cannot link which prior note was spent or what value the new note holds — +/// the zero-knowledge proof ensures privacy. +/// +/// These fields are raw bytes suitable for network serialization. During validation, +/// they are parsed back into typed Orchard structs and verified via `BatchValidator` +/// (Halo 2 proof + RedPallas signatures). +/// +/// All fields except `spend_auth_sig` are covered by the Orchard bundle commitment +/// (BLAKE2b-256 per ZIP-244), which feeds into the platform sighash. The signatures +/// and proof are verified separately and are not part of the commitment. #[derive(Debug, Clone, Encode, Decode, PartialEq)] #[cfg_attr( feature = "state-transition-serde-conversion", @@ -21,16 +47,47 @@ pub struct ShieldedPoolParams { serde(rename_all = "camelCase") )] pub struct SerializedAction { - /// Nullifier of the spent note (Nullifier::to_bytes()) + /// Unique tag derived from the spent note's position and spending key. + /// Published on-chain to prevent double-spends: if this nullifier already + /// exists in the nullifier set, the transaction is rejected. The nullifier + /// is deterministic for a given note but unlinkable to the note's commitment, + /// preserving sender privacy. pub nullifier: [u8; 32], - /// Randomized spend validating key + + /// Randomized spend validating key (RedPallas verification key). + /// Derived from the spender's full viewing key with per-action randomness. + /// Used to verify `spend_auth_sig`, proving the spender controls the spending + /// key for the consumed note without revealing which key it is. pub rk: [u8; 32], - /// Extracted note commitment (ExtractedNoteCommitment::to_bytes()) + + /// Extracted note commitment for the newly created output note. + /// This is added to the commitment tree after the transition is applied, + /// allowing the recipient to later spend it. The commitment hides the note's + /// value, recipient, and randomness — only the recipient (who knows the + /// decryption key) can identify and spend this note. pub cmx: [u8; 32], - /// Encrypted note ciphertext (epk + enc + out from TransmittedNoteCiphertext) + + /// Encrypted note ciphertext (692 bytes = epk 32 + enc_ciphertext 580 + out_ciphertext 80). + /// Contains the `TransmittedNoteCiphertext` fields packed contiguously: + /// - `epk`: ephemeral public key for Diffie-Hellman key agreement + /// - `enc_ciphertext`: note plaintext encrypted to the recipient (value, address, memo) + /// - `out_ciphertext`: encrypted to the sender for wallet recovery + /// Stored on-chain so recipients can scan and decrypt notes addressed to them. + /// Only the intended recipient (or sender) can decrypt; all others see random bytes. pub encrypted_note: Vec, - /// Value commitment (cv_net bytes) + + /// Value commitment (Pedersen commitment to the note's value). + /// Commits to the value flowing through this action without revealing it. + /// The binding signature later proves that the sum of all `cv_net` commitments + /// across actions is consistent with the declared `value_balance`, ensuring + /// no credits are created or destroyed. pub cv_net: [u8; 32], - /// RedPallas spend authorization signature (64 bytes) - pub spend_auth_sig: Vec, + + /// RedPallas spend authorization signature over the platform sighash. + /// Proves the spender authorized this specific bundle (including all actions, + /// value_balance, anchor, and any bound transparent fields). Verified against + /// `rk` during batch validation. This prevents replay attacks — a valid + /// signature from one transition cannot be reused in another. + #[cfg_attr(feature = "state-transition-serde-conversion", serde(with = "serde_bytes_64"))] + pub spend_auth_sig: [u8; 64], } diff --git a/packages/rs-dpp/src/state_transition/mod.rs b/packages/rs-dpp/src/state_transition/mod.rs index e437d6b3766..852cc086b2a 100644 --- a/packages/rs-dpp/src/state_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/mod.rs @@ -136,10 +136,16 @@ use crate::state_transition::identity_update_transition::{ }; use crate::state_transition::masternode_vote_transition::MasternodeVoteTransition; use crate::state_transition::masternode_vote_transition::MasternodeVoteTransitionSignable; +use crate::state_transition::shield_from_asset_lock_transition::{ + ShieldFromAssetLockTransition, ShieldFromAssetLockTransitionSignable, +}; use crate::state_transition::shield_transition::{ShieldTransition, ShieldTransitionSignable}; use crate::state_transition::shielded_transfer_transition::{ ShieldedTransferTransition, ShieldedTransferTransitionSignable, }; +use crate::state_transition::shielded_withdrawal_transition::{ + ShieldedWithdrawalTransition, ShieldedWithdrawalTransitionSignable, +}; #[cfg(feature = "state-transition-signing")] use crate::state_transition::state_transitions::document::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; use crate::state_transition::unshield_transition::{ @@ -172,6 +178,8 @@ macro_rules! call_method { StateTransition::Shield(st) => st.$method($args), StateTransition::ShieldedTransfer(st) => st.$method($args), StateTransition::Unshield(st) => st.$method($args), + StateTransition::ShieldFromAssetLock(st) => st.$method($args), + StateTransition::ShieldedWithdrawal(st) => st.$method($args), } }; ($state_transition:expr, $method:ident ) => { @@ -194,6 +202,8 @@ macro_rules! call_method { StateTransition::Shield(st) => st.$method(), StateTransition::ShieldedTransfer(st) => st.$method(), StateTransition::Unshield(st) => st.$method(), + StateTransition::ShieldFromAssetLock(st) => st.$method(), + StateTransition::ShieldedWithdrawal(st) => st.$method(), } }; } @@ -219,6 +229,8 @@ macro_rules! call_getter_method_identity_signed { StateTransition::Shield(_) => None, StateTransition::ShieldedTransfer(_) => None, StateTransition::Unshield(_) => None, + StateTransition::ShieldFromAssetLock(_) => None, + StateTransition::ShieldedWithdrawal(_) => None, } }; ($state_transition:expr, $method:ident ) => { @@ -241,6 +253,8 @@ macro_rules! call_getter_method_identity_signed { StateTransition::Shield(_) => None, StateTransition::ShieldedTransfer(_) => None, StateTransition::Unshield(_) => None, + StateTransition::ShieldFromAssetLock(_) => None, + StateTransition::ShieldedWithdrawal(_) => None, } }; } @@ -266,6 +280,8 @@ macro_rules! call_method_identity_signed { StateTransition::Shield(_) => {} StateTransition::ShieldedTransfer(_) => {} StateTransition::Unshield(_) => {} + StateTransition::ShieldFromAssetLock(_) => {} + StateTransition::ShieldedWithdrawal(_) => {} } }; ($state_transition:expr, $method:ident ) => { @@ -288,6 +304,8 @@ macro_rules! call_method_identity_signed { StateTransition::Shield(_) => {} StateTransition::ShieldedTransfer(_) => {} StateTransition::Unshield(_) => {} + StateTransition::ShieldFromAssetLock(_) => {} + StateTransition::ShieldedWithdrawal(_) => {} } }; } @@ -334,6 +352,12 @@ macro_rules! call_errorable_method_identity_signed { StateTransition::Unshield(_) => Err(ProtocolError::CorruptedCodeExecution( "unshield transition can not be called for identity signing".to_string(), )), + StateTransition::ShieldFromAssetLock(_) => Err(ProtocolError::CorruptedCodeExecution( + "shield from asset lock transition can not be called for identity signing".to_string(), + )), + StateTransition::ShieldedWithdrawal(_) => Err(ProtocolError::CorruptedCodeExecution( + "shielded withdrawal transition can not be called for identity signing".to_string(), + )), } }; ($state_transition:expr, $method:ident) => { @@ -376,6 +400,12 @@ macro_rules! call_errorable_method_identity_signed { StateTransition::Unshield(_) => Err(ProtocolError::CorruptedCodeExecution( "unshield transition can not be called for identity signing".to_string(), )), + StateTransition::ShieldFromAssetLock(_) => Err(ProtocolError::CorruptedCodeExecution( + "shield from asset lock transition can not be called for identity signing".to_string(), + )), + StateTransition::ShieldedWithdrawal(_) => Err(ProtocolError::CorruptedCodeExecution( + "shielded withdrawal transition can not be called for identity signing".to_string(), + )), } }; } @@ -417,6 +447,8 @@ pub enum StateTransition { Shield(ShieldTransition), ShieldedTransfer(ShieldedTransferTransition), Unshield(UnshieldTransition), + ShieldFromAssetLock(ShieldFromAssetLockTransition), + ShieldedWithdrawal(ShieldedWithdrawalTransition), } impl OptionallyAssetLockProved for StateTransition { @@ -424,6 +456,7 @@ impl OptionallyAssetLockProved for StateTransition { match self { StateTransition::IdentityCreate(st) => st.optional_asset_lock_proof(), StateTransition::IdentityTopUp(st) => st.optional_asset_lock_proof(), + StateTransition::ShieldFromAssetLock(st) => st.optional_asset_lock_proof(), _ => None, } } @@ -501,7 +534,9 @@ impl StateTransition { | StateTransition::AddressCreditWithdrawal(_) => 11..=LATEST_VERSION, StateTransition::Shield(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => 12..=LATEST_VERSION, + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => 12..=LATEST_VERSION, } } @@ -513,6 +548,8 @@ impl StateTransition { | StateTransition::Shield(_) | StateTransition::ShieldedTransfer(_) | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) ) } @@ -530,6 +567,9 @@ impl StateTransition { StateTransition::AddressFundingFromAssetLock(st) => { st.calculate_min_required_fee(platform_version) } + StateTransition::ShieldFromAssetLock(st) => { + st.calculate_min_required_fee(platform_version) + } st => Err(ProtocolError::CorruptedCodeExecution(format!("{} is not an asset lock transaction, but we are calling required_asset_lock_balance_for_processing_start", st.name()))), } } @@ -612,6 +652,8 @@ impl StateTransition { Self::Shield(_) => "Shield".to_string(), Self::ShieldedTransfer(_) => "ShieldedTransfer".to_string(), Self::Unshield(_) => "Unshield".to_string(), + Self::ShieldFromAssetLock(_) => "ShieldFromAssetLock".to_string(), + Self::ShieldedWithdrawal(_) => "ShieldedWithdrawal".to_string(), } } @@ -636,6 +678,8 @@ impl StateTransition { StateTransition::Shield(_) => None, StateTransition::ShieldedTransfer(_) => None, StateTransition::Unshield(_) => None, + StateTransition::ShieldFromAssetLock(st) => Some(st.signature()), + StateTransition::ShieldedWithdrawal(_) => None, } } @@ -649,6 +693,8 @@ impl StateTransition { StateTransition::Shield(st) => st.inputs().len() as u16, StateTransition::ShieldedTransfer(_) => 0, StateTransition::Unshield(_) => 0, + StateTransition::ShieldFromAssetLock(_) => 0, + StateTransition::ShieldedWithdrawal(_) => 0, _ => 1, } } @@ -720,6 +766,8 @@ impl StateTransition { StateTransition::Shield(_) => None, StateTransition::ShieldedTransfer(_) => None, StateTransition::Unshield(_) => None, + StateTransition::ShieldFromAssetLock(_) => None, + StateTransition::ShieldedWithdrawal(_) => None, } } @@ -744,6 +792,8 @@ impl StateTransition { StateTransition::Shield(st) => Some(st.inputs()), StateTransition::ShieldedTransfer(_) => None, StateTransition::Unshield(_) => None, + StateTransition::ShieldFromAssetLock(_) => None, + StateTransition::ShieldedWithdrawal(_) => None, } } @@ -805,11 +855,16 @@ impl StateTransition { | StateTransition::AddressFundsTransfer(_) | StateTransition::Shield(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => false, + | StateTransition::Unshield(_) + | StateTransition::ShieldedWithdrawal(_) => false, StateTransition::AddressFundingFromAssetLock(st) => { st.set_signature(signature); true } + StateTransition::ShieldFromAssetLock(st) => { + st.set_signature(signature); + true + } StateTransition::AddressCreditWithdrawal(_) => false, } } @@ -978,6 +1033,18 @@ impl StateTransition { "unshield transition can not be called for identity signing".to_string(), )) } + StateTransition::ShieldFromAssetLock(_) => { + return Err(ProtocolError::CorruptedCodeExecution( + "shield from asset lock transition can not be called for identity signing" + .to_string(), + )) + } + StateTransition::ShieldedWithdrawal(_) => { + return Err(ProtocolError::CorruptedCodeExecution( + "shielded withdrawal transition can not be called for identity signing" + .to_string(), + )) + } } let data = self.signable_bytes()?; self.set_signature(signer.sign(identity_public_key, data.as_slice())?); @@ -1322,6 +1389,12 @@ impl StateTransitionStructureValidation for StateTransition { StateTransition::Unshield(transition) => { transition.validate_structure(platform_version) } + StateTransition::ShieldFromAssetLock(transition) => { + transition.validate_structure(platform_version) + } + StateTransition::ShieldedWithdrawal(transition) => { + transition.validate_structure(platform_version) + } } } } diff --git a/packages/rs-dpp/src/state_transition/state_transition_types.rs b/packages/rs-dpp/src/state_transition/state_transition_types.rs index ac7e6d2073d..e38071b4b70 100644 --- a/packages/rs-dpp/src/state_transition/state_transition_types.rs +++ b/packages/rs-dpp/src/state_transition/state_transition_types.rs @@ -38,6 +38,8 @@ pub enum StateTransitionType { Shield = 15, ShieldedTransfer = 16, Unshield = 17, + ShieldFromAssetLock = 18, + ShieldedWithdrawal = 19, } impl std::fmt::Display for StateTransitionType { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/mod.rs index 1c036289134..6201633ba62 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/mod.rs @@ -1,3 +1,5 @@ +pub mod shield_from_asset_lock_transition; pub mod shield_transition; pub mod shielded_transfer_transition; +pub mod shielded_withdrawal_transition; pub mod unshield_transition; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/mod.rs new file mode 100644 index 00000000000..02a37644b0c --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/mod.rs @@ -0,0 +1,58 @@ +mod proved; +mod state_transition_estimated_fee_validation; +mod state_transition_like; +mod state_transition_validation; +pub mod v0; +mod version; + +use crate::state_transition::shield_from_asset_lock_transition::v0::ShieldFromAssetLockTransitionV0; +use crate::state_transition::shield_from_asset_lock_transition::v0::ShieldFromAssetLockTransitionV0Signable; +use crate::state_transition::StateTransitionFieldTypes; + +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use derive_more::From; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize, PlatformSignable}; +use platform_versioning::PlatformVersioned; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +#[derive( + Debug, + Clone, + Encode, + Decode, + PlatformDeserialize, + PlatformSerialize, + PlatformSignable, + PlatformVersioned, + From, + PartialEq, +)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(tag = "$version") +)] +#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version +#[platform_version_path_bounds( + "dpp.state_transition_serialization_versions.shield_from_asset_lock_state_transition" +)] +pub enum ShieldFromAssetLockTransition { + #[cfg_attr(feature = "state-transition-serde-conversion", serde(rename = "0"))] + V0(ShieldFromAssetLockTransitionV0), +} + +impl StateTransitionFieldTypes for ShieldFromAssetLockTransition { + fn signature_property_paths() -> Vec<&'static str> { + vec![] + } + + fn identifiers_property_paths() -> Vec<&'static str> { + vec![] + } + + fn binary_property_paths() -> Vec<&'static str> { + vec![] + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/proved.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/proved.rs new file mode 100644 index 00000000000..4c06ae7ea68 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/proved.rs @@ -0,0 +1,27 @@ +use crate::identity::state_transition::{AssetLockProved, OptionallyAssetLockProved}; +use crate::prelude::AssetLockProof; +use crate::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; +use crate::ProtocolError; + +impl OptionallyAssetLockProved for ShieldFromAssetLockTransition { + fn optional_asset_lock_proof(&self) -> Option<&AssetLockProof> { + Some(self.asset_lock_proof()) + } +} + +impl AssetLockProved for ShieldFromAssetLockTransition { + fn set_asset_lock_proof( + &mut self, + asset_lock_proof: AssetLockProof, + ) -> Result<(), ProtocolError> { + match self { + ShieldFromAssetLockTransition::V0(v0) => v0.set_asset_lock_proof(asset_lock_proof), + } + } + + fn asset_lock_proof(&self) -> &AssetLockProof { + match self { + ShieldFromAssetLockTransition::V0(v0) => v0.asset_lock_proof(), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/state_transition_estimated_fee_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/state_transition_estimated_fee_validation.rs new file mode 100644 index 00000000000..1141003afc6 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/state_transition_estimated_fee_validation.rs @@ -0,0 +1,22 @@ +use crate::balances::credits::CREDITS_PER_DUFF; +use crate::fee::Credits; +use crate::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; +use crate::state_transition::StateTransitionEstimatedFeeValidation; +use crate::ProtocolError; +use platform_version::version::PlatformVersion; + +impl StateTransitionEstimatedFeeValidation for ShieldFromAssetLockTransition { + fn calculate_min_required_fee( + &self, + platform_version: &PlatformVersion, + ) -> Result { + let asset_lock_base_cost = platform_version + .dpp + .state_transitions + .identities + .asset_locks + .required_asset_lock_duff_balance_for_processing_start_for_address_funding + * CREDITS_PER_DUFF; + Ok(asset_lock_base_cost) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/state_transition_like.rs new file mode 100644 index 00000000000..8b1c7f86307 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/state_transition_like.rs @@ -0,0 +1,77 @@ +use crate::prelude::UserFeeIncrease; +use crate::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; +use crate::state_transition::{ + StateTransitionLike, StateTransitionSingleSigned, StateTransitionType, +}; +use crate::version::FeatureVersion; +use platform_value::{BinaryData, Identifier}; + +impl StateTransitionLike for ShieldFromAssetLockTransition { + /// Returns IDs of the modified data + fn modified_data_ids(&self) -> Vec { + match self { + ShieldFromAssetLockTransition::V0(transition) => transition.modified_data_ids(), + } + } + + fn state_transition_protocol_version(&self) -> FeatureVersion { + match self { + ShieldFromAssetLockTransition::V0(_) => 0, + } + } + + /// returns the type of State Transition + fn state_transition_type(&self) -> StateTransitionType { + match self { + ShieldFromAssetLockTransition::V0(transition) => transition.state_transition_type(), + } + } + + /// returns the fee multiplier + fn user_fee_increase(&self) -> UserFeeIncrease { + match self { + ShieldFromAssetLockTransition::V0(transition) => transition.user_fee_increase(), + } + } + + /// set a fee multiplier + fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { + match self { + ShieldFromAssetLockTransition::V0(transition) => { + transition.set_user_fee_increase(user_fee_increase) + } + } + } + + fn unique_identifiers(&self) -> Vec { + match self { + ShieldFromAssetLockTransition::V0(transition) => transition.unique_identifiers(), + } + } +} + +impl StateTransitionSingleSigned for ShieldFromAssetLockTransition { + /// returns the signature as a byte-array + fn signature(&self) -> &BinaryData { + match self { + ShieldFromAssetLockTransition::V0(transition) => transition.signature(), + } + } + + /// set a new signature + fn set_signature(&mut self, signature: BinaryData) { + match self { + ShieldFromAssetLockTransition::V0(transition) => { + transition.set_signature(signature) + } + } + } + + fn set_signature_bytes(&mut self, signature: Vec) { + match self { + ShieldFromAssetLockTransition::V0(transition) => { + transition.set_signature_bytes(signature) + } + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/state_transition_validation.rs new file mode 100644 index 00000000000..bf6bf059c24 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/state_transition_validation.rs @@ -0,0 +1,15 @@ +use crate::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; +use crate::state_transition::StateTransitionStructureValidation; +use crate::validation::SimpleConsensusValidationResult; +use platform_version::version::PlatformVersion; + +impl StateTransitionStructureValidation for ShieldFromAssetLockTransition { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> SimpleConsensusValidationResult { + match self { + ShieldFromAssetLockTransition::V0(v0) => v0.validate_structure(platform_version), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs new file mode 100644 index 00000000000..a7d8b69eebc --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs @@ -0,0 +1,54 @@ +mod proved; +mod state_transition_like; +mod state_transition_validation; +mod types; +mod version; + +use crate::identity::state_transition::asset_lock_proof::AssetLockProof; +use crate::prelude::UserFeeIncrease; +use crate::shielded::SerializedAction; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize, PlatformSignable}; +use platform_value::BinaryData; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +#[derive( + Debug, + Clone, + Encode, + Decode, + PlatformSerialize, + PlatformDeserialize, + PlatformSignable, + PartialEq, +)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +#[platform_serialize(unversioned)] +pub struct ShieldFromAssetLockTransitionV0 { + /// Asset lock proof from L1 + pub asset_lock_proof: AssetLockProof, + /// Orchard actions (spend-output pairs) + pub actions: Vec, + /// Bundle flags (spends_enabled | outputs_enabled) + pub flags: u8, + /// Net value flowing into the shielded pool (must be negative for shielding) + pub value_balance: i64, + /// Merkle root of the commitment tree at time of bundle creation + pub anchor: [u8; 32], + /// Halo2 proof bytes + pub proof: Vec, + /// RedPallas binding signature + #[cfg_attr(feature = "state-transition-serde-conversion", serde(with = "crate::shielded::serde_bytes_64"))] + pub binding_signature: [u8; 64], + /// Fee multiplier + pub user_fee_increase: UserFeeIncrease, + /// ECDSA signature over the signable bytes (excluded from sig hash) + #[platform_signable(exclude_from_sig_hash)] + pub signature: BinaryData, +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/proved.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/proved.rs new file mode 100644 index 00000000000..9eccf52473e --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/proved.rs @@ -0,0 +1,18 @@ +use crate::identity::state_transition::AssetLockProved; +use crate::prelude::AssetLockProof; +use crate::state_transition::shield_from_asset_lock_transition::v0::ShieldFromAssetLockTransitionV0; +use crate::ProtocolError; + +impl AssetLockProved for ShieldFromAssetLockTransitionV0 { + fn set_asset_lock_proof( + &mut self, + asset_lock_proof: AssetLockProof, + ) -> Result<(), ProtocolError> { + self.asset_lock_proof = asset_lock_proof; + Ok(()) + } + + fn asset_lock_proof(&self) -> &AssetLockProof { + &self.asset_lock_proof + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_like.rs new file mode 100644 index 00000000000..be3b17d6f5c --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_like.rs @@ -0,0 +1,68 @@ +use platform_value::BinaryData; + +use crate::prelude::UserFeeIncrease; +use crate::state_transition::shield_from_asset_lock_transition::v0::ShieldFromAssetLockTransitionV0; +use crate::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; +use crate::state_transition::{ + StateTransition, StateTransitionSingleSigned, +}; +use crate::version::FeatureVersion; +use crate::{ + prelude::Identifier, + state_transition::{StateTransitionLike, StateTransitionType}, +}; + +impl From for StateTransition { + fn from(value: ShieldFromAssetLockTransitionV0) -> Self { + let transition: ShieldFromAssetLockTransition = value.into(); + transition.into() + } +} + +impl StateTransitionLike for ShieldFromAssetLockTransitionV0 { + fn state_transition_protocol_version(&self) -> FeatureVersion { + 0 + } + + /// returns the type of State Transition + fn state_transition_type(&self) -> StateTransitionType { + StateTransitionType::ShieldFromAssetLock + } + + /// Returns IDs of the modified data + fn modified_data_ids(&self) -> Vec { + vec![] + } + + /// Returns unique identifiers based on the cmx values from actions + fn unique_identifiers(&self) -> Vec { + self.actions + .iter() + .map(|a| hex::encode(a.cmx)) + .collect() + } + + fn user_fee_increase(&self) -> UserFeeIncrease { + self.user_fee_increase + } + + fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { + self.user_fee_increase = user_fee_increase + } +} + +impl StateTransitionSingleSigned for ShieldFromAssetLockTransitionV0 { + /// returns the signature as a byte-array + fn signature(&self) -> &BinaryData { + &self.signature + } + + /// set a new signature + fn set_signature(&mut self, signature: BinaryData) { + self.signature = signature + } + + fn set_signature_bytes(&mut self, signature: Vec) { + self.signature = BinaryData::new(signature) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_validation.rs new file mode 100644 index 00000000000..345e6a141ce --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_validation.rs @@ -0,0 +1,43 @@ +use crate::consensus::basic::state_transition::{ + ShieldedEmptyProofError, ShieldedInvalidValueBalanceError, ShieldedNoActionsError, +}; +use crate::consensus::basic::BasicError; +use crate::state_transition::shield_from_asset_lock_transition::v0::ShieldFromAssetLockTransitionV0; +use crate::state_transition::StateTransitionStructureValidation; +use crate::validation::SimpleConsensusValidationResult; +use platform_version::version::PlatformVersion; + +impl StateTransitionStructureValidation for ShieldFromAssetLockTransitionV0 { + fn validate_structure( + &self, + _platform_version: &PlatformVersion, + ) -> SimpleConsensusValidationResult { + // Actions must not be empty + if self.actions.is_empty() { + return SimpleConsensusValidationResult::new_with_error( + BasicError::ShieldedNoActionsError(ShieldedNoActionsError::new()).into(), + ); + } + + // value_balance must be negative (credits flowing into pool) + if self.value_balance >= 0 { + return SimpleConsensusValidationResult::new_with_error( + BasicError::ShieldedInvalidValueBalanceError( + ShieldedInvalidValueBalanceError::new( + "shield_from_asset_lock value_balance must be negative".to_string(), + ), + ) + .into(), + ); + } + + // Proof must not be empty + if self.proof.is_empty() { + return SimpleConsensusValidationResult::new_with_error( + BasicError::ShieldedEmptyProofError(ShieldedEmptyProofError::new()).into(), + ); + } + + SimpleConsensusValidationResult::new() + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/types.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/types.rs new file mode 100644 index 00000000000..09acbb4fe11 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/types.rs @@ -0,0 +1,16 @@ +use crate::state_transition::shield_from_asset_lock_transition::v0::ShieldFromAssetLockTransitionV0; +use crate::state_transition::StateTransitionFieldTypes; + +impl StateTransitionFieldTypes for ShieldFromAssetLockTransitionV0 { + fn signature_property_paths() -> Vec<&'static str> { + vec![] + } + + fn identifiers_property_paths() -> Vec<&'static str> { + vec![] + } + + fn binary_property_paths() -> Vec<&'static str> { + vec![] + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/version.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/version.rs new file mode 100644 index 00000000000..4ffb283d990 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/version.rs @@ -0,0 +1,9 @@ +use crate::state_transition::shield_from_asset_lock_transition::v0::ShieldFromAssetLockTransitionV0; +use crate::state_transition::FeatureVersioned; +use crate::version::FeatureVersion; + +impl FeatureVersioned for ShieldFromAssetLockTransitionV0 { + fn feature_version(&self) -> FeatureVersion { + 0 + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/version.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/version.rs new file mode 100644 index 00000000000..949a31fb04a --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/version.rs @@ -0,0 +1,11 @@ +use crate::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; +use crate::state_transition::FeatureVersioned; +use crate::version::FeatureVersion; + +impl FeatureVersioned for ShieldFromAssetLockTransition { + fn feature_version(&self) -> FeatureVersion { + match self { + ShieldFromAssetLockTransition::V0(v0) => v0.feature_version(), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs index 085e6449d6a..a633b89343d 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs @@ -31,9 +31,10 @@ use serde::{Deserialize, Serialize}; serde(rename_all = "camelCase") )] #[platform_serialize(unversioned)] -#[derive(Default)] pub struct ShieldTransitionV0 { - /// Address inputs funding the shield (address -> nonce + amount) + /// Address inputs funding the shield (address -> nonce + max contribution). + /// The total across all inputs must cover |value_balance| + fees. + /// Excess credits remain in the source addresses. pub inputs: BTreeMap, /// Orchard actions (spend-output pairs) pub actions: Vec, @@ -45,8 +46,9 @@ pub struct ShieldTransitionV0 { pub anchor: [u8; 32], /// Halo2 proof bytes pub proof: Vec, - /// RedPallas binding signature (64 bytes) - pub binding_signature: Vec, + /// RedPallas binding signature + #[cfg_attr(feature = "state-transition-serde-conversion", serde(with = "crate::shielded::serde_bytes_64"))] + pub binding_signature: [u8; 64], /// Fee payment strategy pub fee_strategy: AddressFundsFeeStrategy, /// Fee multiplier diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs index 003d80239aa..babc81b46a7 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs @@ -1,7 +1,7 @@ -use crate::consensus::basic::overflow_error::OverflowError; use crate::consensus::basic::state_transition::{ FeeStrategyDuplicateError, FeeStrategyEmptyError, FeeStrategyTooManyStepsError, - InputBelowMinimumError, InputWitnessCountMismatchError, TransitionNoInputsError, + InputBelowMinimumError, InputWitnessCountMismatchError, ShieldedEmptyProofError, + ShieldedInvalidValueBalanceError, ShieldedNoActionsError, TransitionNoInputsError, }; use crate::consensus::basic::BasicError; use crate::state_transition::shield_transition::v0::ShieldTransitionV0; @@ -18,10 +18,7 @@ impl StateTransitionStructureValidation for ShieldTransitionV0 { // Actions must not be empty if self.actions.is_empty() { return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Shield transition must have at least one action".to_string(), - )) - .into(), + BasicError::ShieldedNoActionsError(ShieldedNoActionsError::new()).into(), ); } @@ -64,10 +61,11 @@ impl StateTransitionStructureValidation for ShieldTransitionV0 { // value_balance must be negative (credits flowing into pool) if self.value_balance >= 0 { return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Shield transition value_balance must be negative (credits flow into pool)" - .to_string(), - )) + BasicError::ShieldedInvalidValueBalanceError( + ShieldedInvalidValueBalanceError::new( + "shield value_balance must be negative (credits flow into pool)".to_string(), + ), + ) .into(), ); } @@ -75,35 +73,10 @@ impl StateTransitionStructureValidation for ShieldTransitionV0 { // Proof must not be empty if self.proof.is_empty() { return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Shield transition proof must not be empty".to_string(), - )) - .into(), - ); - } - - // Binding signature must be exactly 64 bytes - if self.binding_signature.len() != 64 { - return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Shield transition binding_signature must be exactly 64 bytes".to_string(), - )) - .into(), + BasicError::ShieldedEmptyProofError(ShieldedEmptyProofError::new()).into(), ); } - // Each action's spend_auth_sig must be exactly 64 bytes - for action in &self.actions { - if action.spend_auth_sig.len() != 64 { - return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Each action spend_auth_sig must be exactly 64 bytes".to_string(), - )) - .into(), - ); - } - } - // Fee strategy validation (reuse address funds patterns) if self.fee_strategy.is_empty() { return SimpleConsensusValidationResult::new_with_error( diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs index a14194c03b6..a78bcc4fbbf 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs @@ -27,7 +27,6 @@ use serde::{Deserialize, Serialize}; serde(rename_all = "camelCase") )] #[platform_serialize(unversioned)] -#[derive(Default)] pub struct ShieldedTransferTransitionV0 { /// Orchard actions (spend-output pairs) pub actions: Vec, @@ -39,8 +38,9 @@ pub struct ShieldedTransferTransitionV0 { pub anchor: [u8; 32], /// Halo2 proof bytes pub proof: Vec, - /// RedPallas binding signature (64 bytes) - pub binding_signature: Vec, + /// RedPallas binding signature + #[cfg_attr(feature = "state-transition-serde-conversion", serde(with = "crate::shielded::serde_bytes_64"))] + pub binding_signature: [u8; 64], /// Fee multiplier pub user_fee_increase: UserFeeIncrease, } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs index 1c0ba7f2a06..1205908f031 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs @@ -1,4 +1,7 @@ -use crate::consensus::basic::overflow_error::OverflowError; +use crate::consensus::basic::state_transition::{ + ShieldedEmptyProofError, ShieldedInvalidValueBalanceError, ShieldedNoActionsError, + ShieldedZeroAnchorError, +}; use crate::consensus::basic::BasicError; use crate::state_transition::shielded_transfer_transition::v0::ShieldedTransferTransitionV0; use crate::state_transition::StateTransitionStructureValidation; @@ -13,19 +16,19 @@ impl StateTransitionStructureValidation for ShieldedTransferTransitionV0 { // Actions must not be empty if self.actions.is_empty() { return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Shielded transfer transition must have at least one action".to_string(), - )) - .into(), + BasicError::ShieldedNoActionsError(ShieldedNoActionsError::new()).into(), ); } // value_balance must be >= 0 (fee extracted from pool, 0 means no fee) if self.value_balance < 0 { return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Shielded transfer value_balance must be non-negative (fee only)".to_string(), - )) + BasicError::ShieldedInvalidValueBalanceError( + ShieldedInvalidValueBalanceError::new( + "shielded transfer value_balance must be non-negative (fee only)" + .to_string(), + ), + ) .into(), ); } @@ -33,42 +36,14 @@ impl StateTransitionStructureValidation for ShieldedTransferTransitionV0 { // Proof must not be empty if self.proof.is_empty() { return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Shielded transfer proof must not be empty".to_string(), - )) - .into(), - ); - } - - // Binding signature must be exactly 64 bytes - if self.binding_signature.len() != 64 { - return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Shielded transfer binding_signature must be exactly 64 bytes".to_string(), - )) - .into(), + BasicError::ShieldedEmptyProofError(ShieldedEmptyProofError::new()).into(), ); } - // Each action's spend_auth_sig must be exactly 64 bytes - for action in &self.actions { - if action.spend_auth_sig.len() != 64 { - return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Each action spend_auth_sig must be exactly 64 bytes".to_string(), - )) - .into(), - ); - } - } - // Anchor must not be all zeros if self.anchor == [0u8; 32] { return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Shielded transfer anchor must not be all zeros".to_string(), - )) - .into(), + BasicError::ShieldedZeroAnchorError(ShieldedZeroAnchorError::new()).into(), ); } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/mod.rs new file mode 100644 index 00000000000..89dfa8fab98 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/mod.rs @@ -0,0 +1,60 @@ +mod state_transition_estimated_fee_validation; +mod state_transition_like; +mod state_transition_validation; +pub mod v0; +mod version; + +use crate::state_transition::shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0; +use crate::state_transition::shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0Signable; +use crate::state_transition::StateTransitionFieldTypes; + +use crate::identity::state_transition::OptionallyAssetLockProved; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use derive_more::From; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize, PlatformSignable}; +use platform_versioning::PlatformVersioned; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +#[derive( + Debug, + Clone, + Encode, + Decode, + PlatformDeserialize, + PlatformSerialize, + PlatformSignable, + PlatformVersioned, + From, + PartialEq, +)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(tag = "$version") +)] +#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version +#[platform_version_path_bounds( + "dpp.state_transition_serialization_versions.shielded_withdrawal_state_transition" +)] +pub enum ShieldedWithdrawalTransition { + #[cfg_attr(feature = "state-transition-serde-conversion", serde(rename = "0"))] + V0(ShieldedWithdrawalTransitionV0), +} + +impl OptionallyAssetLockProved for ShieldedWithdrawalTransition {} + +impl StateTransitionFieldTypes for ShieldedWithdrawalTransition { + fn signature_property_paths() -> Vec<&'static str> { + vec![] + } + + fn identifiers_property_paths() -> Vec<&'static str> { + vec![] + } + + fn binary_property_paths() -> Vec<&'static str> { + vec![] + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/state_transition_estimated_fee_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/state_transition_estimated_fee_validation.rs new file mode 100644 index 00000000000..43a78d0d4a3 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/state_transition_estimated_fee_validation.rs @@ -0,0 +1,16 @@ +use crate::fee::Credits; +use crate::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; +use crate::state_transition::StateTransitionEstimatedFeeValidation; +use crate::ProtocolError; +use platform_version::version::PlatformVersion; + +impl StateTransitionEstimatedFeeValidation for ShieldedWithdrawalTransition { + fn calculate_min_required_fee( + &self, + _platform_version: &PlatformVersion, + ) -> Result { + // Fee for shielded withdrawal is paid from value balance in the orchard bundle + // Minimum fee is 0 as the actual fee is extracted from the bundle during validation + Ok(0) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/state_transition_like.rs new file mode 100644 index 00000000000..34496b07cc1 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/state_transition_like.rs @@ -0,0 +1,47 @@ +use crate::prelude::UserFeeIncrease; +use crate::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; +use crate::state_transition::{StateTransitionLike, StateTransitionType}; +use crate::version::FeatureVersion; +use platform_value::Identifier; + +impl StateTransitionLike for ShieldedWithdrawalTransition { + /// Returns ID of the created contract + fn modified_data_ids(&self) -> Vec { + match self { + ShieldedWithdrawalTransition::V0(transition) => transition.modified_data_ids(), + } + } + + fn state_transition_protocol_version(&self) -> FeatureVersion { + match self { + ShieldedWithdrawalTransition::V0(_) => 0, + } + } + /// returns the type of State Transition + fn state_transition_type(&self) -> StateTransitionType { + match self { + ShieldedWithdrawalTransition::V0(transition) => transition.state_transition_type(), + } + } + + /// returns the fee multiplier + fn user_fee_increase(&self) -> UserFeeIncrease { + match self { + ShieldedWithdrawalTransition::V0(transition) => transition.user_fee_increase(), + } + } + /// set a fee multiplier + fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { + match self { + ShieldedWithdrawalTransition::V0(transition) => { + transition.set_user_fee_increase(user_fee_increase) + } + } + } + + fn unique_identifiers(&self) -> Vec { + match self { + ShieldedWithdrawalTransition::V0(transition) => transition.unique_identifiers(), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/state_transition_validation.rs new file mode 100644 index 00000000000..c00c5ea9157 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/state_transition_validation.rs @@ -0,0 +1,15 @@ +use crate::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; +use crate::state_transition::StateTransitionStructureValidation; +use crate::validation::SimpleConsensusValidationResult; +use platform_version::version::PlatformVersion; + +impl StateTransitionStructureValidation for ShieldedWithdrawalTransition { + fn validate_structure( + &self, + platform_version: &PlatformVersion, + ) -> SimpleConsensusValidationResult { + match self { + ShieldedWithdrawalTransition::V0(v0) => v0.validate_structure(platform_version), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs new file mode 100644 index 00000000000..344bbd414ad --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs @@ -0,0 +1,56 @@ +mod state_transition_like; +mod state_transition_validation; +mod types; +mod version; + +use crate::identity::core_script::CoreScript; +use crate::prelude::UserFeeIncrease; +use crate::shielded::SerializedAction; +use crate::withdrawal::Pooling; +use crate::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize, PlatformSignable}; +#[cfg(feature = "state-transition-serde-conversion")] +use serde::{Deserialize, Serialize}; + +#[derive( + Debug, + Clone, + Encode, + Decode, + PlatformSerialize, + PlatformDeserialize, + PlatformSignable, + PartialEq, +)] +#[cfg_attr( + feature = "state-transition-serde-conversion", + derive(Serialize, Deserialize), + serde(rename_all = "camelCase") +)] +#[platform_serialize(unversioned)] +pub struct ShieldedWithdrawalTransitionV0 { + /// Withdrawal amount in credits + pub amount: u64, + /// Orchard actions (spends + change outputs) + pub actions: Vec, + /// Bundle flags (spends_enabled | outputs_enabled) + pub flags: u8, + /// Net value balance (amount + fee flowing out of shielded pool) + pub value_balance: i64, + /// Merkle root of the commitment tree used for spends + pub anchor: [u8; 32], + /// Halo2 proof bytes + pub proof: Vec, + /// RedPallas binding signature + #[cfg_attr(feature = "state-transition-serde-conversion", serde(with = "crate::shielded::serde_bytes_64"))] + pub binding_signature: [u8; 64], + /// Core transaction fee rate + pub core_fee_per_byte: u32, + /// Withdrawal pooling strategy + pub pooling: Pooling, + /// Core address receiving withdrawn funds + pub output_script: CoreScript, + /// Fee multiplier + pub user_fee_increase: UserFeeIncrease, +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_like.rs new file mode 100644 index 00000000000..24187f2492f --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_like.rs @@ -0,0 +1,51 @@ +use crate::prelude::UserFeeIncrease; +use crate::state_transition::shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0; +use crate::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; +use crate::{ + prelude::Identifier, + state_transition::{StateTransitionLike, StateTransitionType}, +}; + +use crate::state_transition::StateTransition; +use crate::state_transition::StateTransitionType::ShieldedWithdrawal; +use crate::version::FeatureVersion; + +impl From for StateTransition { + fn from(value: ShieldedWithdrawalTransitionV0) -> Self { + let transition: ShieldedWithdrawalTransition = value.into(); + transition.into() + } +} + +impl StateTransitionLike for ShieldedWithdrawalTransitionV0 { + fn state_transition_protocol_version(&self) -> FeatureVersion { + 0 + } + + /// returns the type of State Transition + fn state_transition_type(&self) -> StateTransitionType { + ShieldedWithdrawal + } + + /// Returns ID of the created contract + fn modified_data_ids(&self) -> Vec { + vec![] + } + + /// For ZK-only transitions, uniqueness comes from nullifiers in the actions. + /// Each nullifier can only be used once, making them natural unique identifiers. + fn unique_identifiers(&self) -> Vec { + self.actions + .iter() + .map(|action| hex::encode(action.nullifier)) + .collect() + } + + fn user_fee_increase(&self) -> UserFeeIncrease { + self.user_fee_increase + } + + fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { + self.user_fee_increase = user_fee_increase + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_validation.rs new file mode 100644 index 00000000000..c587643a585 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_validation.rs @@ -0,0 +1,68 @@ +use crate::consensus::basic::state_transition::{ + ShieldedEmptyProofError, ShieldedInvalidValueBalanceError, ShieldedNoActionsError, + ShieldedZeroAnchorError, UnshieldAmountZeroError, UnshieldValueBalanceBelowAmountError, +}; +use crate::consensus::basic::BasicError; +use crate::state_transition::shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0; +use crate::state_transition::StateTransitionStructureValidation; +use crate::validation::SimpleConsensusValidationResult; +use platform_version::version::PlatformVersion; + +impl StateTransitionStructureValidation for ShieldedWithdrawalTransitionV0 { + fn validate_structure( + &self, + _platform_version: &PlatformVersion, + ) -> SimpleConsensusValidationResult { + // Actions must not be empty + if self.actions.is_empty() { + return SimpleConsensusValidationResult::new_with_error( + BasicError::ShieldedNoActionsError(ShieldedNoActionsError::new()).into(), + ); + } + + // Amount must be > 0 + if self.amount == 0 { + return SimpleConsensusValidationResult::new_with_error( + BasicError::UnshieldAmountZeroError(UnshieldAmountZeroError::new()).into(), + ); + } + + // value_balance must be positive (credits flowing out of pool = amount + fee) + if self.value_balance <= 0 { + return SimpleConsensusValidationResult::new_with_error( + BasicError::ShieldedInvalidValueBalanceError( + ShieldedInvalidValueBalanceError::new( + "shielded withdrawal value_balance must be positive".to_string(), + ), + ) + .into(), + ); + } + + // value_balance must be >= amount (value_balance = amount + fee) + if (self.value_balance as u64) < self.amount { + return SimpleConsensusValidationResult::new_with_error( + BasicError::UnshieldValueBalanceBelowAmountError( + UnshieldValueBalanceBelowAmountError::new(self.value_balance, self.amount), + ) + .into(), + ); + } + + // Proof must not be empty + if self.proof.is_empty() { + return SimpleConsensusValidationResult::new_with_error( + BasicError::ShieldedEmptyProofError(ShieldedEmptyProofError::new()).into(), + ); + } + + // Anchor must not be all zeros + if self.anchor == [0u8; 32] { + return SimpleConsensusValidationResult::new_with_error( + BasicError::ShieldedZeroAnchorError(ShieldedZeroAnchorError::new()).into(), + ); + } + + SimpleConsensusValidationResult::new() + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/types.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/types.rs new file mode 100644 index 00000000000..5786bdd0554 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/types.rs @@ -0,0 +1,16 @@ +use crate::state_transition::shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0; +use crate::state_transition::StateTransitionFieldTypes; + +impl StateTransitionFieldTypes for ShieldedWithdrawalTransitionV0 { + fn signature_property_paths() -> Vec<&'static str> { + vec![] + } + + fn identifiers_property_paths() -> Vec<&'static str> { + vec![] + } + + fn binary_property_paths() -> Vec<&'static str> { + vec![] + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/version.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/version.rs new file mode 100644 index 00000000000..89d4dfa7750 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/version.rs @@ -0,0 +1,9 @@ +use crate::state_transition::shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0; +use crate::state_transition::FeatureVersioned; +use crate::version::FeatureVersion; + +impl FeatureVersioned for ShieldedWithdrawalTransitionV0 { + fn feature_version(&self) -> FeatureVersion { + 0 + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/version.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/version.rs new file mode 100644 index 00000000000..da339c67331 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/version.rs @@ -0,0 +1,11 @@ +use crate::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; +use crate::state_transition::FeatureVersioned; +use crate::version::FeatureVersion; + +impl FeatureVersioned for ShieldedWithdrawalTransition { + fn feature_version(&self) -> FeatureVersion { + match self { + ShieldedWithdrawalTransition::V0(v0) => v0.feature_version(), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs index 581cb0eac13..aa27c3c840c 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs @@ -43,8 +43,9 @@ pub struct UnshieldTransitionV0 { pub anchor: [u8; 32], /// Halo2 proof bytes pub proof: Vec, - /// RedPallas binding signature (64 bytes) - pub binding_signature: Vec, + /// RedPallas binding signature + #[cfg_attr(feature = "state-transition-serde-conversion", serde(with = "crate::shielded::serde_bytes_64"))] + pub binding_signature: [u8; 64], /// Fee multiplier pub user_fee_increase: UserFeeIncrease, } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs index 6b20a21e271..68ee5ec3d83 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs @@ -1,4 +1,7 @@ -use crate::consensus::basic::overflow_error::OverflowError; +use crate::consensus::basic::state_transition::{ + ShieldedEmptyProofError, ShieldedInvalidValueBalanceError, ShieldedNoActionsError, + ShieldedZeroAnchorError, UnshieldAmountZeroError, UnshieldValueBalanceBelowAmountError, +}; use crate::consensus::basic::BasicError; use crate::state_transition::unshield_transition::v0::UnshieldTransitionV0; use crate::state_transition::StateTransitionStructureValidation; @@ -13,29 +16,25 @@ impl StateTransitionStructureValidation for UnshieldTransitionV0 { // Actions must not be empty if self.actions.is_empty() { return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Unshield transition must have at least one action".to_string(), - )) - .into(), + BasicError::ShieldedNoActionsError(ShieldedNoActionsError::new()).into(), ); } // Amount must be > 0 if self.amount == 0 { return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Unshield transition amount must be greater than zero".to_string(), - )) - .into(), + BasicError::UnshieldAmountZeroError(UnshieldAmountZeroError::new()).into(), ); } // value_balance must be positive (credits flowing out of pool = amount + fee) if self.value_balance <= 0 { return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Unshield transition value_balance must be positive".to_string(), - )) + BasicError::ShieldedInvalidValueBalanceError( + ShieldedInvalidValueBalanceError::new( + "unshield value_balance must be positive".to_string(), + ), + ) .into(), ); } @@ -43,9 +42,9 @@ impl StateTransitionStructureValidation for UnshieldTransitionV0 { // value_balance must be >= amount (value_balance = amount + fee) if (self.value_balance as u64) < self.amount { return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Unshield transition value_balance must be >= amount".to_string(), - )) + BasicError::UnshieldValueBalanceBelowAmountError( + UnshieldValueBalanceBelowAmountError::new(self.value_balance, self.amount), + ) .into(), ); } @@ -53,42 +52,14 @@ impl StateTransitionStructureValidation for UnshieldTransitionV0 { // Proof must not be empty if self.proof.is_empty() { return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Unshield transition proof must not be empty".to_string(), - )) - .into(), + BasicError::ShieldedEmptyProofError(ShieldedEmptyProofError::new()).into(), ); } - // Binding signature must be exactly 64 bytes - if self.binding_signature.len() != 64 { - return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Unshield transition binding_signature must be exactly 64 bytes".to_string(), - )) - .into(), - ); - } - - // Each action's spend_auth_sig must be exactly 64 bytes - for action in &self.actions { - if action.spend_auth_sig.len() != 64 { - return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Each action spend_auth_sig must be exactly 64 bytes".to_string(), - )) - .into(), - ); - } - } - // Anchor must not be all zeros if self.anchor == [0u8; 32] { return SimpleConsensusValidationResult::new_with_error( - BasicError::OverflowError(OverflowError::new( - "Unshield transition anchor must not be all zeros".to_string(), - )) - .into(), + BasicError::ShieldedZeroAnchorError(ShieldedZeroAnchorError::new()).into(), ); } diff --git a/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs b/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs index f30af0628f0..0f5a4d3c574 100644 --- a/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs +++ b/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs @@ -480,6 +480,27 @@ impl ExecutionEvent<'_> { fees_to_add_to_pool: 0, }) } + StateTransitionAction::ShieldFromAssetLockAction(ref shield_from_asset_lock_action) => { + // Fee = asset_lock_value - shield_amount (excess from asset lock) + let fee_amount = shield_from_asset_lock_action + .asset_lock_value_to_be_consumed() + .saturating_sub(shield_from_asset_lock_action.shield_amount()); + let operations = + action.into_high_level_drive_operations(epoch, platform_version)?; + Ok(ExecutionEvent::PaidFixedCost { + operations, + fees_to_add_to_pool: fee_amount, + }) + } + StateTransitionAction::ShieldedWithdrawalAction(_shielded_withdrawal_action) => { + // Fee = value_balance - amount (stays in pool, same pattern as Unshield) + let operations = + action.into_high_level_drive_operations(epoch, platform_version)?; + Ok(ExecutionEvent::PaidFixedCost { + operations, + fees_to_add_to_pool: 0, + }) + } _ => { let user_fee_increase = action.user_fee_increase(); let operations = diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/address_balances_and_nonces.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/address_balances_and_nonces.rs index 4dbd6e41c23..555a14f4c00 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/address_balances_and_nonces.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/address_balances_and_nonces.rs @@ -179,7 +179,9 @@ impl StateTransitionAddressBalancesAndNoncesValidation for StateTransition { | StateTransition::MasternodeVote(_) | StateTransition::IdentityCreditTransferToAddresses(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => false, + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => false, } } @@ -245,7 +247,9 @@ impl StateTransitionAddressBalancesAndNoncesValidation for StateTransition { | StateTransition::MasternodeVote(_) | StateTransition::IdentityCreditTransferToAddresses(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => { + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => { Ok(ConsensusValidationResult::new_with_data(BTreeMap::new())) } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/address_witnesses.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/address_witnesses.rs index d14d137453d..3bdb3c0f53a 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/address_witnesses.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/address_witnesses.rs @@ -81,7 +81,9 @@ impl StateTransitionAddressWitnessValidationV0 for StateTransition { | StateTransition::MasternodeVote(_) | StateTransition::IdentityCreditTransferToAddresses(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => { + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => { return Ok(SimpleConsensusValidationResult::new()); } }; @@ -196,7 +198,9 @@ impl StateTransitionHasAddressWitnessValidationV0 for StateTransition { | StateTransition::MasternodeVote(_) | StateTransition::IdentityCreditTransferToAddresses(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => false, + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => false, }; Ok(has_address_witness_validation) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/addresses_minimum_balance.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/addresses_minimum_balance.rs index 70ab968da18..be839b5d33a 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/addresses_minimum_balance.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/addresses_minimum_balance.rs @@ -73,7 +73,9 @@ impl StateTransitionAddressesMinimumBalanceValidationV0 for StateTransition { | StateTransition::MasternodeVote(_) | StateTransition::Shield(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => { + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => { return Ok(SimpleConsensusValidationResult::new()); } }?; @@ -103,7 +105,9 @@ impl StateTransitionAddressesMinimumBalanceValidationV0 for StateTransition { | StateTransition::AddressFundingFromAssetLock(_) | StateTransition::Shield(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => false, + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => false, } } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/basic_structure.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/basic_structure.rs index a8c151e3446..a32ae2c4a14 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/basic_structure.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/basic_structure.rs @@ -240,6 +240,12 @@ impl StateTransitionBasicStructureValidationV0 for StateTransition { StateTransition::Shield(st) => Ok(st.validate_structure(platform_version)), StateTransition::ShieldedTransfer(st) => Ok(st.validate_structure(platform_version)), StateTransition::Unshield(st) => Ok(st.validate_structure(platform_version)), + StateTransition::ShieldFromAssetLock(st) => { + Ok(st.validate_structure(platform_version)) + } + StateTransition::ShieldedWithdrawal(st) => { + Ok(st.validate_structure(platform_version)) + } } } fn has_basic_structure_validation(&self, platform_version: &PlatformVersion) -> bool { @@ -278,7 +284,9 @@ impl StateTransitionBasicStructureValidationV0 for StateTransition { | StateTransition::AddressCreditWithdrawal(_) | StateTransition::Shield(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => true, + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => true, StateTransition::MasternodeVote(_) => false, } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_balance.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_balance.rs index 9a51f5a233a..5e86b7e9618 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_balance.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_balance.rs @@ -79,7 +79,9 @@ impl StateTransitionIdentityBalanceValidationV0 for StateTransition { | StateTransition::AddressCreditWithdrawal(_) | StateTransition::Shield(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => Ok(SimpleConsensusValidationResult::new()), + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => Ok(SimpleConsensusValidationResult::new()), } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_based_signature.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_based_signature.rs index d5861ce1057..c181776c722 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_based_signature.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_based_signature.rs @@ -133,7 +133,9 @@ impl StateTransitionIdentityBasedSignatureValidationV0 for StateTransition { | StateTransition::AddressCreditWithdrawal(_) | StateTransition::Shield(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => Ok(ConsensusValidationResult::new()), + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => Ok(ConsensusValidationResult::new()), } } @@ -171,7 +173,9 @@ impl StateTransitionIdentityBasedSignatureValidationV0 for StateTransition { | StateTransition::AddressCreditWithdrawal(_) | StateTransition::Shield(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => false, + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => false, StateTransition::DataContractCreate(_) | StateTransition::DataContractUpdate(_) | StateTransition::Batch(_) @@ -197,7 +201,9 @@ impl StateTransitionIdentityBasedSignatureValidationV0 for StateTransition { | StateTransition::IdentityTopUp(_) | StateTransition::Shield(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => false, + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => false, StateTransition::DataContractCreate(_) | StateTransition::DataContractUpdate(_) | StateTransition::Batch(_) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_nonces.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_nonces.rs index 819124bc185..f84d263e5af 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_nonces.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/identity_nonces.rs @@ -117,7 +117,9 @@ impl StateTransitionIdentityNonceValidationV0 for StateTransition { | StateTransition::IdentityTopUp(_) | StateTransition::Shield(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => Ok(SimpleConsensusValidationResult::new()), + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => Ok(SimpleConsensusValidationResult::new()), } } } @@ -166,7 +168,9 @@ impl StateTransitionHasIdentityNonceValidationV0 for StateTransition { | StateTransition::AddressCreditWithdrawal(_) | StateTransition::Shield(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => false, + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => false, }; Ok(has_nonce_validation) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/is_allowed.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/is_allowed.rs index 80d6f35de35..7d45224ed2c 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/is_allowed.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/is_allowed.rs @@ -34,7 +34,9 @@ impl StateTransitionIsAllowedValidationV0 for StateTransition { | StateTransition::AddressCreditWithdrawal(_) | StateTransition::Shield(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => Ok(true), + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => Ok(true), StateTransition::DataContractCreate(_) | StateTransition::DataContractUpdate(_) | StateTransition::IdentityCreate(_) @@ -74,7 +76,9 @@ impl StateTransitionIsAllowedValidationV0 for StateTransition { } StateTransition::Shield(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => { + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => { if platform_version.protocol_version >= SHIELDED_POOL_INITIAL_PROTOCOL_VERSION { Ok(ConsensusValidationResult::new()) } else { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/state.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/state.rs index 9535229012b..b2f92fa7e84 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/state.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/state.rs @@ -196,6 +196,16 @@ impl StateTransitionStateValidation for StateTransition { StateTransition::Unshield(_) => Err(Error::Execution( ExecutionError::CorruptedCodeExecution("unshield should not have state validation"), )), + StateTransition::ShieldFromAssetLock(_) => { + Err(Error::Execution(ExecutionError::CorruptedCodeExecution( + "shield from asset lock should not have state validation", + ))) + } + StateTransition::ShieldedWithdrawal(_) => { + Err(Error::Execution(ExecutionError::CorruptedCodeExecution( + "shielded withdrawal should not have state validation", + ))) + } } } @@ -218,7 +228,9 @@ impl StateTransitionStateValidation for StateTransition { | StateTransition::IdentityCreditTransferToAddresses(_) | StateTransition::Shield(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => false, + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => false, } } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs index ae5d30e23eb..34f086a1eed 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs @@ -47,6 +47,10 @@ pub mod shield; pub mod shielded_common; /// Module for shielded transfer transition validation pub mod shielded_transfer; +/// Module for shielded withdrawal transition validation +pub mod shielded_withdrawal; +/// Module for shield from asset lock transition validation +pub mod shield_from_asset_lock; /// Module for unshield transition validation pub mod unshield; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs index 65595fe3c97..5e037d9e269 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs @@ -48,7 +48,7 @@ mod tests { cmx: [3u8; 32], encrypted_note: vec![4u8; 692], // epk(32) + enc(580) + out(80) cv_net: [5u8; 32], - spend_auth_sig: vec![6u8; 64], + spend_auth_sig: [6u8; 64], } } @@ -61,7 +61,7 @@ mod tests { flags: u8, value_balance: i64, proof: Vec, - binding_signature: Vec, + binding_signature: [u8; 64], fee_strategy: AddressFundsFeeStrategy, witness_count: usize, ) -> StateTransition { @@ -90,7 +90,7 @@ mod tests { flags: u8, value_balance: i64, proof: Vec, - binding_signature: Vec, + binding_signature: [u8; 64], fee_strategy: AddressFundsFeeStrategy, ) -> StateTransition { // First create with empty witnesses to compute signable bytes @@ -145,7 +145,7 @@ mod tests { 0x03, // spends_enabled | outputs_enabled -1000, vec![0u8; 100], // dummy proof bytes - vec![0u8; 64], // dummy binding signature + [0u8; 64], // dummy binding signature AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput(0)]), ) } @@ -208,7 +208,7 @@ mod tests { /// platform-compatible format: (actions, flags, value_balance, anchor, proof, binding_sig). fn serialize_authorized_bundle( bundle: &Bundle, - ) -> (Vec, u8, i64, [u8; 32], Vec, Vec) { + ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { let actions: Vec = bundle .actions() .iter() @@ -225,7 +225,7 @@ mod tests { cmx: action.cmx().to_bytes(), encrypted_note, cv_net: action.cv_net().to_bytes(), - spend_auth_sig: <[u8; 64]>::from(action.authorization()).to_vec(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()), } }) .collect(); @@ -235,7 +235,7 @@ mod tests { let anchor = bundle.anchor().to_bytes(); let proof = bundle.authorization().proof().as_ref().to_vec(); let binding_sig = - <[u8; 64]>::from(bundle.authorization().binding_signature()).to_vec(); + <[u8; 64]>::from(bundle.authorization().binding_signature()); (actions, flags, value_balance, anchor, proof, binding_sig) } @@ -268,7 +268,7 @@ mod tests { 0x03, -1000, vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( 0, )]), @@ -279,7 +279,7 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) + ConsensusError::BasicError(BasicError::ShieldedNoActionsError(_)) )] ); } @@ -296,7 +296,7 @@ mod tests { 0x03, -1000, vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( 0, )]), @@ -368,7 +368,7 @@ mod tests { 0x03, -1, vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( 0, )]), @@ -403,7 +403,7 @@ mod tests { 0x03, 1000, // Positive — invalid for shield (must be negative) vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( 0, )]), @@ -414,7 +414,7 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) + ConsensusError::BasicError(BasicError::ShieldedInvalidValueBalanceError(_)) )] ); } @@ -438,7 +438,7 @@ mod tests { 0x03, 0, // Zero — invalid for shield (must be negative) vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( 0, )]), @@ -449,7 +449,7 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) + ConsensusError::BasicError(BasicError::ShieldedInvalidValueBalanceError(_)) )] ); } @@ -473,7 +473,7 @@ mod tests { 0x03, -1000, vec![], // Empty proof — invalid - vec![0u8; 64], + [0u8; 64], AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( 0, )]), @@ -484,80 +484,7 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) - )] - ); - } - - #[test] - fn test_wrong_binding_sig_length_returns_error() { - let platform_version = PlatformVersion::latest(); - let mut platform = setup_platform(); - - let mut signer = TestAddressSigner::new(); - let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); - - let mut inputs = BTreeMap::new(); - inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); - - let transition = create_signed_shield_transition( - &signer, - inputs, - vec![create_dummy_serialized_action()], - 0x03, - -1000, - vec![0u8; 100], - vec![0u8; 32], // 32 bytes instead of 64 — invalid - AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( - 0, - )]), - ); - - let processing_result = process_transition(&platform, transition, platform_version); - - assert_matches!( - processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) - )] - ); - } - - #[test] - fn test_wrong_spend_auth_sig_length_returns_error() { - let platform_version = PlatformVersion::latest(); - let mut platform = setup_platform(); - - let mut signer = TestAddressSigner::new(); - let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); - - let mut inputs = BTreeMap::new(); - inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); - - let mut bad_action = create_dummy_serialized_action(); - bad_action.spend_auth_sig = vec![0u8; 32]; // 32 bytes instead of 64 - - let transition = create_signed_shield_transition( - &signer, - inputs, - vec![bad_action], - 0x03, - -1000, - vec![0u8; 100], - vec![0u8; 64], - AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( - 0, - )]), - ); - - let processing_result = process_transition(&platform, transition, platform_version); - - assert_matches!( - processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) + ConsensusError::BasicError(BasicError::ShieldedEmptyProofError(_)) )] ); } @@ -581,7 +508,7 @@ mod tests { 0x03, -1000, vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], AddressFundsFeeStrategy::from(vec![]), // Empty fee strategy ); @@ -615,7 +542,7 @@ mod tests { 0x03, -1000, vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], AddressFundsFeeStrategy::from(vec![ AddressFundsFeeStrategyStep::DeductFromInput(0), AddressFundsFeeStrategyStep::DeductFromInput(1), @@ -654,7 +581,7 @@ mod tests { 0x03, -1000, vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], AddressFundsFeeStrategy::from(vec![ AddressFundsFeeStrategyStep::DeductFromInput(0), AddressFundsFeeStrategyStep::DeductFromInput(0), // Duplicate @@ -745,7 +672,7 @@ mod tests { 0x03, -1000, vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( 0, )]), @@ -1035,7 +962,7 @@ mod tests { 0x03, -1000, vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( 0, )]), @@ -1086,7 +1013,7 @@ mod tests { 0x03, i64::MIN, // -9223372036854775808 — would overflow on negation vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput( 0, )]), diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs index 069f19da38c..12a602c5368 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs @@ -100,7 +100,7 @@ impl ShieldStateTransitionTransformIntoActionValidationV0 for ShieldTransition { v0.value_balance, &v0.anchor, v0.proof.as_slice(), - v0.binding_signature.as_slice(), + &v0.binding_signature, ), }; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/mod.rs new file mode 100644 index 00000000000..3745057e8db --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/mod.rs @@ -0,0 +1,64 @@ +mod transform_into_action; + +use dpp::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; + +use crate::error::execution::ExecutionError; +use crate::error::Error; +use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; +use crate::execution::validation::state_transition::shield_from_asset_lock::transform_into_action::v0::ShieldFromAssetLockStateTransitionTransformIntoActionValidationV0; +use crate::execution::validation::state_transition::ValidationMode; +use crate::platform_types::platform::PlatformRef; +use crate::platform_types::platform_state::PlatformStateV0Methods; +use crate::rpc::core::CoreRPCLike; +use dpp::validation::ConsensusValidationResult; +use drive::grovedb::TransactionArg; +use drive::state_transition_action::StateTransitionAction; + +/// A trait to transform into an action for shield from asset lock transition +pub(in crate::execution) trait StateTransitionShieldFromAssetLockTransitionActionTransformer { + /// Transform into an action for shield from asset lock transition + fn transform_into_action_for_shield_from_asset_lock_transition( + &self, + platform: &PlatformRef, + signable_bytes: Vec, + validation_mode: ValidationMode, + execution_context: &mut StateTransitionExecutionContext, + tx: TransactionArg, + ) -> Result, Error>; +} + +impl StateTransitionShieldFromAssetLockTransitionActionTransformer + for ShieldFromAssetLockTransition +{ + fn transform_into_action_for_shield_from_asset_lock_transition( + &self, + platform: &PlatformRef, + signable_bytes: Vec, + validation_mode: ValidationMode, + execution_context: &mut StateTransitionExecutionContext, + tx: TransactionArg, + ) -> Result, Error> { + let platform_version = platform.state.current_platform_version()?; + + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .shield_from_asset_lock_state_transition + .transform_into_action + { + 0 => self.transform_into_action_v0( + platform, + signable_bytes, + validation_mode, + execution_context, + tx, + ), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "shield from asset lock transition: transform_into_action".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/mod.rs new file mode 100644 index 00000000000..e88e88c052f --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/mod.rs @@ -0,0 +1 @@ +pub(in crate::execution::validation::state_transition::state_transitions::shield_from_asset_lock) mod v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs new file mode 100644 index 00000000000..295cc122145 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs @@ -0,0 +1,355 @@ +use crate::error::execution::ExecutionError; +use crate::error::Error; +use crate::execution::types::execution_operation::signature_verification_operation::SignatureVerificationOperation; +use crate::execution::types::execution_operation::{ValidationOperation, SHA256_BLOCK_SIZE}; +use crate::execution::types::state_transition_execution_context::{ + StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0, +}; +use crate::execution::validation::state_transition::common::asset_lock::proof::validate::AssetLockProofValidation; +use crate::execution::validation::state_transition::common::asset_lock::transaction::fetch_asset_lock_transaction_output_sync::fetch_asset_lock_transaction_output_sync; +use crate::execution::validation::state_transition::state_transitions::shielded_common::reconstruct_and_verify_bundle; +use crate::execution::validation::state_transition::ValidationMode; +use crate::platform_types::platform::PlatformRef; +use crate::platform_types::platform_state::PlatformStateV0Methods; +use crate::rpc::core::CoreRPCLike; +use dpp::asset_lock::reduced_asset_lock_value::{AssetLockValue, AssetLockValueGettersV0}; +use dpp::balances::credits::CREDITS_PER_DUFF; +use dpp::consensus::basic::identity::IdentityAssetLockTransactionOutPointNotEnoughBalanceError; +use dpp::consensus::signature::{BasicECDSAError, SignatureError}; +use dpp::consensus::state::shielded::invalid_shielded_proof_error::InvalidShieldedProofError; +use dpp::consensus::state::state_error::StateError; +use dpp::dashcore::hashes::Hash; +use dpp::dashcore::{signer, ScriptBuf, Txid}; +use dpp::fee::Credits; +use dpp::identity::state_transition::AssetLockProved; +use dpp::identity::KeyType; +use dpp::platform_value::{Bytes32, Bytes36}; +use dpp::prelude::ConsensusValidationResult; +use dpp::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; +use dpp::state_transition::signable_bytes_hasher::SignableBytesHasher; +use dpp::state_transition::{StateTransitionEstimatedFeeValidation, StateTransitionSingleSigned}; +use drive::drive::shielded::paths::{shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY}; +use drive::grovedb::TransactionArg; +use drive::state_transition_action::shielded::shield_from_asset_lock::ShieldFromAssetLockTransitionAction; +use drive::state_transition_action::system::partially_use_asset_lock_action::PartiallyUseAssetLockActionV0; +use drive::state_transition_action::system::partially_use_asset_lock_action::PartiallyUseAssetLockAction; +use drive::state_transition_action::StateTransitionAction; +use drive::util::grove_operations::DirectQueryType; + +pub(in crate::execution::validation::state_transition::state_transitions::shield_from_asset_lock) trait ShieldFromAssetLockStateTransitionTransformIntoActionValidationV0 +{ + fn transform_into_action_v0( + &self, + platform: &PlatformRef, + signable_bytes: Vec, + validation_mode: ValidationMode, + execution_context: &mut StateTransitionExecutionContext, + tx: TransactionArg, + ) -> Result, Error>; +} + +impl ShieldFromAssetLockStateTransitionTransformIntoActionValidationV0 + for ShieldFromAssetLockTransition +{ + fn transform_into_action_v0( + &self, + platform: &PlatformRef, + signable_bytes: Vec, + validation_mode: ValidationMode, + execution_context: &mut StateTransitionExecutionContext, + tx: TransactionArg, + ) -> Result, Error> { + let platform_version = platform.state.current_platform_version()?; + + // Extract note commitments and encrypted notes from serialized actions + let note_commitments: Vec<[u8; 32]> = match self { + ShieldFromAssetLockTransition::V0(v0) => v0.actions.iter().map(|a| a.cmx).collect(), + }; + let encrypted_notes: Vec> = match self { + ShieldFromAssetLockTransition::V0(v0) => v0 + .actions + .iter() + .map(|a| a.encrypted_note.clone()) + .collect(), + }; + + // Step 1: The value_balance must be negative for shielding (funds flowing into the pool) + let value_balance = match self { + ShieldFromAssetLockTransition::V0(v0) => v0.value_balance, + }; + if value_balance >= 0 { + return Ok(ConsensusValidationResult::new_with_error( + StateError::InvalidShieldedProofError(InvalidShieldedProofError::new( + "shield_from_asset_lock value_balance must be negative".to_string(), + )) + .into(), + )); + } + + // Step 2: Safely negate to get the shield amount, guarding against overflow (i64::MIN) + let shield_amount: Credits = match value_balance.checked_neg() { + Some(positive) => positive as u64, + None => { + return Ok(ConsensusValidationResult::new_with_error( + StateError::InvalidShieldedProofError(InvalidShieldedProofError::new( + "shield_from_asset_lock value_balance overflow (i64::MIN)".to_string(), + )) + .into(), + )); + } + }; + + // Step 3: Calculate minimum required fee from platform_version + let required_balance = self.calculate_min_required_fee(platform_version)?; + + let signable_bytes_len = signable_bytes.len(); + + let mut signable_bytes_hasher = SignableBytesHasher::Bytes(signable_bytes); + + // Step 4: Validate asset lock proof + let asset_lock_proof_validation = if validation_mode != ValidationMode::NoValidation { + AssetLockProved::asset_lock_proof(self).validate( + platform, + &mut signable_bytes_hasher, + required_balance, + validation_mode, + tx, + platform_version, + )? + } else { + ConsensusValidationResult::new() + }; + + if !asset_lock_proof_validation.is_valid() { + return Ok(ConsensusValidationResult::new_with_errors( + asset_lock_proof_validation.errors, + )); + } + + // Step 5: Fetch/validate asset lock transaction output + let mut needs_signature_verification = true; + + let asset_lock_value_to_be_consumed = if asset_lock_proof_validation.has_data() { + let asset_lock_value = asset_lock_proof_validation.into_data()?; + // There is no need to recheck signatures on recheck tx + if validation_mode == ValidationMode::RecheckTx { + needs_signature_verification = false; + } + asset_lock_value + } else { + let tx_out_validation = fetch_asset_lock_transaction_output_sync( + platform.core_rpc, + AssetLockProved::asset_lock_proof(self), + platform_version, + )?; + + if !tx_out_validation.is_valid() { + return Ok(ConsensusValidationResult::new_with_errors( + tx_out_validation.errors, + )); + } + + let tx_out = tx_out_validation.into_data()?; + + let tx_out_credit_value = tx_out.value.saturating_mul(CREDITS_PER_DUFF); + + // Verify locked amount >= shield_amount + min_fee + let required_total = shield_amount.saturating_add(required_balance); + if tx_out_credit_value < required_total { + let asset_lock_proof = AssetLockProved::asset_lock_proof(self); + return Ok(ConsensusValidationResult::new_with_error( + IdentityAssetLockTransactionOutPointNotEnoughBalanceError::new( + asset_lock_proof + .out_point() + .map(|outpoint| outpoint.txid) + .unwrap_or(Txid::all_zeros()), + asset_lock_proof.output_index() as usize, + tx_out_credit_value, + tx_out_credit_value, + required_total, + ) + .into(), + )); + } + + if validation_mode == ValidationMode::RecheckTx { + needs_signature_verification = false; + } + + let initial_balance_amount = tx_out.value * CREDITS_PER_DUFF; + AssetLockValue::new( + initial_balance_amount, + tx_out.script_pubkey.0, + initial_balance_amount, + vec![], + platform_version, + )? + }; + + // Step 6: Verify ECDSA signature over signable_bytes (P2PKH from asset lock output) + if needs_signature_verification { + let tx_out_script_pubkey = + ScriptBuf(asset_lock_value_to_be_consumed.tx_out_script().clone()); + + let public_key_hash = tx_out_script_pubkey + .p2pkh_public_key_hash_bytes() + .ok_or_else(|| { + Error::Execution(ExecutionError::CorruptedCachedState( + "the script inside the state must be a p2pkh".to_string(), + )) + })?; + + let block_count = signable_bytes_len as u16 / SHA256_BLOCK_SIZE; + + execution_context.add_operation(ValidationOperation::DoubleSha256(block_count)); + execution_context.add_operation(ValidationOperation::SignatureVerification( + SignatureVerificationOperation::new(KeyType::ECDSA_HASH160), + )); + + if let Err(e) = signer::verify_hash_signature( + signable_bytes_hasher.hash_bytes().as_slice(), + self.signature().as_slice(), + public_key_hash, + ) { + return Ok(ConsensusValidationResult::new_with_error( + SignatureError::BasicECDSAError(BasicECDSAError::new(e.to_string())).into(), + )); + } + } + + // Step 7: Also check that the remaining asset lock balance covers shield_amount + let remaining_credit_value = asset_lock_value_to_be_consumed.remaining_credit_value(); + if remaining_credit_value < shield_amount { + let asset_lock_proof = AssetLockProved::asset_lock_proof(self); + return Ok(ConsensusValidationResult::new_with_error( + IdentityAssetLockTransactionOutPointNotEnoughBalanceError::new( + asset_lock_proof + .out_point() + .map(|outpoint| outpoint.txid) + .unwrap_or(Txid::all_zeros()), + asset_lock_proof.output_index() as usize, + remaining_credit_value, + remaining_credit_value, + shield_amount, + ) + .into(), + )); + } + + // Step 8: Read current shielded pool total balance from GroveDB + let mut drive_operations = vec![]; + let pool_path = shielded_credit_pool_path(); + + let current_total_balance = platform + .drive + .grove_get_raw_value_u64_from_encoded_var_vec( + (&pool_path).into(), + &[SHIELDED_TOTAL_BALANCE_KEY], + DirectQueryType::StatefulDirectQuery, + tx, + &mut drive_operations, + &platform_version.drive, + )? + .unwrap_or(0); + + // Step 9: Verify Orchard ZK proof via reconstruct_and_verify_bundle() + // Use EMPTY extra_sighash_data -- no transparent binding needed since + // the asset lock proof authenticates the source of funds. + let (actions, flags, anchor, proof, binding_signature) = match self { + ShieldFromAssetLockTransition::V0(v0) => ( + &v0.actions, + v0.flags, + &v0.anchor, + v0.proof.as_slice(), + &v0.binding_signature, + ), + }; + + if let Err(e) = reconstruct_and_verify_bundle( + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + &[], // No transparent fields to bind for shield_from_asset_lock + ) { + // Step 10: ZK proof failed -- consume asset lock with penalty (PartiallyUseAssetLockAction) + let penalty = platform_version + .drive_abci + .validation_and_processing + .penalties + .shielded_proof_verification_failure; + + let desired_used_credits = penalty + .checked_add(execution_context.fee_cost(platform_version)?.processing_fee) + .ok_or(Error::Execution(ExecutionError::Overflow( + "processing fee overflow in shield_from_asset_lock penalty calculation", + )))?; + + let asset_lock_outpoint = AssetLockProved::asset_lock_proof(self) + .out_point() + .ok_or_else(|| { + Error::Execution(ExecutionError::CorruptedCachedState( + "asset lock proof must have an outpoint after validation".to_string(), + )) + })?; + + let signable_bytes_hash: Bytes32 = signable_bytes_hasher.into_hashed_bytes(); + let mut previous_transaction_hashes = + asset_lock_value_to_be_consumed.used_tags_ref().clone(); + previous_transaction_hashes.push(signable_bytes_hash); + + let remaining_after_penalty = remaining_credit_value.saturating_sub(desired_used_credits); + let used_credits = std::cmp::min(remaining_credit_value, desired_used_credits); + + let user_fee_increase = match self { + ShieldFromAssetLockTransition::V0(v0) => v0.user_fee_increase, + }; + + let partially_use_action = PartiallyUseAssetLockAction::from( + PartiallyUseAssetLockActionV0 { + asset_lock_outpoint: Bytes36::new(asset_lock_outpoint.into()), + initial_credit_value: asset_lock_value_to_be_consumed.initial_credit_value(), + previous_transaction_hashes, + asset_lock_script: asset_lock_value_to_be_consumed.tx_out_script().clone(), + remaining_credit_value: remaining_after_penalty, + used_credits, + user_fee_increase, + inputs_with_remaining_balance: None, + fee_strategy: None, + }, + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + StateTransitionAction::PartiallyUseAssetLockAction(partially_use_action), + vec![StateError::InvalidShieldedProofError(e).into()], + )); + } + + // Step 11: Build the successful action + let asset_lock_outpoint = AssetLockProved::asset_lock_proof(self) + .out_point() + .ok_or_else(|| { + Error::Execution(ExecutionError::CorruptedCachedState( + "asset lock proof must have an outpoint after validation".to_string(), + )) + })?; + + let asset_lock_value_credits = asset_lock_value_to_be_consumed.remaining_credit_value(); + let signable_bytes_hash: [u8; 32] = signable_bytes_hasher.into_hashed_bytes().0; + + let result = ShieldFromAssetLockTransitionAction::try_from_transition( + self, + asset_lock_outpoint.into(), + asset_lock_value_credits, + signable_bytes_hash, + shield_amount, + note_commitments, + encrypted_notes, + current_total_balance, + ); + + Ok(result.map(|action| action.into())) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs index 4a3c9b7efda..a6fe7bf6d52 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs @@ -75,7 +75,7 @@ pub fn reconstruct_and_verify_bundle( value_balance: i64, anchor: &[u8; 32], proof: &[u8], - binding_signature: &[u8], + binding_signature: &[u8; 64], extra_sighash_data: &[u8], ) -> Result<(), InvalidShieldedProofError> { let vk = get_verifying_key(); @@ -117,14 +117,6 @@ pub fn reconstruct_and_verify_bundle( InvalidShieldedProofError::new("invalid value commitment bytes".to_string()) })?; - let spend_auth_sig_bytes: [u8; 64] = - a.spend_auth_sig.as_slice().try_into().map_err(|_| { - InvalidShieldedProofError::new(format!( - "spend auth signature size mismatch: expected 64, got {}", - a.spend_auth_sig.len() - )) - })?; - let action = Action::from_parts( nullifier, rk, @@ -135,22 +127,15 @@ pub fn reconstruct_and_verify_bundle( out_ciphertext, }, cv_net, - redpallas::Signature::from(spend_auth_sig_bytes), + redpallas::Signature::from(a.spend_auth_sig), ); orchard_actions.push(action); } // Reconstruct Authorized (proof + binding signature) - let binding_sig_bytes: [u8; 64] = binding_signature.try_into().map_err(|_| { - InvalidShieldedProofError::new(format!( - "binding signature size mismatch: expected 64, got {}", - binding_signature.len() - )) - })?; - let authorized = Authorized::from_parts( Proof::new(proof.to_vec()), - redpallas::Signature::from(binding_sig_bytes), + redpallas::Signature::from(*binding_signature), ); // Reconstruct Bundle diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs index 379ec66978e..f0d3eb8ae9d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs @@ -34,7 +34,7 @@ mod tests { cmx: [3u8; 32], encrypted_note: vec![4u8; 692], // epk(32) + enc(580) + out(80) cv_net: [5u8; 32], - spend_auth_sig: vec![6u8; 64], + spend_auth_sig: [6u8; 64], } } @@ -46,7 +46,7 @@ mod tests { value_balance: i64, anchor: [u8; 32], proof: Vec, - binding_signature: Vec, + binding_signature: [u8; 64], user_fee_increase: u16, ) -> StateTransition { StateTransition::ShieldedTransfer(ShieldedTransferTransition::V0( @@ -71,7 +71,7 @@ mod tests { 0, // zero fee [42u8; 32], // non-zero anchor vec![0u8; 100], // dummy proof bytes - vec![0u8; 64], // dummy binding signature + [0u8; 64], // dummy binding signature 0, ) } @@ -235,7 +235,7 @@ mod tests { 0, [42u8; 32], vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], 0, ); @@ -244,7 +244,7 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) + ConsensusError::BasicError(BasicError::ShieldedNoActionsError(_)) )] ); } @@ -260,7 +260,7 @@ mod tests { -1000, // Negative — invalid for shielded transfer (must be >= 0) [42u8; 32], vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], 0, ); @@ -269,7 +269,7 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) + ConsensusError::BasicError(BasicError::ShieldedInvalidValueBalanceError(_)) )] ); } @@ -285,7 +285,7 @@ mod tests { 0, [42u8; 32], vec![], // Empty proof — invalid - vec![0u8; 64], + [0u8; 64], 0, ); @@ -294,60 +294,7 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) - )] - ); - } - - #[test] - fn test_wrong_binding_sig_length_returns_error() { - let platform_version = PlatformVersion::latest(); - let platform = setup_platform(); - - let transition = create_shielded_transfer_transition( - vec![create_dummy_serialized_action()], - 0x03, - 0, - [42u8; 32], - vec![0u8; 100], - vec![0u8; 32], // 32 bytes instead of 64 — invalid - 0, - ); - - let processing_result = process_transition(&platform, transition, platform_version); - - assert_matches!( - processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) - )] - ); - } - - #[test] - fn test_wrong_spend_auth_sig_length_returns_error() { - let platform_version = PlatformVersion::latest(); - let platform = setup_platform(); - - let mut bad_action = create_dummy_serialized_action(); - bad_action.spend_auth_sig = vec![0u8; 32]; // 32 bytes instead of 64 - - let transition = create_shielded_transfer_transition( - vec![bad_action], - 0x03, - 0, - [42u8; 32], - vec![0u8; 100], - vec![0u8; 64], - 0, - ); - - let processing_result = process_transition(&platform, transition, platform_version); - - assert_matches!( - processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) + ConsensusError::BasicError(BasicError::ShieldedEmptyProofError(_)) )] ); } @@ -363,7 +310,7 @@ mod tests { 0, [0u8; 32], // All zeros — invalid vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], 0, ); @@ -372,7 +319,7 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) + ConsensusError::BasicError(BasicError::ShieldedZeroAnchorError(_)) )] ); } @@ -461,7 +408,7 @@ mod tests { fn serialize_authorized_bundle( bundle: &Bundle, - ) -> (Vec, u8, i64, [u8; 32], Vec, Vec) { + ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { let actions: Vec = bundle .actions() .iter() @@ -477,7 +424,7 @@ mod tests { cmx: action.cmx().to_bytes(), encrypted_note, cv_net: action.cv_net().to_bytes(), - spend_auth_sig: <[u8; 64]>::from(action.authorization()).to_vec(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()), } }) .collect(); @@ -486,7 +433,7 @@ mod tests { let anchor = bundle.anchor().to_bytes(); let proof = bundle.authorization().proof().as_ref().to_vec(); let binding_sig = - <[u8; 64]>::from(bundle.authorization().binding_signature()).to_vec(); + <[u8; 64]>::from(bundle.authorization().binding_signature()); (actions, flags, value_balance, anchor, proof, binding_sig) } @@ -614,7 +561,7 @@ mod tests { 0, anchor, vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], 0, ); @@ -657,7 +604,7 @@ mod tests { fn serialize_authorized_bundle( bundle: &Bundle, - ) -> (Vec, u8, i64, [u8; 32], Vec, Vec) { + ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { let actions: Vec = bundle .actions() .iter() @@ -673,7 +620,7 @@ mod tests { cmx: action.cmx().to_bytes(), encrypted_note, cv_net: action.cv_net().to_bytes(), - spend_auth_sig: <[u8; 64]>::from(action.authorization()).to_vec(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()), } }) .collect(); @@ -682,13 +629,13 @@ mod tests { let anchor = bundle.anchor().to_bytes(); let proof = bundle.authorization().proof().as_ref().to_vec(); let binding_sig = - <[u8; 64]>::from(bundle.authorization().binding_signature()).to_vec(); + <[u8; 64]>::from(bundle.authorization().binding_signature()); (actions, flags, value_balance, anchor, proof, binding_sig) } /// Build a valid Orchard bundle for shielded transfer tests. /// Returns (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig). - fn build_valid_shielded_transfer_bundle() -> (Vec, u8, i64, [u8; 32], Vec, Vec) { + fn build_valid_shielded_transfer_bundle() -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { let mut rng = OsRng; let pk = get_proving_key(); @@ -802,7 +749,7 @@ mod tests { value_balance, anchor_bytes, proof_bytes, - vec![0u8; 64], // ZEROED binding signature + [0u8; 64], // ZEROED binding signature 0, ); @@ -834,7 +781,7 @@ mod tests { // ATTACK: Zero out all spend auth signatures for action in &mut actions { - action.spend_auth_sig = vec![0u8; 64]; + action.spend_auth_sig = [0u8; 64]; } insert_anchor_into_state(&platform, &anchor_bytes); @@ -890,7 +837,7 @@ mod tests { 0, anchor, vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], 0, ); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs index 1a580c5461e..4685af3f7d5 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs @@ -120,7 +120,7 @@ impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 for Shielded v0.flags, v0.value_balance, v0.proof.as_slice(), - v0.binding_signature.as_slice(), + &v0.binding_signature, ), }; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/mod.rs new file mode 100644 index 00000000000..e9b56726a49 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/mod.rs @@ -0,0 +1,51 @@ +mod transform_into_action; + +use dpp::block::block_info::BlockInfo; +use dpp::state_transition::state_transitions::shielded::shielded_withdrawal_transition::ShieldedWithdrawalTransition; +use dpp::validation::ConsensusValidationResult; +use drive::grovedb::TransactionArg; +use drive::state_transition_action::StateTransitionAction; + +use crate::error::execution::ExecutionError; +use crate::error::Error; +use crate::execution::validation::state_transition::shielded_withdrawal::transform_into_action::v0::ShieldedWithdrawalStateTransitionTransformIntoActionValidationV0; +use crate::platform_types::platform::PlatformRef; +use crate::platform_types::platform_state::PlatformStateV0Methods; +use crate::rpc::core::CoreRPCLike; + +/// A trait to transform into an action for shielded withdrawal transition +pub trait StateTransitionShieldedWithdrawalTransitionActionTransformer { + /// Transform into an action for shielded withdrawal transition + fn transform_into_action_for_shielded_withdrawal_transition( + &self, + platform: &PlatformRef, + block_info: &BlockInfo, + tx: TransactionArg, + ) -> Result, Error>; +} + +impl StateTransitionShieldedWithdrawalTransitionActionTransformer for ShieldedWithdrawalTransition { + fn transform_into_action_for_shielded_withdrawal_transition( + &self, + platform: &PlatformRef, + block_info: &BlockInfo, + tx: TransactionArg, + ) -> Result, Error> { + let platform_version = platform.state.current_platform_version()?; + + match platform_version + .drive_abci + .validation_and_processing + .state_transitions + .shielded_withdrawal_state_transition + .transform_into_action + { + 0 => self.transform_into_action_v0(platform.drive, block_info, tx, platform_version), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "shielded withdrawal transition: transform_into_action".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/mod.rs new file mode 100644 index 00000000000..f60ce30ca28 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/mod.rs @@ -0,0 +1 @@ +pub(in crate::execution::validation::state_transition::state_transitions::shielded_withdrawal) mod v0; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs new file mode 100644 index 00000000000..c35e95bd47b --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs @@ -0,0 +1,191 @@ +use crate::error::Error; +use crate::execution::validation::state_transition::state_transitions::shielded_common::reconstruct_and_verify_bundle; +use dpp::block::block_info::BlockInfo; +use dpp::consensus::state::shielded::invalid_anchor_error::InvalidAnchorError; +use dpp::consensus::state::shielded::nullifier_already_spent_error::NullifierAlreadySpentError; +use dpp::consensus::state::state_error::StateError; +use dpp::prelude::ConsensusValidationResult; +use dpp::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; +use dpp::version::PlatformVersion; +use drive::drive::shielded::paths::{ + shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, + shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY, +}; +use drive::drive::Drive; +use drive::grovedb::TransactionArg; +use drive::state_transition_action::shielded::shielded_withdrawal::ShieldedWithdrawalTransitionAction; +use drive::state_transition_action::StateTransitionAction; +use drive::util::grove_operations::DirectQueryType; + +pub(in crate::execution::validation::state_transition::state_transitions::shielded_withdrawal) trait ShieldedWithdrawalStateTransitionTransformIntoActionValidationV0 +{ + fn transform_into_action_v0( + &self, + drive: &Drive, + block_info: &BlockInfo, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error>; +} + +impl ShieldedWithdrawalStateTransitionTransformIntoActionValidationV0 + for ShieldedWithdrawalTransition +{ + fn transform_into_action_v0( + &self, + drive: &Drive, + block_info: &BlockInfo, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + // Extract nullifiers, note commitments, and encrypted notes from serialized actions + let nullifiers: Vec<[u8; 32]> = match self { + ShieldedWithdrawalTransition::V0(v0) => { + v0.actions.iter().map(|a| a.nullifier).collect() + } + }; + let note_commitments: Vec<[u8; 32]> = match self { + ShieldedWithdrawalTransition::V0(v0) => v0.actions.iter().map(|a| a.cmx).collect(), + }; + let encrypted_notes: Vec> = match self { + ShieldedWithdrawalTransition::V0(v0) => v0 + .actions + .iter() + .map(|a| a.encrypted_note.clone()) + .collect(), + }; + + // The anchor from the transition (Merkle root of commitment tree) + let anchor: [u8; 32] = match self { + ShieldedWithdrawalTransition::V0(v0) => v0.anchor, + }; + + // Read current shielded pool total balance from GroveDB + let mut drive_operations = vec![]; + let pool_path = shielded_credit_pool_path(); + + let current_total_balance = drive + .grove_get_raw_value_u64_from_encoded_var_vec( + (&pool_path).into(), + &[SHIELDED_TOTAL_BALANCE_KEY], + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )? + .unwrap_or(0); + + // Verify the pool has sufficient balance for the withdrawal. + // value_balance is the total amount leaving the pool (amount + fee). + let value_balance = match self { + ShieldedWithdrawalTransition::V0(v0) => v0.value_balance, + }; + + // value_balance > 0 is already validated in structure validation, + // so the cast to u64 is safe here. + if current_total_balance < (value_balance as u64) { + return Ok(ConsensusValidationResult::new_with_error( + StateError::InvalidShieldedProofError( + dpp::consensus::state::shielded::invalid_shielded_proof_error::InvalidShieldedProofError::new( + format!( + "shielded pool has insufficient balance: pool has {} but withdrawal requires {}", + current_total_balance, value_balance + ), + ), + ) + .into(), + )); + } + + // Verify the anchor exists in the recorded anchors tree + let anchors_path = shielded_anchors_credit_pool_path(); + let anchor_exists = drive.grove_has_raw( + (&anchors_path).into(), + &anchor, + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )?; + + if !anchor_exists { + return Ok(ConsensusValidationResult::new_with_error( + StateError::InvalidAnchorError(InvalidAnchorError::new(anchor)).into(), + )); + } + + // Check that no nullifier has already been spent + let nullifiers_path = shielded_credit_pool_nullifiers_path(); + for nullifier in &nullifiers { + let exists = drive.grove_has_raw( + (&nullifiers_path).into(), + nullifier, + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )?; + + if exists { + return Ok(ConsensusValidationResult::new_with_error( + StateError::NullifierAlreadySpentError(NullifierAlreadySpentError::new( + *nullifier, + )) + .into(), + )); + } + } + + // Verify the Orchard ZK proof, binding transparent fields to the sighash. + // For shielded withdrawal, the extra_sighash_data binds the withdrawal + // destination (output_script) and amount, preventing an attacker from + // substituting a different output_script or amount while reusing a valid + // Orchard bundle. + let (st_actions, st_flags, st_value_balance, st_proof, st_binding_sig, output_script, amount) = + match self { + ShieldedWithdrawalTransition::V0(v0) => ( + &v0.actions, + v0.flags, + v0.value_balance, + v0.proof.as_slice(), + &v0.binding_signature, + &v0.output_script, + v0.amount, + ), + }; + + // Serialize transparent fields to bind them to the Orchard sighash. + // output_script.as_bytes() || amount.to_le_bytes() + let mut extra_sighash_data = output_script.as_bytes().to_vec(); + extra_sighash_data.extend_from_slice(&amount.to_le_bytes()); + + if let Err(e) = reconstruct_and_verify_bundle( + st_actions, + st_flags, + st_value_balance, + &anchor, + st_proof, + st_binding_sig, + &extra_sighash_data, + ) { + return Ok(ConsensusValidationResult::new_with_error( + StateError::InvalidShieldedProofError(e).into(), + )); + } + + // Build the action, which includes creating the withdrawal document + let creation_time_ms = block_info.time_ms; + + let result = ShieldedWithdrawalTransitionAction::try_from_transition( + self, + nullifiers, + note_commitments, + encrypted_notes, + anchor, + current_total_balance, + creation_time_ms, + ); + + Ok(result.map(|action| action.into())) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs index 9e7968b13cc..42fc396945e 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs @@ -35,7 +35,7 @@ mod tests { cmx: [3u8; 32], encrypted_note: vec![4u8; 692], // epk(32) + enc(580) + out(80) cv_net: [5u8; 32], - spend_auth_sig: vec![6u8; 64], + spend_auth_sig: [6u8; 64], } } @@ -57,7 +57,7 @@ mod tests { value_balance: i64, anchor: [u8; 32], proof: Vec, - binding_signature: Vec, + binding_signature: [u8; 64], user_fee_increase: u16, ) -> StateTransition { StateTransition::Unshield(UnshieldTransition::V0(UnshieldTransitionV0 { @@ -84,7 +84,7 @@ mod tests { 1000, // value_balance = amount (no fee for simplicity) [42u8; 32], // non-zero anchor vec![0u8; 100], // dummy proof bytes - vec![0u8; 64], // dummy binding signature + [0u8; 64], // dummy binding signature 0, ) } @@ -250,7 +250,7 @@ mod tests { 1000, [42u8; 32], vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], 0, ); @@ -259,7 +259,7 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) + ConsensusError::BasicError(BasicError::ShieldedNoActionsError(_)) )] ); } @@ -277,7 +277,7 @@ mod tests { 1000, [42u8; 32], vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], 0, ); @@ -286,7 +286,7 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) + ConsensusError::BasicError(BasicError::UnshieldAmountZeroError(_)) )] ); } @@ -304,7 +304,7 @@ mod tests { 0, // Zero value_balance — invalid (must be positive) [42u8; 32], vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], 0, ); @@ -313,7 +313,7 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) + ConsensusError::BasicError(BasicError::ShieldedInvalidValueBalanceError(_)) )] ); } @@ -331,7 +331,7 @@ mod tests { -1000, // Negative value_balance — invalid [42u8; 32], vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], 0, ); @@ -340,7 +340,7 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) + ConsensusError::BasicError(BasicError::ShieldedInvalidValueBalanceError(_)) )] ); } @@ -358,7 +358,7 @@ mod tests { 1000, // value_balance = 1000 < amount — invalid [42u8; 32], vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], 0, ); @@ -367,7 +367,7 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) + ConsensusError::BasicError(BasicError::UnshieldValueBalanceBelowAmountError(_)) )] ); } @@ -385,7 +385,7 @@ mod tests { 1000, [42u8; 32], vec![], // Empty proof — invalid - vec![0u8; 64], + [0u8; 64], 0, ); @@ -394,64 +394,7 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) - )] - ); - } - - #[test] - fn test_wrong_binding_sig_length_returns_error() { - let platform_version = PlatformVersion::latest(); - let platform = setup_platform(); - - let transition = create_unshield_transition( - create_output_address(), - 1000, - vec![create_dummy_serialized_action()], - 0x03, - 1000, - [42u8; 32], - vec![0u8; 100], - vec![0u8; 32], // 32 bytes instead of 64 — invalid - 0, - ); - - let processing_result = process_transition(&platform, transition, platform_version); - - assert_matches!( - processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) - )] - ); - } - - #[test] - fn test_wrong_spend_auth_sig_length_returns_error() { - let platform_version = PlatformVersion::latest(); - let platform = setup_platform(); - - let mut bad_action = create_dummy_serialized_action(); - bad_action.spend_auth_sig = vec![0u8; 32]; // 32 bytes instead of 64 - - let transition = create_unshield_transition( - create_output_address(), - 1000, - vec![bad_action], - 0x03, - 1000, - [42u8; 32], - vec![0u8; 100], - vec![0u8; 64], - 0, - ); - - let processing_result = process_transition(&platform, transition, platform_version); - - assert_matches!( - processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) + ConsensusError::BasicError(BasicError::ShieldedEmptyProofError(_)) )] ); } @@ -469,7 +412,7 @@ mod tests { 1000, [0u8; 32], // All zeros — invalid vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], 0, ); @@ -478,7 +421,7 @@ mod tests { assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::BasicError(BasicError::OverflowError(_)) + ConsensusError::BasicError(BasicError::ShieldedZeroAnchorError(_)) )] ); } @@ -567,7 +510,7 @@ mod tests { fn serialize_authorized_bundle( bundle: &Bundle, - ) -> (Vec, u8, i64, [u8; 32], Vec, Vec) { + ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { let actions: Vec = bundle .actions() .iter() @@ -583,7 +526,7 @@ mod tests { cmx: action.cmx().to_bytes(), encrypted_note, cv_net: action.cv_net().to_bytes(), - spend_auth_sig: <[u8; 64]>::from(action.authorization()).to_vec(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()), } }) .collect(); @@ -592,7 +535,7 @@ mod tests { let anchor = bundle.anchor().to_bytes(); let proof = bundle.authorization().proof().as_ref().to_vec(); let binding_sig = - <[u8; 64]>::from(bundle.authorization().binding_signature()).to_vec(); + <[u8; 64]>::from(bundle.authorization().binding_signature()); (actions, flags, value_balance, anchor, proof, binding_sig) } @@ -736,7 +679,7 @@ mod tests { 1000, anchor, vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], 0, ); @@ -774,7 +717,7 @@ mod tests { fn serialize_authorized_bundle( bundle: &Bundle, - ) -> (Vec, u8, i64, [u8; 32], Vec, Vec) { + ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { let actions: Vec = bundle .actions() .iter() @@ -790,7 +733,7 @@ mod tests { cmx: action.cmx().to_bytes(), encrypted_note, cv_net: action.cv_net().to_bytes(), - spend_auth_sig: <[u8; 64]>::from(action.authorization()).to_vec(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()), } }) .collect(); @@ -799,7 +742,7 @@ mod tests { let anchor = bundle.anchor().to_bytes(); let proof = bundle.authorization().proof().as_ref().to_vec(); let binding_sig = - <[u8; 64]>::from(bundle.authorization().binding_signature()).to_vec(); + <[u8; 64]>::from(bundle.authorization().binding_signature()); (actions, flags, value_balance, anchor, proof, binding_sig) } @@ -807,7 +750,7 @@ mod tests { /// The `output_address` and `amount` are bound to the sighash so that /// the resulting bundle can only be used with those specific transparent fields. /// Returns (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig). - fn build_valid_unshield_bundle(output_address: &PlatformAddress, amount: u64) -> (Vec, u8, i64, [u8; 32], Vec, Vec) { + fn build_valid_unshield_bundle(output_address: &PlatformAddress, amount: u64) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { let mut rng = OsRng; let pk = get_proving_key(); @@ -989,7 +932,7 @@ mod tests { 1000, anchor, vec![0u8; 100], - vec![0u8; 64], + [0u8; 64], 0, ); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs index 4789214599a..261ffd01538 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs @@ -114,7 +114,7 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti v0.flags, v0.value_balance, v0.proof.as_slice(), - v0.binding_signature.as_slice(), + &v0.binding_signature, v0.output_address, v0.amount, ), diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs index b9653f46b45..1203122375d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs @@ -9,6 +9,8 @@ use crate::execution::validation::state_transition::identity_create_from_address use crate::execution::validation::state_transition::identity_top_up::StateTransitionIdentityTopUpTransitionActionTransformer; use crate::execution::validation::state_transition::shield::StateTransitionShieldTransitionActionTransformer; use crate::execution::validation::state_transition::shielded_transfer::StateTransitionShieldedTransferTransitionActionTransformer; +use crate::execution::validation::state_transition::shield_from_asset_lock::StateTransitionShieldFromAssetLockTransitionActionTransformer; +use crate::execution::validation::state_transition::shielded_withdrawal::StateTransitionShieldedWithdrawalTransitionActionTransformer; use crate::execution::validation::state_transition::unshield::StateTransitionUnshieldTransitionActionTransformer; use crate::execution::validation::state_transition::ValidationMode; use crate::platform_types::platform::PlatformRef; @@ -251,6 +253,23 @@ impl StateTransitionActionTransformer for StateTransition { StateTransition::Unshield(st) => { st.transform_into_action_for_unshield_transition(platform, tx) } + StateTransition::ShieldFromAssetLock(st) => { + let signable_bytes = self.signable_bytes()?; + st.transform_into_action_for_shield_from_asset_lock_transition( + platform, + signable_bytes, + validation_mode, + execution_context, + tx, + ) + } + StateTransition::ShieldedWithdrawal(st) => { + st.transform_into_action_for_shielded_withdrawal_transition( + platform, + block_info, + tx, + ) + } } } } diff --git a/packages/rs-drive-abci/src/query/mod.rs b/packages/rs-drive-abci/src/query/mod.rs index e2b4ae0792d..c87f5f73158 100644 --- a/packages/rs-drive-abci/src/query/mod.rs +++ b/packages/rs-drive-abci/src/query/mod.rs @@ -7,6 +7,7 @@ mod prefunded_specialized_balances; mod proofs; mod response_metadata; mod service; +mod shielded; mod system; mod token_queries; mod validator_queries; diff --git a/packages/rs-drive-abci/src/query/service.rs b/packages/rs-drive-abci/src/query/service.rs index 309d8d562f9..98b7a19b5b3 100644 --- a/packages/rs-drive-abci/src/query/service.rs +++ b/packages/rs-drive-abci/src/query/service.rs @@ -51,6 +51,9 @@ use dapi_grpc::platform::v0::{ GetTokenPreProgrammedDistributionsResponse, GetTokenStatusesRequest, GetTokenStatusesResponse, GetTokenTotalSupplyRequest, GetTokenTotalSupplyResponse, GetTotalCreditsInPlatformRequest, GetTotalCreditsInPlatformResponse, GetVotePollsByEndDateRequest, GetVotePollsByEndDateResponse, + GetShieldedAnchorsRequest, GetShieldedAnchorsResponse, GetShieldedEncryptedNotesRequest, + GetShieldedEncryptedNotesResponse, GetShieldedNullifiersRequest, GetShieldedNullifiersResponse, + GetShieldedPoolStateRequest, GetShieldedPoolStateResponse, WaitForStateTransitionResultRequest, WaitForStateTransitionResultResponse, }; use dapi_grpc::tonic::{Code, Request, Response, Status}; @@ -878,6 +881,54 @@ impl PlatformService for QueryService { ) .await } + + async fn get_shielded_encrypted_notes( + &self, + request: Request, + ) -> Result, Status> { + self.handle_blocking_query( + request, + Platform::::query_shielded_encrypted_notes, + "get_shielded_encrypted_notes", + ) + .await + } + + async fn get_shielded_anchors( + &self, + request: Request, + ) -> Result, Status> { + self.handle_blocking_query( + request, + Platform::::query_shielded_anchors, + "get_shielded_anchors", + ) + .await + } + + async fn get_shielded_pool_state( + &self, + request: Request, + ) -> Result, Status> { + self.handle_blocking_query( + request, + Platform::::query_shielded_pool_state, + "get_shielded_pool_state", + ) + .await + } + + async fn get_shielded_nullifiers( + &self, + request: Request, + ) -> Result, Status> { + self.handle_blocking_query( + request, + Platform::::query_shielded_nullifiers, + "get_shielded_nullifiers", + ) + .await + } } #[async_trait] diff --git a/packages/rs-drive-abci/src/query/shielded/anchors/mod.rs b/packages/rs-drive-abci/src/query/shielded/anchors/mod.rs new file mode 100644 index 00000000000..c8b6d28b31c --- /dev/null +++ b/packages/rs-drive-abci/src/query/shielded/anchors/mod.rs @@ -0,0 +1,63 @@ +mod v0; + +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_shielded_anchors_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_shielded_anchors_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{GetShieldedAnchorsRequest, GetShieldedAnchorsResponse}; +use dpp::version::PlatformVersion; + +impl Platform { + /// Querying the valid shielded anchors + pub fn query_shielded_anchors( + &self, + GetShieldedAnchorsRequest { version }: GetShieldedAnchorsRequest, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let Some(version) = version else { + return Ok(QueryValidationResult::new_with_error( + QueryError::DecodingError( + "could not decode shielded anchors query".to_string(), + ), + )); + }; + + let feature_version_bounds = &platform_version + .drive_abci + .query + .shielded_queries + .anchors; + + let feature_version = match &version { + RequestVersion::V0(_) => 0, + }; + if !feature_version_bounds.check_version(feature_version) { + return Ok(QueryValidationResult::new_with_error( + QueryError::UnsupportedQueryVersion( + "shielded_anchors".to_string(), + feature_version_bounds.min_version, + feature_version_bounds.max_version, + platform_version.protocol_version, + feature_version, + ), + )); + } + match version { + RequestVersion::V0(request_v0) => { + let result = self.query_shielded_anchors_v0( + request_v0, + platform_state, + platform_version, + )?; + + Ok(result.map(|response_v0| GetShieldedAnchorsResponse { + version: Some(ResponseVersion::V0(response_v0)), + })) + } + } + } +} diff --git a/packages/rs-drive-abci/src/query/shielded/anchors/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/anchors/v0/mod.rs new file mode 100644 index 00000000000..ee64514a842 --- /dev/null +++ b/packages/rs-drive-abci/src/query/shielded/anchors/v0/mod.rs @@ -0,0 +1,77 @@ +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::response_metadata::CheckpointUsed; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_shielded_anchors_request::GetShieldedAnchorsRequestV0; +use dapi_grpc::platform::v0::get_shielded_anchors_response::get_shielded_anchors_response_v0::Anchors; +use dapi_grpc::platform::v0::get_shielded_anchors_response::{ + get_shielded_anchors_response_v0, GetShieldedAnchorsResponseV0, +}; +use dpp::check_validation_result_with_data; +use dpp::validation::ValidationResult; +use dpp::version::PlatformVersion; +use drive::drive::shielded::paths::shielded_anchors_credit_pool_path_vec; +use drive::grovedb::query_result_type::QueryResultType; +use drive::grovedb::{PathQuery, Query, SizedQuery}; +use drive::util::grove_operations::GroveDBToUse; + +impl Platform { + pub(super) fn query_shielded_anchors_v0( + &self, + GetShieldedAnchorsRequestV0 { prove }: GetShieldedAnchorsRequestV0, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let path_query = PathQuery { + path: shielded_anchors_credit_pool_path_vec(), + query: SizedQuery { + query: Query::new_range_full(), + limit: None, + offset: None, + }, + }; + + let response = if prove { + let proof = check_validation_result_with_data!(self.drive.grove_get_proved_path_query( + &path_query, + None, + &mut vec![], + &platform_version.drive, + )); + + let (grovedb_used, proof) = + self.response_proof_v0(platform_state, proof, GroveDBToUse::Current)?; + + GetShieldedAnchorsResponseV0 { + result: Some(get_shielded_anchors_response_v0::Result::Proof(proof)), + metadata: Some(self.response_metadata_v0(platform_state, grovedb_used)), + } + } else { + let (results, _) = self.drive.grove_get_raw_path_query( + &path_query, + None, + QueryResultType::QueryKeyElementPairResultType, + &mut vec![], + &platform_version.drive, + )?; + + let anchors: Vec> = results + .to_key_elements() + .into_iter() + .map(|(key, _element)| key) + .collect(); + + GetShieldedAnchorsResponseV0 { + result: Some(get_shielded_anchors_response_v0::Result::Anchors(Anchors { + anchors, + })), + metadata: Some( + self.response_metadata_v0(platform_state, CheckpointUsed::Current), + ), + } + }; + + Ok(QueryValidationResult::new_with_data(response)) + } +} diff --git a/packages/rs-drive-abci/src/query/shielded/encrypted_notes/mod.rs b/packages/rs-drive-abci/src/query/shielded/encrypted_notes/mod.rs new file mode 100644 index 00000000000..6f1a44bff5b --- /dev/null +++ b/packages/rs-drive-abci/src/query/shielded/encrypted_notes/mod.rs @@ -0,0 +1,65 @@ +mod v0; + +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_shielded_encrypted_notes_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_shielded_encrypted_notes_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{ + GetShieldedEncryptedNotesRequest, GetShieldedEncryptedNotesResponse, +}; +use dpp::version::PlatformVersion; + +impl Platform { + /// Querying shielded encrypted notes for wallet sync + pub fn query_shielded_encrypted_notes( + &self, + GetShieldedEncryptedNotesRequest { version }: GetShieldedEncryptedNotesRequest, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let Some(version) = version else { + return Ok(QueryValidationResult::new_with_error( + QueryError::DecodingError( + "could not decode shielded encrypted notes query".to_string(), + ), + )); + }; + + let feature_version_bounds = &platform_version + .drive_abci + .query + .shielded_queries + .encrypted_notes; + + let feature_version = match &version { + RequestVersion::V0(_) => 0, + }; + if !feature_version_bounds.check_version(feature_version) { + return Ok(QueryValidationResult::new_with_error( + QueryError::UnsupportedQueryVersion( + "shielded_encrypted_notes".to_string(), + feature_version_bounds.min_version, + feature_version_bounds.max_version, + platform_version.protocol_version, + feature_version, + ), + )); + } + match version { + RequestVersion::V0(request_v0) => { + let result = self.query_shielded_encrypted_notes_v0( + request_v0, + platform_state, + platform_version, + )?; + + Ok(result.map(|response_v0| GetShieldedEncryptedNotesResponse { + version: Some(ResponseVersion::V0(response_v0)), + })) + } + } + } +} diff --git a/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs new file mode 100644 index 00000000000..e85dfe054f3 --- /dev/null +++ b/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs @@ -0,0 +1,121 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::response_metadata::CheckpointUsed; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_shielded_encrypted_notes_request::GetShieldedEncryptedNotesRequestV0; +use dapi_grpc::platform::v0::get_shielded_encrypted_notes_response::get_shielded_encrypted_notes_response_v0::{ + EncryptedNote, EncryptedNotes, +}; +use dapi_grpc::platform::v0::get_shielded_encrypted_notes_response::{ + get_shielded_encrypted_notes_response_v0, GetShieldedEncryptedNotesResponseV0, +}; +use dpp::check_validation_result_with_data; +use dpp::validation::ValidationResult; +use dpp::version::PlatformVersion; +use drive::drive::shielded::paths::shielded_credit_pool_encrypted_notes_path_vec; +use drive::error::query::QuerySyntaxError; +use drive::grovedb::query_result_type::QueryResultType; +use drive::grovedb::{PathQuery, Query, SizedQuery}; +use drive::util::grove_operations::GroveDBToUse; + +impl Platform { + pub(super) fn query_shielded_encrypted_notes_v0( + &self, + GetShieldedEncryptedNotesRequestV0 { + start_cmx, + count, + prove, + }: GetShieldedEncryptedNotesRequestV0, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let max_elements = platform_version.drive_abci.query.max_returned_elements as u32; + let limit = if count == 0 || count > max_elements { + max_elements as u16 + } else { + count as u16 + }; + + if limit > max_elements as u16 { + return Ok(QueryValidationResult::new_with_error(QueryError::Query( + QuerySyntaxError::InvalidLimit(format!( + "trying to get {} encrypted notes, maximum is {}", + limit, max_elements + )), + ))); + } + + let query = if start_cmx.is_empty() { + Query::new_range_full() + } else { + let mut q = Query::new(); + q.insert_range_after(start_cmx..); + q + }; + + let path_query = PathQuery { + path: shielded_credit_pool_encrypted_notes_path_vec(), + query: SizedQuery { + query, + limit: Some(limit), + offset: None, + }, + }; + + let response = if prove { + let proof = check_validation_result_with_data!(self.drive.grove_get_proved_path_query( + &path_query, + None, + &mut vec![], + &platform_version.drive, + )); + + let (grovedb_used, proof) = + self.response_proof_v0(platform_state, proof, GroveDBToUse::Current)?; + + GetShieldedEncryptedNotesResponseV0 { + result: Some(get_shielded_encrypted_notes_response_v0::Result::Proof( + proof, + )), + metadata: Some(self.response_metadata_v0(platform_state, grovedb_used)), + } + } else { + let (results, _) = self.drive.grove_get_raw_path_query( + &path_query, + None, + QueryResultType::QueryKeyElementPairResultType, + &mut vec![], + &platform_version.drive, + )?; + + let entries: Vec = results + .to_key_elements() + .into_iter() + .filter_map(|(key, element)| { + element + .into_item_bytes() + .ok() + .map(|encrypted_note| EncryptedNote { + cmx: key, + encrypted_note, + }) + }) + .collect(); + + GetShieldedEncryptedNotesResponseV0 { + result: Some( + get_shielded_encrypted_notes_response_v0::Result::EncryptedNotes( + EncryptedNotes { entries }, + ), + ), + metadata: Some( + self.response_metadata_v0(platform_state, CheckpointUsed::Current), + ), + } + }; + + Ok(QueryValidationResult::new_with_data(response)) + } +} diff --git a/packages/rs-drive-abci/src/query/shielded/mod.rs b/packages/rs-drive-abci/src/query/shielded/mod.rs new file mode 100644 index 00000000000..c8cb1fb0643 --- /dev/null +++ b/packages/rs-drive-abci/src/query/shielded/mod.rs @@ -0,0 +1,4 @@ +mod anchors; +mod encrypted_notes; +mod nullifiers; +mod pool_state; diff --git a/packages/rs-drive-abci/src/query/shielded/nullifiers/mod.rs b/packages/rs-drive-abci/src/query/shielded/nullifiers/mod.rs new file mode 100644 index 00000000000..cab55f9eeb2 --- /dev/null +++ b/packages/rs-drive-abci/src/query/shielded/nullifiers/mod.rs @@ -0,0 +1,63 @@ +mod v0; + +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_shielded_nullifiers_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_shielded_nullifiers_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{GetShieldedNullifiersRequest, GetShieldedNullifiersResponse}; +use dpp::version::PlatformVersion; + +impl Platform { + /// Querying shielded nullifier spend status + pub fn query_shielded_nullifiers( + &self, + GetShieldedNullifiersRequest { version }: GetShieldedNullifiersRequest, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let Some(version) = version else { + return Ok(QueryValidationResult::new_with_error( + QueryError::DecodingError( + "could not decode shielded nullifiers query".to_string(), + ), + )); + }; + + let feature_version_bounds = &platform_version + .drive_abci + .query + .shielded_queries + .nullifiers; + + let feature_version = match &version { + RequestVersion::V0(_) => 0, + }; + if !feature_version_bounds.check_version(feature_version) { + return Ok(QueryValidationResult::new_with_error( + QueryError::UnsupportedQueryVersion( + "shielded_nullifiers".to_string(), + feature_version_bounds.min_version, + feature_version_bounds.max_version, + platform_version.protocol_version, + feature_version, + ), + )); + } + match version { + RequestVersion::V0(request_v0) => { + let result = self.query_shielded_nullifiers_v0( + request_v0, + platform_state, + platform_version, + )?; + + Ok(result.map(|response_v0| GetShieldedNullifiersResponse { + version: Some(ResponseVersion::V0(response_v0)), + })) + } + } + } +} diff --git a/packages/rs-drive-abci/src/query/shielded/nullifiers/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/nullifiers/v0/mod.rs new file mode 100644 index 00000000000..38fbb45b49d --- /dev/null +++ b/packages/rs-drive-abci/src/query/shielded/nullifiers/v0/mod.rs @@ -0,0 +1,115 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::response_metadata::CheckpointUsed; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_shielded_nullifiers_request::GetShieldedNullifiersRequestV0; +use dapi_grpc::platform::v0::get_shielded_nullifiers_response::get_shielded_nullifiers_response_v0::{ + NullifierStatus, NullifierStatuses, +}; +use dapi_grpc::platform::v0::get_shielded_nullifiers_response::{ + get_shielded_nullifiers_response_v0, GetShieldedNullifiersResponseV0, +}; +use dpp::check_validation_result_with_data; +use dpp::validation::ValidationResult; +use dpp::version::PlatformVersion; +use drive::drive::shielded::paths::{ + shielded_credit_pool_nullifiers_path, shielded_credit_pool_nullifiers_path_vec, +}; +use drive::error::query::QuerySyntaxError; +use drive::grovedb::{PathQuery, Query, SizedQuery}; +use drive::util::grove_operations::{DirectQueryType, GroveDBToUse}; + +impl Platform { + pub(super) fn query_shielded_nullifiers_v0( + &self, + GetShieldedNullifiersRequestV0 { + nullifiers, + prove, + }: GetShieldedNullifiersRequestV0, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let max_elements = platform_version.drive_abci.query.max_returned_elements as usize; + if nullifiers.len() > max_elements { + return Ok(QueryValidationResult::new_with_error(QueryError::Query( + QuerySyntaxError::InvalidLimit(format!( + "trying to check {} nullifiers, maximum is {}", + nullifiers.len(), + max_elements + )), + ))); + } + + if nullifiers.is_empty() { + return Ok(QueryValidationResult::new_with_error( + QueryError::InvalidArgument("nullifiers list must not be empty".to_string()), + )); + } + + let response = if prove { + let path_query = PathQuery { + path: shielded_credit_pool_nullifiers_path_vec(), + query: SizedQuery { + query: { + let mut q = Query::new(); + q.insert_keys(nullifiers.clone()); + q + }, + limit: None, + offset: None, + }, + }; + + let proof = check_validation_result_with_data!(self.drive.grove_get_proved_path_query( + &path_query, + None, + &mut vec![], + &platform_version.drive, + )); + + let (grovedb_used, proof) = + self.response_proof_v0(platform_state, proof, GroveDBToUse::Current)?; + + GetShieldedNullifiersResponseV0 { + result: Some(get_shielded_nullifiers_response_v0::Result::Proof(proof)), + metadata: Some(self.response_metadata_v0(platform_state, grovedb_used)), + } + } else { + let nullifiers_path = shielded_credit_pool_nullifiers_path(); + + let entries: Vec = nullifiers + .into_iter() + .map(|nullifier| { + let is_spent = self.drive.grove_has_raw( + (&nullifiers_path).into(), + &nullifier, + DirectQueryType::StatefulDirectQuery, + None, + &mut vec![], + &platform_version.drive, + )?; + + Ok(NullifierStatus { + nullifier, + is_spent, + }) + }) + .collect::, Error>>()?; + + GetShieldedNullifiersResponseV0 { + result: Some( + get_shielded_nullifiers_response_v0::Result::NullifierStatuses( + NullifierStatuses { entries }, + ), + ), + metadata: Some( + self.response_metadata_v0(platform_state, CheckpointUsed::Current), + ), + } + }; + + Ok(QueryValidationResult::new_with_data(response)) + } +} diff --git a/packages/rs-drive-abci/src/query/shielded/pool_state/mod.rs b/packages/rs-drive-abci/src/query/shielded/pool_state/mod.rs new file mode 100644 index 00000000000..496c6e8162b --- /dev/null +++ b/packages/rs-drive-abci/src/query/shielded/pool_state/mod.rs @@ -0,0 +1,63 @@ +mod v0; + +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_shielded_pool_state_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_shielded_pool_state_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{GetShieldedPoolStateRequest, GetShieldedPoolStateResponse}; +use dpp::version::PlatformVersion; + +impl Platform { + /// Querying the shielded pool state (total balance) + pub fn query_shielded_pool_state( + &self, + GetShieldedPoolStateRequest { version }: GetShieldedPoolStateRequest, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let Some(version) = version else { + return Ok(QueryValidationResult::new_with_error( + QueryError::DecodingError( + "could not decode shielded pool state query".to_string(), + ), + )); + }; + + let feature_version_bounds = &platform_version + .drive_abci + .query + .shielded_queries + .pool_state; + + let feature_version = match &version { + RequestVersion::V0(_) => 0, + }; + if !feature_version_bounds.check_version(feature_version) { + return Ok(QueryValidationResult::new_with_error( + QueryError::UnsupportedQueryVersion( + "shielded_pool_state".to_string(), + feature_version_bounds.min_version, + feature_version_bounds.max_version, + platform_version.protocol_version, + feature_version, + ), + )); + } + match version { + RequestVersion::V0(request_v0) => { + let result = self.query_shielded_pool_state_v0( + request_v0, + platform_state, + platform_version, + )?; + + Ok(result.map(|response_v0| GetShieldedPoolStateResponse { + version: Some(ResponseVersion::V0(response_v0)), + })) + } + } + } +} diff --git a/packages/rs-drive-abci/src/query/shielded/pool_state/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/pool_state/v0/mod.rs new file mode 100644 index 00000000000..cfdacc8af56 --- /dev/null +++ b/packages/rs-drive-abci/src/query/shielded/pool_state/v0/mod.rs @@ -0,0 +1,77 @@ +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::response_metadata::CheckpointUsed; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_shielded_pool_state_request::GetShieldedPoolStateRequestV0; +use dapi_grpc::platform::v0::get_shielded_pool_state_response::{ + get_shielded_pool_state_response_v0, GetShieldedPoolStateResponseV0, +}; +use dpp::check_validation_result_with_data; +use dpp::validation::ValidationResult; +use dpp::version::PlatformVersion; +use drive::drive::shielded::paths::{ + shielded_credit_pool_path, shielded_credit_pool_path_vec, SHIELDED_TOTAL_BALANCE_KEY, +}; +use drive::grovedb::{PathQuery, Query, SizedQuery}; +use drive::util::grove_operations::{DirectQueryType, GroveDBToUse}; + +impl Platform { + pub(super) fn query_shielded_pool_state_v0( + &self, + GetShieldedPoolStateRequestV0 { prove }: GetShieldedPoolStateRequestV0, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let response = if prove { + let path_query = PathQuery { + path: shielded_credit_pool_path_vec(), + query: SizedQuery { + query: Query::new_single_key(vec![SHIELDED_TOTAL_BALANCE_KEY]), + limit: Some(1), + offset: None, + }, + }; + + let proof = check_validation_result_with_data!(self.drive.grove_get_proved_path_query( + &path_query, + None, + &mut vec![], + &platform_version.drive, + )); + + let (grovedb_used, proof) = + self.response_proof_v0(platform_state, proof, GroveDBToUse::Current)?; + + GetShieldedPoolStateResponseV0 { + result: Some(get_shielded_pool_state_response_v0::Result::Proof(proof)), + metadata: Some(self.response_metadata_v0(platform_state, grovedb_used)), + } + } else { + let pool_path = shielded_credit_pool_path(); + + let total_balance = self + .drive + .grove_get_raw_value_u64_from_encoded_var_vec( + (&pool_path).into(), + &[SHIELDED_TOTAL_BALANCE_KEY], + DirectQueryType::StatefulDirectQuery, + None, + &mut vec![], + &platform_version.drive, + )? + .unwrap_or(0); + + GetShieldedPoolStateResponseV0 { + result: Some(get_shielded_pool_state_response_v0::Result::TotalBalance( + total_balance, + )), + metadata: Some( + self.response_metadata_v0(platform_state, CheckpointUsed::Current), + ), + } + }; + + Ok(QueryValidationResult::new_with_data(response)) + } +} diff --git a/packages/rs-drive-proof-verifier/src/proof.rs b/packages/rs-drive-proof-verifier/src/proof.rs index 401dd87e0c5..ddfbf089a3f 100644 --- a/packages/rs-drive-proof-verifier/src/proof.rs +++ b/packages/rs-drive-proof-verifier/src/proof.rs @@ -2279,6 +2279,179 @@ fn u32_to_u16_opt(i: u32) -> Result, Error> { Ok(i) } +// --- Shielded Pool Query Proof Verification --- + +impl FromProof for ShieldedPoolState { + type Request = platform::GetShieldedPoolStateRequest; + type Response = platform::GetShieldedPoolStateResponse; + + fn maybe_from_proof_with_metadata<'a, I: Into, O: Into>( + _request: I, + response: O, + _network: Network, + platform_version: &PlatformVersion, + provider: &'a dyn ContextProvider, + ) -> Result<(Option, ResponseMetadata, Proof), Error> + where + Self: Sized + 'a, + { + let response: Self::Response = response.into(); + let proof = response.proof().or(Err(Error::NoProofInResult))?; + let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?; + + let (root_hash, maybe_balance) = + Drive::verify_shielded_pool_state(&proof.grovedb_proof, platform_version) + .map_drive_error(proof, mtd)?; + + verify_tenderdash_proof(proof, mtd, &root_hash, provider)?; + + Ok(( + maybe_balance.map(ShieldedPoolState), + mtd.clone(), + proof.clone(), + )) + } +} + +impl FromProof for ShieldedAnchors { + type Request = platform::GetShieldedAnchorsRequest; + type Response = platform::GetShieldedAnchorsResponse; + + fn maybe_from_proof_with_metadata<'a, I: Into, O: Into>( + _request: I, + response: O, + _network: Network, + platform_version: &PlatformVersion, + provider: &'a dyn ContextProvider, + ) -> Result<(Option, ResponseMetadata, Proof), Error> + where + Self: Sized + 'a, + { + let response: Self::Response = response.into(); + let proof = response.proof().or(Err(Error::NoProofInResult))?; + let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?; + + let (root_hash, anchors) = + Drive::verify_shielded_anchors(&proof.grovedb_proof, platform_version) + .map_drive_error(proof, mtd)?; + + verify_tenderdash_proof(proof, mtd, &root_hash, provider)?; + + let result = if anchors.is_empty() { + None + } else { + Some(ShieldedAnchors(anchors)) + }; + + Ok((result, mtd.clone(), proof.clone())) + } +} + +impl FromProof for ShieldedEncryptedNotes { + type Request = platform::GetShieldedEncryptedNotesRequest; + type Response = platform::GetShieldedEncryptedNotesResponse; + + fn maybe_from_proof_with_metadata<'a, I: Into, O: Into>( + request: I, + response: O, + _network: Network, + platform_version: &PlatformVersion, + provider: &'a dyn ContextProvider, + ) -> Result<(Option, ResponseMetadata, Proof), Error> + where + Self: Sized + 'a, + { + use dapi_grpc::platform::v0::get_shielded_encrypted_notes_request; + + let request: Self::Request = request.into(); + let response: Self::Response = response.into(); + let proof = response.proof().or(Err(Error::NoProofInResult))?; + let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?; + + let (start_cmx, count) = match request.version.ok_or(Error::EmptyVersion)? { + get_shielded_encrypted_notes_request::Version::V0(v0) => (v0.start_cmx, v0.count), + }; + + let max_elements = platform_version.drive_abci.query.max_returned_elements as u32; + + let (root_hash, notes) = Drive::verify_shielded_encrypted_notes( + &proof.grovedb_proof, + &start_cmx, + count, + max_elements, + platform_version, + ) + .map_drive_error(proof, mtd)?; + + verify_tenderdash_proof(proof, mtd, &root_hash, provider)?; + + let result = if notes.is_empty() { + None + } else { + Some(ShieldedEncryptedNotes( + notes + .into_iter() + .map(|(cmx, encrypted_note)| ShieldedEncryptedNote { + cmx, + encrypted_note, + }) + .collect(), + )) + }; + + Ok((result, mtd.clone(), proof.clone())) + } +} + +impl FromProof for ShieldedNullifierStatuses { + type Request = platform::GetShieldedNullifiersRequest; + type Response = platform::GetShieldedNullifiersResponse; + + fn maybe_from_proof_with_metadata<'a, I: Into, O: Into>( + request: I, + response: O, + _network: Network, + platform_version: &PlatformVersion, + provider: &'a dyn ContextProvider, + ) -> Result<(Option, ResponseMetadata, Proof), Error> + where + Self: Sized + 'a, + { + use dapi_grpc::platform::v0::get_shielded_nullifiers_request; + + let request: Self::Request = request.into(); + let response: Self::Response = response.into(); + let proof = response.proof().or(Err(Error::NoProofInResult))?; + let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?; + + let nullifiers = match request.version.ok_or(Error::EmptyVersion)? { + get_shielded_nullifiers_request::Version::V0(v0) => v0.nullifiers, + }; + + let (root_hash, statuses) = + Drive::verify_shielded_nullifiers(&proof.grovedb_proof, &nullifiers, platform_version) + .map_drive_error(proof, mtd)?; + + verify_tenderdash_proof(proof, mtd, &root_hash, provider)?; + + let result = if statuses.is_empty() { + None + } else { + Some(ShieldedNullifierStatuses( + statuses + .into_iter() + .map(|(nullifier, is_spent)| ShieldedNullifierStatus { + nullifier, + is_spent, + }) + .collect(), + )) + }; + + Ok((result, mtd.clone(), proof.clone())) + } +} + /// Determine number of non-None elements pub trait Length { /// Return number of non-None elements in the data structure diff --git a/packages/rs-drive-proof-verifier/src/types.rs b/packages/rs-drive-proof-verifier/src/types.rs index 05be5edfc8c..5798482789f 100644 --- a/packages/rs-drive-proof-verifier/src/types.rs +++ b/packages/rs-drive-proof-verifier/src/types.rs @@ -759,3 +759,90 @@ impl std::ops::DerefMut for PlatformAddressTrunkState { &mut self.0 } } + +/// Shielded pool total balance +#[derive(Debug, derive_more::From, Clone, Copy)] +#[cfg_attr( + feature = "mocks", + derive(Encode, Decode, PlatformSerialize, PlatformDeserialize), + platform_serialize(unversioned) +)] +pub struct ShieldedPoolState(pub u64); + +/// A single encrypted note (cmx + encrypted data) +#[derive(Debug, Clone)] +#[cfg_attr( + feature = "mocks", + derive(Encode, Decode, PlatformSerialize, PlatformDeserialize), + platform_serialize(unversioned) +)] +pub struct ShieldedEncryptedNote { + /// The note commitment (cmx), 32 bytes + pub cmx: Vec, + /// The encrypted note data + pub encrypted_note: Vec, +} + +/// Collection of encrypted notes returned by query +#[derive(Debug, Clone, Default, derive_more::From)] +#[cfg_attr( + feature = "mocks", + derive(Encode, Decode, PlatformSerialize, PlatformDeserialize), + platform_serialize(unversioned) +)] +pub struct ShieldedEncryptedNotes(pub Vec); + +/// Valid anchors for building spend proofs +#[derive(Debug, Clone, Default, derive_more::From)] +#[cfg_attr( + feature = "mocks", + derive(Encode, Decode, PlatformSerialize, PlatformDeserialize), + platform_serialize(unversioned) +)] +pub struct ShieldedAnchors(pub Vec>); + +/// Status of a single nullifier (spent or unspent) +#[derive(Debug, Clone)] +#[cfg_attr( + feature = "mocks", + derive(Encode, Decode, PlatformSerialize, PlatformDeserialize), + platform_serialize(unversioned) +)] +pub struct ShieldedNullifierStatus { + /// The nullifier bytes (32 bytes) + pub nullifier: Vec, + /// Whether this nullifier has been spent + pub is_spent: bool, +} + +/// Collection of nullifier statuses returned by query +#[derive(Debug, Clone, Default, derive_more::From)] +#[cfg_attr( + feature = "mocks", + derive(Encode, Decode, PlatformSerialize, PlatformDeserialize), + platform_serialize(unversioned) +)] +pub struct ShieldedNullifierStatuses(pub Vec); + +/// Query parameters for encrypted notes (pagination) +#[derive(Debug, Clone)] +#[cfg_attr( + feature = "mocks", + derive(Encode, Decode, PlatformSerialize, PlatformDeserialize), + platform_serialize(unversioned) +)] +pub struct ShieldedEncryptedNotesQuery { + /// Optional pagination cursor (32 bytes, exclusive start) + pub start_cmx: Option>, + /// Max number of notes to return + pub count: u32, +} + +/// Query parameters for nullifier status check +#[derive(Debug, Clone)] +#[cfg_attr( + feature = "mocks", + derive(Encode, Decode, PlatformSerialize, PlatformDeserialize), + platform_serialize(unversioned) +)] +pub struct ShieldedNullifiersQuery(pub Vec>); diff --git a/packages/rs-drive/src/prove/prove_state_transition/v0/mod.rs b/packages/rs-drive/src/prove/prove_state_transition/v0/mod.rs index f573737beb8..b51d8e7c6f1 100644 --- a/packages/rs-drive/src/prove/prove_state_transition/v0/mod.rs +++ b/packages/rs-drive/src/prove/prove_state_transition/v0/mod.rs @@ -303,7 +303,9 @@ impl Drive { } StateTransition::Shield(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => { + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => { return Err(Error::Proof(ProofError::InvalidTransition( "shielded state transitions do not support proof generation yet".to_string(), ))); diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs index 9bad810dfad..3bce1e6fd1e 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs @@ -116,6 +116,14 @@ impl DriveHighLevelOperationConverter for StateTransitionAction { StateTransitionAction::UnshieldAction(unshield_action) => { unshield_action.into_high_level_drive_operations(epoch, platform_version) } + StateTransitionAction::ShieldFromAssetLockAction(shield_from_asset_lock_action) => { + shield_from_asset_lock_action + .into_high_level_drive_operations(epoch, platform_version) + } + StateTransitionAction::ShieldedWithdrawalAction(shielded_withdrawal_action) => { + shielded_withdrawal_action + .into_high_level_drive_operations(epoch, platform_version) + } } } } diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs index 31602de7245..53746f1ffc3 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs @@ -1,16 +1,19 @@ use crate::drive::shielded::paths::{ shielded_credit_pool_encrypted_notes_path_vec, shielded_credit_pool_nullifiers_path_vec, - shielded_credit_pool_path_vec, SHIELDED_COMMITMENTS_KEY, - SHIELDED_TOTAL_BALANCE_KEY, + shielded_credit_pool_path_vec, SHIELDED_COMMITMENTS_KEY, SHIELDED_TOTAL_BALANCE_KEY, }; use crate::error::Error; use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; use crate::state_transition_action::shielded::shield::ShieldTransitionAction; +use crate::state_transition_action::shielded::shield_from_asset_lock::ShieldFromAssetLockTransitionAction; use crate::state_transition_action::shielded::shielded_transfer::ShieldedTransferTransitionAction; +use crate::state_transition_action::shielded::shielded_withdrawal::ShieldedWithdrawalTransitionAction; use crate::state_transition_action::shielded::unshield::UnshieldTransitionAction; use crate::util::batch::drive_op_batch::finalize_task::DriveOperationFinalizeTask; use crate::util::batch::drive_op_batch::AddressFundsOperationType; -use crate::util::batch::DriveOperation; +use crate::util::batch::{DocumentOperationType, DriveOperation, SystemOperationType}; +use crate::util::object_size_info::{DocumentInfo, OwnedDocumentInfo}; +use dpp::asset_lock::reduced_asset_lock_value::AssetLockValue; use dpp::block::epoch::Epoch; use dpp::version::PlatformVersion; use grovedb::batch::QualifiedGroveDbOp; @@ -252,3 +255,186 @@ impl DriveHighLevelOperationConverter for UnshieldTransitionAction { } } } + +impl DriveHighLevelOperationConverter for ShieldFromAssetLockTransitionAction { + fn into_high_level_drive_operations<'a>( + self, + _epoch: &Epoch, + _platform_version: &PlatformVersion, + ) -> Result>, Error> { + match self { + ShieldFromAssetLockTransitionAction::V0(v0) => { + let mut ops: Vec> = Vec::new(); + + // 1. Add credits to system from the asset lock + ops.push(DriveOperation::SystemOperation( + SystemOperationType::AddToSystemCredits { + amount: v0.asset_lock_value_to_be_consumed, + }, + )); + + // 2. Record asset lock as consumed (prevent replay) + let asset_lock_value = AssetLockValue::new( + v0.asset_lock_value_to_be_consumed, + vec![], // tx_out_script not needed for shielded + 0, // remaining_credit_value = 0 (fully consumed) + vec![], // no used tags for shielded + _platform_version, + ) + .map_err(|e| Error::Protocol(Box::new(e)))?; + ops.push(DriveOperation::SystemOperation( + SystemOperationType::AddUsedAssetLock { + asset_lock_outpoint: v0.asset_lock_outpoint.into(), + asset_lock_value, + }, + )); + + let encrypted_notes_path = shielded_credit_pool_encrypted_notes_path_vec(); + let pool_path = shielded_credit_pool_path_vec(); + + // 3. Append note commitments to commitment tree + for cmx in v0.note_commitments.iter() { + ops.push(DriveOperation::ShieldedPoolOperation( + QualifiedGroveDbOp::commitment_tree_append_op( + pool_path.clone(), + vec![SHIELDED_COMMITMENTS_KEY], + *cmx, + ), + )); + } + + // 4. Insert encrypted notes keyed by their commitment + for (cmx, encrypted_note) in + v0.note_commitments.iter().zip(v0.encrypted_notes.iter()) + { + ops.push(DriveOperation::ShieldedPoolOperation( + QualifiedGroveDbOp::insert_only_op( + encrypted_notes_path.clone(), + cmx.to_vec(), + Element::new_item(encrypted_note.clone()), + ), + )); + } + + // 5. Update total balance: current_total_balance + shield_amount + let new_total_balance = v0.current_total_balance.checked_add(v0.shield_amount) + .ok_or_else(|| Error::Drive( + crate::error::drive::DriveError::CorruptedDriveState( + "shielded pool total balance overflow when adding shield_from_asset_lock amount".to_string(), + ), + ))?; + ops.push(DriveOperation::ShieldedPoolOperation( + QualifiedGroveDbOp::insert_or_replace_op( + pool_path, + vec![SHIELDED_TOTAL_BALANCE_KEY], + Element::new_sum_item(new_total_balance as i64), + ), + )); + + // 6. Record anchor after batch is applied + ops.push(DriveOperation::FinalizeOperation( + DriveOperationFinalizeTask::RecordShieldedAnchor, + )); + + Ok(ops) + } + } + } +} + +impl DriveHighLevelOperationConverter for ShieldedWithdrawalTransitionAction { + fn into_high_level_drive_operations<'a>( + self, + _epoch: &Epoch, + _platform_version: &PlatformVersion, + ) -> Result>, Error> { + match self { + ShieldedWithdrawalTransitionAction::V0(v0) => { + let mut ops: Vec> = Vec::new(); + + let nullifiers_path = shielded_credit_pool_nullifiers_path_vec(); + let encrypted_notes_path = shielded_credit_pool_encrypted_notes_path_vec(); + let pool_path = shielded_credit_pool_path_vec(); + + // 1. Insert nullifiers (prevent double-spend) + for nullifier in v0.nullifiers.iter() { + ops.push(DriveOperation::ShieldedPoolOperation( + QualifiedGroveDbOp::insert_only_op( + nullifiers_path.clone(), + nullifier.to_vec(), + Element::new_item(vec![]), + ), + )); + } + + // 2. Append change note commitments to commitment tree + for cmx in v0.note_commitments.iter() { + ops.push(DriveOperation::ShieldedPoolOperation( + QualifiedGroveDbOp::commitment_tree_append_op( + pool_path.clone(), + vec![SHIELDED_COMMITMENTS_KEY], + *cmx, + ), + )); + } + + // 3. Insert encrypted change notes + for (cmx, encrypted_note) in + v0.note_commitments.iter().zip(v0.encrypted_notes.iter()) + { + ops.push(DriveOperation::ShieldedPoolOperation( + QualifiedGroveDbOp::insert_only_op( + encrypted_notes_path.clone(), + cmx.to_vec(), + Element::new_item(encrypted_note.clone()), + ), + )); + } + + // 4. Update total balance: subtract withdrawal amount + let new_total_balance = v0 + .current_total_balance + .checked_sub(v0.amount) + .ok_or_else(|| Error::Drive( + crate::error::drive::DriveError::CorruptedDriveState( + "shielded pool total balance underflow when subtracting shielded_withdrawal amount".to_string(), + ), + ))?; + ops.push(DriveOperation::ShieldedPoolOperation( + QualifiedGroveDbOp::insert_or_replace_op( + pool_path, + vec![SHIELDED_TOTAL_BALANCE_KEY], + Element::new_sum_item(new_total_balance as i64), + ), + )); + + // 5. Add withdrawal document + ops.push(DriveOperation::DocumentOperation( + DocumentOperationType::AddWithdrawalDocument { + owned_document_info: OwnedDocumentInfo { + document_info: DocumentInfo::DocumentOwnedInfo(( + v0.prepared_withdrawal_document, + None, + )), + owner_id: None, + }, + }, + )); + + // 6. Remove credits from system (they leave the system to Core) + ops.push(DriveOperation::SystemOperation( + SystemOperationType::RemoveFromSystemCredits { + amount: v0.amount, + }, + )); + + // 7. Record anchor after batch is applied + ops.push(DriveOperation::FinalizeOperation( + DriveOperationFinalizeTask::RecordShieldedAnchor, + )); + + Ok(ops) + } + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/mod.rs index 7f955432044..b45a2d3dfb4 100644 --- a/packages/rs-drive/src/state_transition_action/mod.rs +++ b/packages/rs-drive/src/state_transition_action/mod.rs @@ -30,7 +30,9 @@ use crate::state_transition_action::identity::identity_topup_from_addresses::Ide use crate::state_transition_action::identity::identity_update::IdentityUpdateTransitionAction; use crate::state_transition_action::identity::masternode_vote::MasternodeVoteTransitionAction; use crate::state_transition_action::shielded::shield::ShieldTransitionAction; +use crate::state_transition_action::shielded::shield_from_asset_lock::ShieldFromAssetLockTransitionAction; use crate::state_transition_action::shielded::shielded_transfer::ShieldedTransferTransitionAction; +use crate::state_transition_action::shielded::shielded_withdrawal::ShieldedWithdrawalTransitionAction; use crate::state_transition_action::shielded::unshield::UnshieldTransitionAction; use crate::state_transition_action::system::bump_address_input_nonces_action::{ BumpAddressInputNonceActionAccessorsV0, BumpAddressInputNoncesAction, @@ -101,6 +103,10 @@ pub enum StateTransitionAction { ShieldedTransferAction(ShieldedTransferTransitionAction), /// unshield (shielded pool -> address) UnshieldAction(UnshieldTransitionAction), + /// shield from asset lock (L1 asset lock -> shielded pool) + ShieldFromAssetLockAction(ShieldFromAssetLockTransitionAction), + /// shielded withdrawal (shielded pool -> L1 core address) + ShieldedWithdrawalAction(ShieldedWithdrawalTransitionAction), } impl StateTransitionAction { @@ -149,6 +155,12 @@ impl StateTransitionAction { StateTransitionAction::ShieldAction(action) => action.user_fee_increase(), StateTransitionAction::ShieldedTransferAction(action) => action.user_fee_increase(), StateTransitionAction::UnshieldAction(action) => action.user_fee_increase(), + StateTransitionAction::ShieldFromAssetLockAction(action) => { + action.user_fee_increase() + } + StateTransitionAction::ShieldedWithdrawalAction(action) => { + action.user_fee_increase() + } } } } diff --git a/packages/rs-drive/src/state_transition_action/shielded/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/mod.rs index 0fad9d78d6d..b28bf298a38 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/mod.rs @@ -1,6 +1,10 @@ /// Shield transition action pub mod shield; +/// Shield from asset lock transition action +pub mod shield_from_asset_lock; /// Shielded transfer transition action pub mod shielded_transfer; +/// Shielded withdrawal transition action +pub mod shielded_withdrawal; /// Unshield transition action pub mod unshield; diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/mod.rs new file mode 100644 index 00000000000..ab7113c10c1 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/mod.rs @@ -0,0 +1,67 @@ +/// transformer +pub mod transformer; +/// v0 +pub mod v0; + +use crate::state_transition_action::shielded::shield_from_asset_lock::v0::ShieldFromAssetLockTransitionActionV0; +use derive_more::From; +use dpp::fee::Credits; +use dpp::prelude::UserFeeIncrease; + +/// Shield from asset lock transition action +#[derive(Debug, Clone, From)] +pub enum ShieldFromAssetLockTransitionAction { + /// v0 + V0(ShieldFromAssetLockTransitionActionV0), +} + +impl ShieldFromAssetLockTransitionAction { + /// Get asset lock outpoint + pub fn asset_lock_outpoint(&self) -> &[u8; 36] { + match self { + ShieldFromAssetLockTransitionAction::V0(transition) => { + &transition.asset_lock_outpoint + } + } + } + /// Get remaining asset lock value to be consumed + pub fn asset_lock_value_to_be_consumed(&self) -> Credits { + match self { + ShieldFromAssetLockTransitionAction::V0(transition) => { + transition.asset_lock_value_to_be_consumed + } + } + } + /// Get signable bytes hasher + pub fn signable_bytes_hasher(&self) -> &[u8; 32] { + match self { + ShieldFromAssetLockTransitionAction::V0(transition) => { + &transition.signable_bytes_hasher + } + } + } + /// Get the shield amount + pub fn shield_amount(&self) -> Credits { + match self { + ShieldFromAssetLockTransitionAction::V0(transition) => transition.shield_amount, + } + } + /// Get note commitments + pub fn note_commitments(&self) -> &Vec<[u8; 32]> { + match self { + ShieldFromAssetLockTransitionAction::V0(transition) => &transition.note_commitments, + } + } + /// Get encrypted notes + pub fn encrypted_notes(&self) -> &Vec> { + match self { + ShieldFromAssetLockTransitionAction::V0(transition) => &transition.encrypted_notes, + } + } + /// fee multiplier + pub fn user_fee_increase(&self) -> UserFeeIncrease { + match self { + ShieldFromAssetLockTransitionAction::V0(transition) => transition.user_fee_increase, + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/transformer.rs new file mode 100644 index 00000000000..8c61167af79 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/transformer.rs @@ -0,0 +1,35 @@ +use crate::state_transition_action::shielded::shield_from_asset_lock::v0::ShieldFromAssetLockTransitionActionV0; +use crate::state_transition_action::shielded::shield_from_asset_lock::ShieldFromAssetLockTransitionAction; +use dpp::fee::Credits; +use dpp::prelude::ConsensusValidationResult; +use dpp::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; + +impl ShieldFromAssetLockTransitionAction { + /// Transforms the state transition into an action + pub fn try_from_transition( + value: &ShieldFromAssetLockTransition, + asset_lock_outpoint: [u8; 36], + asset_lock_value_to_be_consumed: Credits, + signable_bytes_hasher: [u8; 32], + shield_amount: Credits, + note_commitments: Vec<[u8; 32]>, + encrypted_notes: Vec>, + current_total_balance: Credits, + ) -> ConsensusValidationResult { + match value { + ShieldFromAssetLockTransition::V0(v0) => { + let result = ShieldFromAssetLockTransitionActionV0::try_from_transition( + v0, + asset_lock_outpoint, + asset_lock_value_to_be_consumed, + signable_bytes_hasher, + shield_amount, + note_commitments, + encrypted_notes, + current_total_balance, + ); + result.map(|action| action.into()) + } + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/mod.rs new file mode 100644 index 00000000000..cb11bc5c7a4 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/mod.rs @@ -0,0 +1,25 @@ +mod transformer; + +use dpp::fee::Credits; +use dpp::prelude::UserFeeIncrease; + +/// Shield from asset lock transition action v0 +#[derive(Debug, Clone)] +pub struct ShieldFromAssetLockTransitionActionV0 { + /// Asset lock outpoint bytes (txid + vout) + pub asset_lock_outpoint: [u8; 36], + /// Remaining asset lock value to be consumed + pub asset_lock_value_to_be_consumed: Credits, + /// SHA256(signable_bytes) for replay protection + pub signable_bytes_hasher: [u8; 32], + /// Amount going into shielded pool (|value_balance|) + pub shield_amount: Credits, + /// Note commitments from the orchard bundle (cmx values) + pub note_commitments: Vec<[u8; 32]>, + /// Encrypted notes from the orchard bundle + pub encrypted_notes: Vec>, + /// fee multiplier + pub user_fee_increase: UserFeeIncrease, + /// Current total balance of the shielded pool + pub current_total_balance: Credits, +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/transformer.rs new file mode 100644 index 00000000000..c4f4b68a75d --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/transformer.rs @@ -0,0 +1,29 @@ +use crate::state_transition_action::shielded::shield_from_asset_lock::v0::ShieldFromAssetLockTransitionActionV0; +use dpp::fee::Credits; +use dpp::prelude::ConsensusValidationResult; +use dpp::state_transition::state_transitions::shielded::shield_from_asset_lock_transition::v0::ShieldFromAssetLockTransitionV0; + +impl ShieldFromAssetLockTransitionActionV0 { + /// Transforms the shield from asset lock transition into an action + pub fn try_from_transition( + value: &ShieldFromAssetLockTransitionV0, + asset_lock_outpoint: [u8; 36], + asset_lock_value_to_be_consumed: Credits, + signable_bytes_hasher: [u8; 32], + shield_amount: Credits, + note_commitments: Vec<[u8; 32]>, + encrypted_notes: Vec>, + current_total_balance: Credits, + ) -> ConsensusValidationResult { + ConsensusValidationResult::new_with_data(ShieldFromAssetLockTransitionActionV0 { + asset_lock_outpoint, + asset_lock_value_to_be_consumed, + signable_bytes_hasher, + shield_amount, + note_commitments, + encrypted_notes, + user_fee_increase: value.user_fee_increase, + current_total_balance, + }) + } +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/mod.rs new file mode 100644 index 00000000000..b9b8b4f54db --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/mod.rs @@ -0,0 +1,92 @@ +/// transformer +pub mod transformer; +/// v0 +pub mod v0; + +use crate::state_transition_action::shielded::shielded_withdrawal::v0::ShieldedWithdrawalTransitionActionV0; +use derive_more::From; +use dpp::document::Document; +use dpp::fee::Credits; +use dpp::identity::core_script::CoreScript; +use dpp::prelude::UserFeeIncrease; +use dpp::withdrawal::Pooling; + +/// Shielded withdrawal transition action +#[derive(Debug, Clone, From)] +pub enum ShieldedWithdrawalTransitionAction { + /// v0 + V0(ShieldedWithdrawalTransitionActionV0), +} + +impl ShieldedWithdrawalTransitionAction { + /// Get withdrawal amount + pub fn amount(&self) -> Credits { + match self { + ShieldedWithdrawalTransitionAction::V0(transition) => transition.amount, + } + } + /// Get nullifiers + pub fn nullifiers(&self) -> &Vec<[u8; 32]> { + match self { + ShieldedWithdrawalTransitionAction::V0(transition) => &transition.nullifiers, + } + } + /// Get note commitments + pub fn note_commitments(&self) -> &Vec<[u8; 32]> { + match self { + ShieldedWithdrawalTransitionAction::V0(transition) => &transition.note_commitments, + } + } + /// Get encrypted notes + pub fn encrypted_notes(&self) -> &Vec> { + match self { + ShieldedWithdrawalTransitionAction::V0(transition) => &transition.encrypted_notes, + } + } + /// Get anchor + pub fn anchor(&self) -> &[u8; 32] { + match self { + ShieldedWithdrawalTransitionAction::V0(transition) => &transition.anchor, + } + } + /// Get core fee per byte + pub fn core_fee_per_byte(&self) -> u32 { + match self { + ShieldedWithdrawalTransitionAction::V0(transition) => transition.core_fee_per_byte, + } + } + /// Get pooling strategy + pub fn pooling(&self) -> Pooling { + match self { + ShieldedWithdrawalTransitionAction::V0(transition) => transition.pooling, + } + } + /// Get output script + pub fn output_script(&self) -> &CoreScript { + match self { + ShieldedWithdrawalTransitionAction::V0(transition) => &transition.output_script, + } + } + /// fee multiplier + pub fn user_fee_increase(&self) -> UserFeeIncrease { + match self { + ShieldedWithdrawalTransitionAction::V0(transition) => transition.user_fee_increase, + } + } + /// Get prepared withdrawal document + pub fn prepared_withdrawal_document(&self) -> &Document { + match self { + ShieldedWithdrawalTransitionAction::V0(transition) => { + &transition.prepared_withdrawal_document + } + } + } + /// Get prepared withdrawal document owned + pub fn prepared_withdrawal_document_owned(self) -> Document { + match self { + ShieldedWithdrawalTransitionAction::V0(transition) => { + transition.prepared_withdrawal_document + } + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/transformer.rs new file mode 100644 index 00000000000..e20d74f59cd --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/transformer.rs @@ -0,0 +1,33 @@ +use crate::state_transition_action::shielded::shielded_withdrawal::v0::ShieldedWithdrawalTransitionActionV0; +use crate::state_transition_action::shielded::shielded_withdrawal::ShieldedWithdrawalTransitionAction; +use dpp::fee::Credits; +use dpp::prelude::ConsensusValidationResult; +use dpp::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; + +impl ShieldedWithdrawalTransitionAction { + /// Transforms the state transition into an action + pub fn try_from_transition( + value: &ShieldedWithdrawalTransition, + nullifiers: Vec<[u8; 32]>, + note_commitments: Vec<[u8; 32]>, + encrypted_notes: Vec>, + anchor: [u8; 32], + current_total_balance: Credits, + creation_time_ms: u64, + ) -> ConsensusValidationResult { + match value { + ShieldedWithdrawalTransition::V0(v0) => { + let result = ShieldedWithdrawalTransitionActionV0::try_from_transition( + v0, + nullifiers, + note_commitments, + encrypted_notes, + anchor, + current_total_balance, + creation_time_ms, + ); + result.map(|action| action.into()) + } + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/mod.rs new file mode 100644 index 00000000000..9f2e4f465cf --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/mod.rs @@ -0,0 +1,34 @@ +mod transformer; + +use dpp::document::Document; +use dpp::fee::Credits; +use dpp::identity::core_script::CoreScript; +use dpp::prelude::UserFeeIncrease; +use dpp::withdrawal::Pooling; + +/// Shielded withdrawal transition action v0 +#[derive(Debug, Clone)] +pub struct ShieldedWithdrawalTransitionActionV0 { + /// Withdrawal amount in credits + pub amount: Credits, + /// Nullifiers from spent notes + pub nullifiers: Vec<[u8; 32]>, + /// Note commitments for change outputs + pub note_commitments: Vec<[u8; 32]>, + /// Encrypted change notes + pub encrypted_notes: Vec>, + /// Merkle root used for spends + pub anchor: [u8; 32], + /// Core transaction fee rate + pub core_fee_per_byte: u32, + /// Withdrawal pooling strategy + pub pooling: Pooling, + /// Core address receiving funds + pub output_script: CoreScript, + /// fee multiplier + pub user_fee_increase: UserFeeIncrease, + /// Current total balance of the shielded pool + pub current_total_balance: Credits, + /// Pre-built withdrawal document (status: QUEUED) + pub prepared_withdrawal_document: Document, +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/transformer.rs new file mode 100644 index 00000000000..34e2054803f --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/transformer.rs @@ -0,0 +1,78 @@ +use crate::state_transition_action::shielded::shielded_withdrawal::v0::ShieldedWithdrawalTransitionActionV0; +use dpp::data_contracts::withdrawals_contract; +use dpp::data_contracts::withdrawals_contract::v1::document_types::withdrawal; +use dpp::document::{Document, DocumentV0}; +use dpp::fee::Credits; +use dpp::platform_value::platform_value; +use dpp::prelude::ConsensusValidationResult; +use dpp::state_transition::state_transitions::shielded::shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0; + +impl ShieldedWithdrawalTransitionActionV0 { + /// Transforms the shielded withdrawal transition into an action + pub fn try_from_transition( + value: &ShieldedWithdrawalTransitionV0, + nullifiers: Vec<[u8; 32]>, + note_commitments: Vec<[u8; 32]>, + encrypted_notes: Vec>, + anchor: [u8; 32], + current_total_balance: Credits, + creation_time_ms: u64, + ) -> ConsensusValidationResult { + // Generate entropy from first nullifier + output_script for document ID + let mut entropy = Vec::new(); + if let Some(first_nullifier) = nullifiers.first() { + entropy.extend_from_slice(first_nullifier); + } + entropy.extend_from_slice(value.output_script.as_bytes()); + + // The owner_id is the contract owner + let owner_id = withdrawals_contract::OWNER_ID; + + let document_id = Document::generate_document_id_v0( + &withdrawals_contract::ID, + &owner_id, + withdrawal::NAME, + &entropy, + ); + + let document_data = platform_value!({ + withdrawal::properties::AMOUNT: value.amount, + withdrawal::properties::CORE_FEE_PER_BYTE: value.core_fee_per_byte, + withdrawal::properties::POOLING: value.pooling, + withdrawal::properties::OUTPUT_SCRIPT: value.output_script.as_bytes(), + withdrawal::properties::STATUS: withdrawals_contract::WithdrawalStatus::QUEUED, + }); + + let withdrawal_document = DocumentV0 { + id: document_id, + owner_id, + properties: document_data.into_btree_string_map().unwrap(), + revision: Some(1), + created_at: Some(creation_time_ms), + updated_at: Some(creation_time_ms), + transferred_at: None, + created_at_block_height: None, + updated_at_block_height: None, + transferred_at_block_height: None, + created_at_core_block_height: None, + updated_at_core_block_height: None, + transferred_at_core_block_height: None, + creator_id: None, + } + .into(); + + ConsensusValidationResult::new_with_data(ShieldedWithdrawalTransitionActionV0 { + amount: value.amount, + nullifiers, + note_commitments, + encrypted_notes, + anchor, + core_fee_per_byte: value.core_fee_per_byte, + pooling: value.pooling, + output_script: value.output_script.clone(), + user_fee_increase: value.user_fee_increase, + current_total_balance, + prepared_withdrawal_document: withdrawal_document, + }) + } +} diff --git a/packages/rs-drive/src/state_transition_action/system/partially_use_asset_lock_action/mod.rs b/packages/rs-drive/src/state_transition_action/system/partially_use_asset_lock_action/mod.rs index bfd70ca3d27..c6e8106f89f 100644 --- a/packages/rs-drive/src/state_transition_action/system/partially_use_asset_lock_action/mod.rs +++ b/packages/rs-drive/src/state_transition_action/system/partially_use_asset_lock_action/mod.rs @@ -1,4 +1,3 @@ -use crate::state_transition_action::system::partially_use_asset_lock_action::v0::PartiallyUseAssetLockActionV0; use derive_more::From; use dpp::address_funds::{AddressFundsFeeStrategy, PlatformAddress}; use dpp::fee::Credits; @@ -9,7 +8,9 @@ use std::collections::BTreeMap; mod transformer; mod v0; -pub use v0::PartiallyUseAssetLockActionAccessorsV0; +pub use v0::{ + PartiallyUseAssetLockActionAccessorsV0, PartiallyUseAssetLockActionV0, +}; #[derive(Debug, Clone, From)] /// An action expressing that an asset lock should be partially used diff --git a/packages/rs-drive/src/state_transition_action/system/partially_use_asset_lock_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/system/partially_use_asset_lock_action/v0/mod.rs index 0179e9179b0..91f31c70432 100644 --- a/packages/rs-drive/src/state_transition_action/system/partially_use_asset_lock_action/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/system/partially_use_asset_lock_action/v0/mod.rs @@ -5,6 +5,7 @@ use dpp::prelude::{AddressNonce, UserFeeIncrease}; use std::collections::BTreeMap; mod transformer; +/// Partially use asset lock action v0 #[derive(Default, Debug, Clone)] pub struct PartiallyUseAssetLockActionV0 { /// asset lock outpoint diff --git a/packages/rs-drive/src/verify/mod.rs b/packages/rs-drive/src/verify/mod.rs index 10bbd254b1b..a8edff11378 100644 --- a/packages/rs-drive/src/verify/mod.rs +++ b/packages/rs-drive/src/verify/mod.rs @@ -22,6 +22,8 @@ pub mod state_transition; pub mod tokens; /// Voting proof verification module pub mod voting; +/// Shielded pool proof verification module +pub mod shielded; /// Represents the root hash of the grovedb tree pub type RootHash = [u8; 32]; diff --git a/packages/rs-drive/src/verify/shielded/mod.rs b/packages/rs-drive/src/verify/shielded/mod.rs new file mode 100644 index 00000000000..fac116b3830 --- /dev/null +++ b/packages/rs-drive/src/verify/shielded/mod.rs @@ -0,0 +1,8 @@ +/// Module for verifying shielded pool state (total balance) +pub mod verify_shielded_pool_state; +/// Module for verifying shielded anchors +pub mod verify_shielded_anchors; +/// Module for verifying shielded encrypted notes +pub mod verify_shielded_encrypted_notes; +/// Module for verifying shielded nullifiers +pub mod verify_shielded_nullifiers; diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/mod.rs new file mode 100644 index 00000000000..6711040c20e --- /dev/null +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/mod.rs @@ -0,0 +1,30 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::verify::RootHash; +use dpp::version::PlatformVersion; + +impl Drive { + /// Verifies a proof for the valid shielded anchors. + pub fn verify_shielded_anchors( + proof: &[u8], + platform_version: &PlatformVersion, + ) -> Result<(RootHash, Vec>), Error> { + match platform_version + .drive + .methods + .verify + .shielded + .verify_shielded_anchors + { + 0 => Self::verify_shielded_anchors_v0(proof, platform_version), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_shielded_anchors".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs new file mode 100644 index 00000000000..af9c15b1a1e --- /dev/null +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs @@ -0,0 +1,35 @@ +use crate::drive::shielded::paths::shielded_anchors_credit_pool_path_vec; +use crate::drive::Drive; +use crate::error::Error; +use crate::verify::RootHash; +use grovedb::{GroveDb, PathQuery, Query, SizedQuery}; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn verify_shielded_anchors_v0( + proof: &[u8], + platform_version: &PlatformVersion, + ) -> Result<(RootHash, Vec>), Error> { + let path_query = PathQuery { + path: shielded_anchors_credit_pool_path_vec(), + query: SizedQuery { + query: Query::new_range_full(), + limit: None, + offset: None, + }, + }; + + let (root_hash, proved_key_values) = GroveDb::verify_query( + proof, + &path_query, + &platform_version.drive.grove_version, + )?; + + let anchors = proved_key_values + .into_iter() + .map(|(_, key, _)| key) + .collect(); + + Ok((root_hash, anchors)) + } +} diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/mod.rs new file mode 100644 index 00000000000..5c4da081688 --- /dev/null +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/mod.rs @@ -0,0 +1,39 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::verify::RootHash; +use dpp::version::PlatformVersion; + +impl Drive { + /// Verifies a proof for shielded encrypted notes. + pub fn verify_shielded_encrypted_notes( + proof: &[u8], + start_cmx: &[u8], + count: u32, + max_elements: u32, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, Vec<(Vec, Vec)>), Error> { + match platform_version + .drive + .methods + .verify + .shielded + .verify_shielded_encrypted_notes + { + 0 => Self::verify_shielded_encrypted_notes_v0( + proof, + start_cmx, + count, + max_elements, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_shielded_encrypted_notes".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs new file mode 100644 index 00000000000..32750854957 --- /dev/null +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs @@ -0,0 +1,58 @@ +use crate::drive::shielded::paths::shielded_credit_pool_encrypted_notes_path_vec; +use crate::drive::Drive; +use crate::error::Error; +use crate::verify::RootHash; +use grovedb::{Element, GroveDb, PathQuery, Query, SizedQuery}; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn verify_shielded_encrypted_notes_v0( + proof: &[u8], + start_cmx: &[u8], + count: u32, + max_elements: u32, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, Vec<(Vec, Vec)>), Error> { + let limit = if count == 0 || count > max_elements { + max_elements as u16 + } else { + count as u16 + }; + + let query = if start_cmx.is_empty() { + Query::new_range_full() + } else { + let mut q = Query::new(); + q.insert_range_after(start_cmx.to_vec()..); + q + }; + + let path_query = PathQuery { + path: shielded_credit_pool_encrypted_notes_path_vec(), + query: SizedQuery { + query, + limit: Some(limit), + offset: None, + }, + }; + + let (root_hash, proved_key_values) = GroveDb::verify_query( + proof, + &path_query, + &platform_version.drive.grove_version, + )?; + + let notes = proved_key_values + .into_iter() + .filter_map(|(_, key, maybe_element)| { + if let Some(Element::Item(bytes, _)) = maybe_element { + Some((key, bytes)) + } else { + None + } + }) + .collect(); + + Ok((root_hash, notes)) + } +} diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/mod.rs new file mode 100644 index 00000000000..a15cdff5cd4 --- /dev/null +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/mod.rs @@ -0,0 +1,31 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::verify::RootHash; +use dpp::version::PlatformVersion; + +impl Drive { + /// Verifies a proof for shielded nullifier spend status. + pub fn verify_shielded_nullifiers( + proof: &[u8], + nullifiers: &[Vec], + platform_version: &PlatformVersion, + ) -> Result<(RootHash, Vec<(Vec, bool)>), Error> { + match platform_version + .drive + .methods + .verify + .shielded + .verify_shielded_nullifiers + { + 0 => Self::verify_shielded_nullifiers_v0(proof, nullifiers, platform_version), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_shielded_nullifiers".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/v0/mod.rs new file mode 100644 index 00000000000..5afac90dcb9 --- /dev/null +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/v0/mod.rs @@ -0,0 +1,43 @@ +use crate::drive::shielded::paths::shielded_credit_pool_nullifiers_path_vec; +use crate::drive::Drive; +use crate::error::Error; +use crate::verify::RootHash; +use grovedb::{GroveDb, PathQuery, Query, SizedQuery}; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn verify_shielded_nullifiers_v0( + proof: &[u8], + nullifiers: &[Vec], + platform_version: &PlatformVersion, + ) -> Result<(RootHash, Vec<(Vec, bool)>), Error> { + let mut query = Query::new(); + query.insert_keys(nullifiers.to_vec()); + + let path_query = PathQuery { + path: shielded_credit_pool_nullifiers_path_vec(), + query: SizedQuery { + query, + limit: None, + offset: None, + }, + }; + + let (root_hash, proved_key_values) = GroveDb::verify_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )?; + + // Map each proved entry: if element is Some, nullifier is spent; if None, not spent + let statuses = proved_key_values + .into_iter() + .map(|(_, key, maybe_element)| { + let is_spent = maybe_element.is_some(); + (key, is_spent) + }) + .collect(); + + Ok((root_hash, statuses)) + } +} diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_pool_state/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_pool_state/mod.rs new file mode 100644 index 00000000000..a515650ea12 --- /dev/null +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_pool_state/mod.rs @@ -0,0 +1,30 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::verify::RootHash; +use dpp::version::PlatformVersion; + +impl Drive { + /// Verifies a proof for the shielded pool total balance. + pub fn verify_shielded_pool_state( + proof: &[u8], + platform_version: &PlatformVersion, + ) -> Result<(RootHash, Option), Error> { + match platform_version + .drive + .methods + .verify + .shielded + .verify_shielded_pool_state + { + 0 => Self::verify_shielded_pool_state_v0(proof, platform_version), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_shielded_pool_state".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_pool_state/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_pool_state/v0/mod.rs new file mode 100644 index 00000000000..39809d6096d --- /dev/null +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_pool_state/v0/mod.rs @@ -0,0 +1,58 @@ +use crate::drive::shielded::paths::{shielded_credit_pool_path_vec, SHIELDED_TOTAL_BALANCE_KEY}; +use crate::drive::Drive; +use crate::error::proof::ProofError; +use crate::error::Error; +use crate::verify::RootHash; +use grovedb::{Element, GroveDb, PathQuery, Query, SizedQuery}; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn verify_shielded_pool_state_v0( + proof: &[u8], + platform_version: &PlatformVersion, + ) -> Result<(RootHash, Option), Error> { + let path_query = PathQuery { + path: shielded_credit_pool_path_vec(), + query: SizedQuery { + query: Query::new_single_key(vec![SHIELDED_TOTAL_BALANCE_KEY]), + limit: Some(1), + offset: None, + }, + }; + + let (root_hash, mut proved_key_values) = GroveDb::verify_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )?; + + if proved_key_values.len() > 1 { + return Err(Error::Proof(ProofError::TooManyElements( + "expected at most 1 element for shielded pool state", + ))); + } + + let balance = if let Some(proved) = proved_key_values.pop() { + match proved.2 { + Some(Element::SumItem(value, _)) => { + if value < 0 { + return Err(Error::Proof(ProofError::CorruptedProof( + "shielded pool balance cannot be negative".to_string(), + ))); + } + Some(value as u64) + } + Some(_) => { + return Err(Error::Proof(ProofError::CorruptedProof( + "expected a sum item for shielded pool balance".to_string(), + ))); + } + None => None, + } + } else { + None + }; + + Ok((root_hash, balance)) + } +} diff --git a/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs b/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs index 3b9fd00d9f4..044cd9854e4 100644 --- a/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs +++ b/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs @@ -1117,9 +1117,13 @@ impl Drive { } StateTransition::Shield(_) | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) => Err(Error::Proof(ProofError::InvalidTransition( - "shielded state transitions do not support proof verification yet".to_string(), - ))), + | StateTransition::Unshield(_) + | StateTransition::ShieldFromAssetLock(_) + | StateTransition::ShieldedWithdrawal(_) => { + Err(Error::Proof(ProofError::InvalidTransition( + "shielded state transitions do not support proof verification yet".to_string(), + ))) + } } } } diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/mod.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/mod.rs index 947dbd6dd46..5b6a458dc38 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/mod.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/mod.rs @@ -31,6 +31,8 @@ pub struct DPPStateTransitionSerializationVersions { pub shield_state_transition: FeatureVersionBounds, pub shielded_transfer_state_transition: FeatureVersionBounds, pub unshield_state_transition: FeatureVersionBounds, + pub shield_from_asset_lock_state_transition: FeatureVersionBounds, + pub shielded_withdrawal_state_transition: FeatureVersionBounds, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v1.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v1.rs index 6524e176cf3..478f87dee89 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v1.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v1.rs @@ -147,4 +147,14 @@ pub const STATE_TRANSITION_SERIALIZATION_VERSIONS_V1: DPPStateTransitionSerializ max_version: 0, default_current_version: 0, }, + shield_from_asset_lock_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + shielded_withdrawal_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, }; diff --git a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v2.rs b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v2.rs index 0c1c9762333..b2b12cae1af 100644 --- a/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v2.rs +++ b/packages/rs-platform-version/src/version/dpp_versions/dpp_state_transition_serialization_versions/v2.rs @@ -147,4 +147,14 @@ pub const STATE_TRANSITION_SERIALIZATION_VERSIONS_V2: DPPStateTransitionSerializ max_version: 0, default_current_version: 0, }, + shield_from_asset_lock_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + shielded_withdrawal_state_transition: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs index df96bd63440..a9e147a8528 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs @@ -17,6 +17,7 @@ pub struct DriveAbciQueryVersions { pub system: DriveAbciQuerySystemVersions, pub group_queries: DriveAbciQueryGroupVersions, pub address_funds_queries: DriveAbciQueryAddressFundsVersions, + pub shielded_queries: DriveAbciQueryShieldedVersions, } #[derive(Clone, Debug, Default)] @@ -92,6 +93,14 @@ pub struct DriveAbciQueryDataContractVersions { pub data_contracts: FeatureVersionBounds, } +#[derive(Clone, Debug, Default)] +pub struct DriveAbciQueryShieldedVersions { + pub encrypted_notes: FeatureVersionBounds, + pub anchors: FeatureVersionBounds, + pub pool_state: FeatureVersionBounds, + pub nullifiers: FeatureVersionBounds, +} + #[derive(Clone, Debug, Default)] pub struct DriveAbciQuerySystemVersions { pub version_upgrade_state: FeatureVersionBounds, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs index 9a9652733fa..61227ee6a9f 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs @@ -1,9 +1,9 @@ use crate::version::drive_abci_versions::drive_abci_query_versions::{ DriveAbciQueryAddressFundsVersions, DriveAbciQueryDataContractVersions, DriveAbciQueryGroupVersions, DriveAbciQueryIdentityVersions, - DriveAbciQueryPrefundedSpecializedBalancesVersions, DriveAbciQuerySystemVersions, - DriveAbciQueryTokenVersions, DriveAbciQueryValidatorVersions, DriveAbciQueryVersions, - DriveAbciQueryVotingVersions, + DriveAbciQueryPrefundedSpecializedBalancesVersions, DriveAbciQueryShieldedVersions, + DriveAbciQuerySystemVersions, DriveAbciQueryTokenVersions, DriveAbciQueryValidatorVersions, + DriveAbciQueryVersions, DriveAbciQueryVotingVersions, }; use versioned_feature_core::FeatureVersionBounds; @@ -247,6 +247,28 @@ pub const DRIVE_ABCI_QUERY_VERSIONS_V1: DriveAbciQueryVersions = DriveAbciQueryV default_current_version: 0, }, }, + shielded_queries: DriveAbciQueryShieldedVersions { + encrypted_notes: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + anchors: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + pool_state: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + nullifiers: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + }, address_funds_queries: DriveAbciQueryAddressFundsVersions { addresses_infos: FeatureVersionBounds { min_version: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/mod.rs index cd1be732674..7f68f5fb613 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 @@ -63,6 +63,8 @@ pub struct DriveAbciStateTransitionValidationVersions { pub shield_state_transition: DriveAbciStateTransitionValidationVersion, pub shielded_transfer_state_transition: DriveAbciStateTransitionValidationVersion, pub unshield_state_transition: DriveAbciStateTransitionValidationVersion, + pub shield_from_asset_lock_state_transition: DriveAbciStateTransitionValidationVersion, + pub shielded_withdrawal_state_transition: DriveAbciStateTransitionValidationVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs index 0b919b3ba6e..53b31b49e4c 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs @@ -224,6 +224,22 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V1: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, + shield_from_asset_lock_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + shielded_withdrawal_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, }, has_nonce_validation: 0, has_address_witness_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs index 7f07ee00a91..19e77ba362c 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs @@ -224,6 +224,22 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V2: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, + shield_from_asset_lock_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + shielded_withdrawal_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, }, has_nonce_validation: 0, has_address_witness_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs index a4beaa2fb87..dbbb6bcd9b5 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs @@ -224,6 +224,22 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V3: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, + shield_from_asset_lock_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + shielded_withdrawal_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, }, has_nonce_validation: 0, has_address_witness_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v4.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v4.rs index 228a3c3d8bc..0d17c1c432c 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 @@ -227,6 +227,22 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V4: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, + shield_from_asset_lock_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + shielded_withdrawal_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, }, has_nonce_validation: 1, // <---- changed this has_address_witness_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs index 0aa70e5f460..6368e6927d3 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs @@ -228,6 +228,22 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V5: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, + shield_from_asset_lock_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + shielded_withdrawal_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, }, has_nonce_validation: 1, has_address_witness_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs index 78c31aefa9c..18bfcbbe660 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs @@ -231,6 +231,22 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V6: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, + shield_from_asset_lock_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + shielded_withdrawal_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, }, has_nonce_validation: 1, has_address_witness_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs index f5d4ea5e209..422cb31cf27 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs @@ -225,6 +225,22 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V7: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, + shield_from_asset_lock_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + shielded_withdrawal_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, }, has_nonce_validation: 1, has_address_witness_validation: 0, diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs index 8e979270ce8..aa602a504c6 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs @@ -14,6 +14,15 @@ pub struct DriveVerifyMethodVersions { pub voting: DriveVerifyVoteMethodVersions, pub address_funds: DriveVerifyAddressFundsMethodVersions, pub state_transition: DriveVerifyStateTransitionMethodVersions, + pub shielded: DriveVerifyShieldedMethodVersions, +} + +#[derive(Clone, Debug, Default)] +pub struct DriveVerifyShieldedMethodVersions { + pub verify_shielded_pool_state: FeatureVersion, + pub verify_shielded_anchors: FeatureVersion, + pub verify_shielded_encrypted_notes: FeatureVersion, + pub verify_shielded_nullifiers: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs index 7c255e83a78..288c009b854 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs @@ -2,8 +2,9 @@ use crate::version::drive_versions::drive_verify_method_versions::{ DriveVerifyAddressFundsMethodVersions, DriveVerifyContractMethodVersions, DriveVerifyDocumentMethodVersions, DriveVerifyGroupMethodVersions, DriveVerifyIdentityMethodVersions, DriveVerifyMethodVersions, - DriveVerifySingleDocumentMethodVersions, DriveVerifyStateTransitionMethodVersions, - DriveVerifySystemMethodVersions, DriveVerifyTokenMethodVersions, DriveVerifyVoteMethodVersions, + DriveVerifyShieldedMethodVersions, DriveVerifySingleDocumentMethodVersions, + DriveVerifyStateTransitionMethodVersions, DriveVerifySystemMethodVersions, + DriveVerifyTokenMethodVersions, DriveVerifyVoteMethodVersions, }; pub const DRIVE_VERIFY_METHOD_VERSIONS_V1: DriveVerifyMethodVersions = DriveVerifyMethodVersions { @@ -90,4 +91,10 @@ pub const DRIVE_VERIFY_METHOD_VERSIONS_V1: DriveVerifyMethodVersions = DriveVeri state_transition: DriveVerifyStateTransitionMethodVersions { verify_state_transition_was_executed_with_proof: 0, }, + shielded: DriveVerifyShieldedMethodVersions { + verify_shielded_pool_state: 0, + verify_shielded_anchors: 0, + verify_shielded_encrypted_notes: 0, + verify_shielded_nullifiers: 0, + }, }; diff --git a/packages/rs-platform-version/src/version/mocks/v2_test.rs b/packages/rs-platform-version/src/version/mocks/v2_test.rs index 05610c204f6..748d2f20499 100644 --- a/packages/rs-platform-version/src/version/mocks/v2_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v2_test.rs @@ -19,9 +19,9 @@ use crate::version::drive_abci_versions::drive_abci_method_versions::v1::DRIVE_A use crate::version::drive_abci_versions::drive_abci_query_versions::{ DriveAbciQueryAddressFundsVersions, DriveAbciQueryDataContractVersions, DriveAbciQueryGroupVersions, DriveAbciQueryIdentityVersions, - DriveAbciQueryPrefundedSpecializedBalancesVersions, DriveAbciQuerySystemVersions, - DriveAbciQueryTokenVersions, DriveAbciQueryValidatorVersions, DriveAbciQueryVersions, - DriveAbciQueryVotingVersions, + DriveAbciQueryPrefundedSpecializedBalancesVersions, DriveAbciQueryShieldedVersions, + DriveAbciQuerySystemVersions, DriveAbciQueryTokenVersions, DriveAbciQueryValidatorVersions, + DriveAbciQueryVersions, DriveAbciQueryVotingVersions, }; use crate::version::drive_abci_versions::drive_abci_structure_versions::v1::DRIVE_ABCI_STRUCTURE_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_validation_versions::v1::DRIVE_ABCI_VALIDATION_VERSIONS_V1; @@ -391,6 +391,28 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { default_current_version: 0, }, }, + shielded_queries: DriveAbciQueryShieldedVersions { + encrypted_notes: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + anchors: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + pool_state: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + nullifiers: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + }, address_funds_queries: DriveAbciQueryAddressFundsVersions { addresses_infos: FeatureVersionBounds { min_version: 0, diff --git a/packages/rs-sdk/src/mock/requests.rs b/packages/rs-sdk/src/mock/requests.rs index 7236315e504..e9483182d41 100644 --- a/packages/rs-sdk/src/mock/requests.rs +++ b/packages/rs-sdk/src/mock/requests.rs @@ -37,8 +37,9 @@ use drive_proof_verifier::types::{ AddressInfo, Contenders, ContestedResources, CurrentQuorumsInfo, ElementFetchRequestItem, IdentityBalanceAndRevision, IndexMap, MasternodeProtocolVote, PlatformAddressTrunkState, PrefundedSpecializedBalance, ProposerBlockCounts, RecentAddressBalanceChanges, - RecentCompactedAddressBalanceChanges, RetrievedValues, TotalCreditsInPlatform, - VotePollsGroupedByTimestamp, Voters, + RecentCompactedAddressBalanceChanges, RetrievedValues, ShieldedAnchors, ShieldedEncryptedNote, + ShieldedEncryptedNotes, ShieldedNullifierStatus, ShieldedNullifierStatuses, ShieldedPoolState, + TotalCreditsInPlatform, VotePollsGroupedByTimestamp, Voters, }; use std::{collections::BTreeMap, hash::Hash}; @@ -507,6 +508,12 @@ impl_mock_response!(PlatformAddress); impl_mock_response!(AddressInfo); impl_mock_response!(RecentAddressBalanceChanges); impl_mock_response!(RecentCompactedAddressBalanceChanges); +impl_mock_response!(ShieldedPoolState); +impl_mock_response!(ShieldedAnchors); +impl_mock_response!(ShieldedEncryptedNotes); +impl_mock_response!(ShieldedEncryptedNote); +impl_mock_response!(ShieldedNullifierStatuses); +impl_mock_response!(ShieldedNullifierStatus); /// MockResponse for GroveTrunkQueryResult - panics when called because the Tree type /// doesn't support serialization. Address sync operations should not be mocked. diff --git a/packages/rs-sdk/src/platform/fetch.rs b/packages/rs-sdk/src/platform/fetch.rs index a80eaacb97b..5b2faee5cf7 100644 --- a/packages/rs-sdk/src/platform/fetch.rs +++ b/packages/rs-sdk/src/platform/fetch.rs @@ -369,6 +369,22 @@ impl Fetch for drive_proof_verifier::types::PlatformAddressTrunkState { type Request = platform_proto::GetAddressesTrunkStateRequest; } +impl Fetch for drive_proof_verifier::types::ShieldedPoolState { + type Request = platform_proto::GetShieldedPoolStateRequest; +} + +impl Fetch for drive_proof_verifier::types::ShieldedAnchors { + type Request = platform_proto::GetShieldedAnchorsRequest; +} + +impl Fetch for drive_proof_verifier::types::ShieldedEncryptedNotes { + type Request = platform_proto::GetShieldedEncryptedNotesRequest; +} + +impl Fetch for drive_proof_verifier::types::ShieldedNullifierStatuses { + type Request = platform_proto::GetShieldedNullifiersRequest; +} + /// Refetch the data contract from the network, update the context provider /// cache, and return a new [DocumentQuery] with the fresh contract. /// diff --git a/packages/rs-sdk/src/platform/query.rs b/packages/rs-sdk/src/platform/query.rs index eb9bdaa4427..763fe6b579b 100644 --- a/packages/rs-sdk/src/platform/query.rs +++ b/packages/rs-sdk/src/platform/query.rs @@ -28,8 +28,11 @@ use dapi_grpc::platform::v0::{ GetTotalCreditsInPlatformRequest, KeyRequestType, }; use dapi_grpc::platform::v0::{ - get_status_request, GetContestedResourceIdentityVotesRequest, - GetPrefundedSpecializedBalanceRequest, GetStatusRequest, GetTokenDirectPurchasePricesRequest, + get_shielded_anchors_request, get_shielded_encrypted_notes_request, + get_shielded_nullifiers_request, get_shielded_pool_state_request, get_status_request, + GetContestedResourceIdentityVotesRequest, GetPrefundedSpecializedBalanceRequest, + GetShieldedAnchorsRequest, GetShieldedEncryptedNotesRequest, GetShieldedNullifiersRequest, + GetShieldedPoolStateRequest, GetStatusRequest, GetTokenDirectPurchasePricesRequest, GetTokenPerpetualDistributionLastClaimRequest, GetVotePollsByEndDateRequest, SpecificKeys, }; use dpp::address_funds::PlatformAddress; @@ -43,7 +46,9 @@ use drive::query::vote_poll_vote_state_query::ContestedDocumentVotePollDriveQuer use drive::query::vote_polls_by_document_type_query::VotePollsByDocumentTypeQuery; use drive::query::{DriveDocumentQuery, VotePollsByEndDateDriveQuery}; use drive_proof_verifier::from_request::TryFromRequest; -use drive_proof_verifier::types::{KeysInPath, NoParamQuery}; +use drive_proof_verifier::types::{ + KeysInPath, NoParamQuery, ShieldedEncryptedNotesQuery, ShieldedNullifiersQuery, +}; use rs_dapi_client::transport::TransportRequest; use std::collections::BTreeSet; use std::fmt::Debug; @@ -982,3 +987,68 @@ impl Query }) } } + +// --- Shielded Pool Queries --- + +impl Query for NoParamQuery { + fn query(self, prove: bool) -> Result { + if !prove { + unimplemented!("queries without proofs are not supported yet"); + } + + Ok(GetShieldedPoolStateRequest { + version: Some(get_shielded_pool_state_request::Version::V0( + get_shielded_pool_state_request::GetShieldedPoolStateRequestV0 { prove }, + )), + }) + } +} + +impl Query for NoParamQuery { + fn query(self, prove: bool) -> Result { + if !prove { + unimplemented!("queries without proofs are not supported yet"); + } + + Ok(GetShieldedAnchorsRequest { + version: Some(get_shielded_anchors_request::Version::V0( + get_shielded_anchors_request::GetShieldedAnchorsRequestV0 { prove }, + )), + }) + } +} + +impl Query for ShieldedEncryptedNotesQuery { + fn query(self, prove: bool) -> Result { + if !prove { + unimplemented!("queries without proofs are not supported yet"); + } + + Ok(GetShieldedEncryptedNotesRequest { + version: Some(get_shielded_encrypted_notes_request::Version::V0( + get_shielded_encrypted_notes_request::GetShieldedEncryptedNotesRequestV0 { + start_cmx: self.start_cmx.unwrap_or_default(), + count: self.count, + prove, + }, + )), + }) + } +} + +impl Query for ShieldedNullifiersQuery { + fn query(self, prove: bool) -> Result { + if !prove { + unimplemented!("queries without proofs are not supported yet"); + } + + Ok(GetShieldedNullifiersRequest { + version: Some(get_shielded_nullifiers_request::Version::V0( + get_shielded_nullifiers_request::GetShieldedNullifiersRequestV0 { + nullifiers: self.0, + prove, + }, + )), + }) + } +} diff --git a/packages/rs-sdk/src/platform/types.rs b/packages/rs-sdk/src/platform/types.rs index 5eb63d5185f..b77f8fa3c5b 100644 --- a/packages/rs-sdk/src/platform/types.rs +++ b/packages/rs-sdk/src/platform/types.rs @@ -4,5 +4,6 @@ pub mod evonode; pub mod finalized_epoch; pub mod identity; pub mod proposed_blocks; +mod shielded; mod total_credits_in_platform; pub mod version_votes; diff --git a/packages/rs-sdk/src/platform/types/shielded.rs b/packages/rs-sdk/src/platform/types/shielded.rs new file mode 100644 index 00000000000..8aed8506b9a --- /dev/null +++ b/packages/rs-sdk/src/platform/types/shielded.rs @@ -0,0 +1,70 @@ +//! Shielded pool query types and helpers +use crate::platform::fetch_current_no_parameters::FetchCurrent; +use crate::{platform::Fetch, Error, Sdk}; +use async_trait::async_trait; +use dapi_grpc::platform::v0::{Proof, ResponseMetadata}; +use drive_proof_verifier::types::{NoParamQuery, ShieldedAnchors, ShieldedPoolState}; + +#[async_trait] +impl FetchCurrent for ShieldedPoolState { + async fn fetch_current(sdk: &Sdk) -> Result { + let (state, _) = Self::fetch_current_with_metadata(sdk).await?; + Ok(state) + } + + async fn fetch_current_with_metadata(sdk: &Sdk) -> Result<(Self, ResponseMetadata), Error> { + let (state, metadata) = Self::fetch_with_metadata(sdk, NoParamQuery {}, None).await?; + Ok(( + state.ok_or(Error::Generic( + "shielded pool state not found".to_string(), + ))?, + metadata, + )) + } + + async fn fetch_current_with_metadata_and_proof( + sdk: &Sdk, + ) -> Result<(Self, ResponseMetadata, Proof), Error> { + let (state, metadata, proof) = + Self::fetch_with_metadata_and_proof(sdk, NoParamQuery {}, None).await?; + Ok(( + state.ok_or(Error::Generic( + "shielded pool state not found".to_string(), + ))?, + metadata, + proof, + )) + } +} + +#[async_trait] +impl FetchCurrent for ShieldedAnchors { + async fn fetch_current(sdk: &Sdk) -> Result { + let (anchors, _) = Self::fetch_current_with_metadata(sdk).await?; + Ok(anchors) + } + + async fn fetch_current_with_metadata(sdk: &Sdk) -> Result<(Self, ResponseMetadata), Error> { + let (anchors, metadata) = Self::fetch_with_metadata(sdk, NoParamQuery {}, None).await?; + Ok(( + anchors.ok_or(Error::Generic( + "shielded anchors not found".to_string(), + ))?, + metadata, + )) + } + + async fn fetch_current_with_metadata_and_proof( + sdk: &Sdk, + ) -> Result<(Self, ResponseMetadata, Proof), Error> { + let (anchors, metadata, proof) = + Self::fetch_with_metadata_and_proof(sdk, NoParamQuery {}, None).await?; + Ok(( + anchors.ok_or(Error::Generic( + "shielded anchors not found".to_string(), + ))?, + metadata, + proof, + )) + } +} From d72958aadecfd308446ee866ed32a294f71e288a Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 11 Feb 2026 09:35:12 +0000 Subject: [PATCH 09/40] more work --- .../protos/platform/v0/platform.proto | 2 +- .../src/errors/consensus/basic/basic_error.rs | 12 +- .../consensus/basic/state_transition/mod.rs | 16 +- packages/rs-dpp/src/shielded/mod.rs | 10 +- .../state_transition_like.rs | 4 +- .../v0/mod.rs | 5 +- .../v0/state_transition_like.rs | 9 +- .../shielded/shield_transition/v0/mod.rs | 5 +- .../v0/state_transition_validation.rs | 3 +- .../shielded_transfer_transition/v0/mod.rs | 5 +- .../shielded_withdrawal_transition/v0/mod.rs | 5 +- .../shielded/unshield_transition/v0/mod.rs | 5 +- .../execution/types/execution_event/mod.rs | 3 +- .../processor/traits/basic_structure.rs | 8 +- .../state_transition/state_transitions/mod.rs | 4 +- .../state_transitions/shield/tests.rs | 35 +-- .../shield/transform_into_action/v0/mod.rs | 12 +- .../transform_into_action/v0/mod.rs | 10 +- .../shielded_transfer/tests.rs | 51 ++-- .../transform_into_action/v0/mod.rs | 31 ++- .../state_transitions/unshield/tests.rs | 51 ++-- .../unshield/transform_into_action/v0/mod.rs | 10 +- .../state_transition/transformer/mod.rs | 11 +- packages/rs-drive-abci/src/query/service.rs | 8 +- .../src/query/shielded/anchors/mod.rs | 17 +- .../src/query/shielded/anchors/v0/mod.rs | 4 +- .../query/shielded/encrypted_notes/v0/mod.rs | 30 +- .../src/query/shielded/nullifiers/mod.rs | 4 +- .../src/query/shielded/nullifiers/v0/mod.rs | 9 +- .../src/query/shielded/pool_state/mod.rs | 4 +- .../src/query/shielded/pool_state/v0/mod.rs | 4 +- packages/rs-drive-proof-verifier/src/proof.rs | 6 +- packages/rs-drive-proof-verifier/src/types.rs | 4 +- .../src/drive/initialization/v3/mod.rs | 4 +- .../src/drive/shielded/estimated_costs.rs | 25 +- .../action_convert_to_operations/mod.rs | 3 +- .../shielded/mod.rs | 258 +++++++----------- .../src/state_transition_action/mod.rs | 8 +- .../shielded/shield_from_asset_lock/mod.rs | 4 +- .../partially_use_asset_lock_action/mod.rs | 4 +- .../batch/drive_op_batch/finalize_task.rs | 15 +- .../src/util/batch/drive_op_batch/mod.rs | 19 +- .../src/util/batch/drive_op_batch/shielded.rs | 99 +++++++ .../mod.rs | 44 +++ .../v0/mod.rs | 64 +++++ .../rs-drive/src/util/grove_operations/mod.rs | 2 + packages/rs-drive/src/verify/mod.rs | 4 +- packages/rs-drive/src/verify/shielded/mod.rs | 4 +- .../verify_shielded_anchors/v0/mod.rs | 7 +- .../verify_shielded_encrypted_notes/mod.rs | 4 +- .../verify_shielded_encrypted_notes/v0/mod.rs | 24 +- .../drive_grove_method_versions/mod.rs | 1 + .../drive_grove_method_versions/v1.rs | 1 + packages/rs-sdk/src/platform/query.rs | 2 +- .../rs-sdk/src/platform/types/shielded.rs | 16 +- 55 files changed, 551 insertions(+), 458 deletions(-) create mode 100644 packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs create mode 100644 packages/rs-drive/src/util/grove_operations/batch_insert_auto_incremented_items_in_count_tree/mod.rs create mode 100644 packages/rs-drive/src/util/grove_operations/batch_insert_auto_incremented_items_in_count_tree/v0/mod.rs diff --git a/packages/dapi-grpc/protos/platform/v0/platform.proto b/packages/dapi-grpc/protos/platform/v0/platform.proto index 2611acb8b39..7f993724d51 100644 --- a/packages/dapi-grpc/protos/platform/v0/platform.proto +++ b/packages/dapi-grpc/protos/platform/v0/platform.proto @@ -2138,7 +2138,7 @@ message GetRecentCompactedAddressBalanceChangesResponse { message GetShieldedEncryptedNotesRequest { message GetShieldedEncryptedNotesRequestV0 { - bytes start_cmx = 1; + uint64 start_index = 1; uint32 count = 2; bool prove = 3; } diff --git a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs index 74732d4c69d..856f93a9c95 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs @@ -77,12 +77,12 @@ use crate::consensus::basic::state_transition::{ InputWitnessCountMismatchError, InputsNotLessThanOutputsError, InsufficientFundingAmountError, InvalidRemainderOutputCountError, InvalidStateTransitionTypeError, MissingStateTransitionTypeError, OutputAddressAlsoInputError, OutputBelowMinimumError, - OutputsNotGreaterThanInputsError, ShieldedEmptyProofError, - ShieldedInvalidValueBalanceError, ShieldedNoActionsError, ShieldedZeroAnchorError, - StateTransitionMaxSizeExceededError, StateTransitionNotActiveError, TransitionNoInputsError, - TransitionNoOutputsError, TransitionOverMaxInputsError, TransitionOverMaxOutputsError, - UnshieldAmountZeroError, UnshieldValueBalanceBelowAmountError, - WithdrawalBalanceMismatchError, WithdrawalBelowMinAmountError, + OutputsNotGreaterThanInputsError, ShieldedEmptyProofError, ShieldedInvalidValueBalanceError, + ShieldedNoActionsError, ShieldedZeroAnchorError, StateTransitionMaxSizeExceededError, + StateTransitionNotActiveError, TransitionNoInputsError, TransitionNoOutputsError, + TransitionOverMaxInputsError, TransitionOverMaxOutputsError, UnshieldAmountZeroError, + UnshieldValueBalanceBelowAmountError, WithdrawalBalanceMismatchError, + WithdrawalBelowMinAmountError, }; use crate::consensus::basic::{ IncompatibleProtocolVersionError, UnsupportedFeatureError, UnsupportedProtocolVersionError, diff --git a/packages/rs-dpp/src/errors/consensus/basic/state_transition/mod.rs b/packages/rs-dpp/src/errors/consensus/basic/state_transition/mod.rs index 210619362f6..06d06f3a777 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/state_transition/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/state_transition/mod.rs @@ -13,16 +13,16 @@ mod missing_state_transition_type_error; mod output_address_also_input_error; mod output_below_minimum_error; mod outputs_not_greater_than_inputs_error; +mod shielded_empty_proof_error; +mod shielded_invalid_value_balance_error; +mod shielded_no_actions_error; +mod shielded_zero_anchor_error; mod state_transition_max_size_exceeded_error; mod state_transition_not_active_error; mod transition_no_inputs_error; mod transition_no_outputs_error; mod transition_over_max_inputs_error; mod transition_over_max_outputs_error; -mod shielded_empty_proof_error; -mod shielded_invalid_value_balance_error; -mod shielded_no_actions_error; -mod shielded_zero_anchor_error; mod unshield_amount_zero_error; mod unshield_value_balance_below_amount_error; mod withdrawal_balance_mismatch_error; @@ -43,16 +43,16 @@ pub use missing_state_transition_type_error::*; pub use output_address_also_input_error::*; pub use output_below_minimum_error::*; pub use outputs_not_greater_than_inputs_error::*; +pub use shielded_empty_proof_error::*; +pub use shielded_invalid_value_balance_error::*; +pub use shielded_no_actions_error::*; +pub use shielded_zero_anchor_error::*; pub use state_transition_max_size_exceeded_error::*; pub use state_transition_not_active_error::*; pub use transition_no_inputs_error::*; pub use transition_no_outputs_error::*; pub use transition_over_max_inputs_error::*; pub use transition_over_max_outputs_error::*; -pub use shielded_empty_proof_error::*; -pub use shielded_invalid_value_balance_error::*; -pub use shielded_no_actions_error::*; -pub use shielded_zero_anchor_error::*; pub use unshield_amount_zero_error::*; pub use unshield_value_balance_below_amount_error::*; pub use withdrawal_balance_mismatch_error::*; diff --git a/packages/rs-dpp/src/shielded/mod.rs b/packages/rs-dpp/src/shielded/mod.rs index d64dd1bea0a..79802ea709e 100644 --- a/packages/rs-dpp/src/shielded/mod.rs +++ b/packages/rs-dpp/src/shielded/mod.rs @@ -13,8 +13,9 @@ pub(crate) mod serde_bytes_64 { pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<[u8; 64], D::Error> { let vec = >::deserialize(deserializer)?; - vec.try_into() - .map_err(|v: Vec| serde::de::Error::custom(format!("expected 64 bytes, got {}", v.len()))) + vec.try_into().map_err(|v: Vec| { + serde::de::Error::custom(format!("expected 64 bytes, got {}", v.len())) + }) } } @@ -88,6 +89,9 @@ pub struct SerializedAction { /// value_balance, anchor, and any bound transparent fields). Verified against /// `rk` during batch validation. This prevents replay attacks — a valid /// signature from one transition cannot be reused in another. - #[cfg_attr(feature = "state-transition-serde-conversion", serde(with = "serde_bytes_64"))] + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(with = "serde_bytes_64") + )] pub spend_auth_sig: [u8; 64], } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/state_transition_like.rs index 8b1c7f86307..51844628ca7 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/state_transition_like.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/state_transition_like.rs @@ -61,9 +61,7 @@ impl StateTransitionSingleSigned for ShieldFromAssetLockTransition { /// set a new signature fn set_signature(&mut self, signature: BinaryData) { match self { - ShieldFromAssetLockTransition::V0(transition) => { - transition.set_signature(signature) - } + ShieldFromAssetLockTransition::V0(transition) => transition.set_signature(signature), } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs index a7d8b69eebc..5aab3cac355 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs @@ -44,7 +44,10 @@ pub struct ShieldFromAssetLockTransitionV0 { /// Halo2 proof bytes pub proof: Vec, /// RedPallas binding signature - #[cfg_attr(feature = "state-transition-serde-conversion", serde(with = "crate::shielded::serde_bytes_64"))] + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(with = "crate::shielded::serde_bytes_64") + )] pub binding_signature: [u8; 64], /// Fee multiplier pub user_fee_increase: UserFeeIncrease, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_like.rs index be3b17d6f5c..186631184dd 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_like.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_like.rs @@ -3,9 +3,7 @@ use platform_value::BinaryData; use crate::prelude::UserFeeIncrease; use crate::state_transition::shield_from_asset_lock_transition::v0::ShieldFromAssetLockTransitionV0; use crate::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; -use crate::state_transition::{ - StateTransition, StateTransitionSingleSigned, -}; +use crate::state_transition::{StateTransition, StateTransitionSingleSigned}; use crate::version::FeatureVersion; use crate::{ prelude::Identifier, @@ -36,10 +34,7 @@ impl StateTransitionLike for ShieldFromAssetLockTransitionV0 { /// Returns unique identifiers based on the cmx values from actions fn unique_identifiers(&self) -> Vec { - self.actions - .iter() - .map(|a| hex::encode(a.cmx)) - .collect() + self.actions.iter().map(|a| hex::encode(a.cmx)).collect() } fn user_fee_increase(&self) -> UserFeeIncrease { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs index a633b89343d..78237843aa4 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs @@ -47,7 +47,10 @@ pub struct ShieldTransitionV0 { /// Halo2 proof bytes pub proof: Vec, /// RedPallas binding signature - #[cfg_attr(feature = "state-transition-serde-conversion", serde(with = "crate::shielded::serde_bytes_64"))] + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(with = "crate::shielded::serde_bytes_64") + )] pub binding_signature: [u8; 64], /// Fee payment strategy pub fee_strategy: AddressFundsFeeStrategy, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs index babc81b46a7..418750cb3c6 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs @@ -63,7 +63,8 @@ impl StateTransitionStructureValidation for ShieldTransitionV0 { return SimpleConsensusValidationResult::new_with_error( BasicError::ShieldedInvalidValueBalanceError( ShieldedInvalidValueBalanceError::new( - "shield value_balance must be negative (credits flow into pool)".to_string(), + "shield value_balance must be negative (credits flow into pool)" + .to_string(), ), ) .into(), diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs index a78bcc4fbbf..d8deefa0bea 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs @@ -39,7 +39,10 @@ pub struct ShieldedTransferTransitionV0 { /// Halo2 proof bytes pub proof: Vec, /// RedPallas binding signature - #[cfg_attr(feature = "state-transition-serde-conversion", serde(with = "crate::shielded::serde_bytes_64"))] + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(with = "crate::shielded::serde_bytes_64") + )] pub binding_signature: [u8; 64], /// Fee multiplier pub user_fee_increase: UserFeeIncrease, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs index 344bbd414ad..31502f0785a 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs @@ -43,7 +43,10 @@ pub struct ShieldedWithdrawalTransitionV0 { /// Halo2 proof bytes pub proof: Vec, /// RedPallas binding signature - #[cfg_attr(feature = "state-transition-serde-conversion", serde(with = "crate::shielded::serde_bytes_64"))] + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(with = "crate::shielded::serde_bytes_64") + )] pub binding_signature: [u8; 64], /// Core transaction fee rate pub core_fee_per_byte: u32, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs index aa27c3c840c..0dad877d726 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs @@ -44,7 +44,10 @@ pub struct UnshieldTransitionV0 { /// Halo2 proof bytes pub proof: Vec, /// RedPallas binding signature - #[cfg_attr(feature = "state-transition-serde-conversion", serde(with = "crate::shielded::serde_bytes_64"))] + #[cfg_attr( + feature = "state-transition-serde-conversion", + serde(with = "crate::shielded::serde_bytes_64") + )] pub binding_signature: [u8; 64], /// Fee multiplier pub user_fee_increase: UserFeeIncrease, diff --git a/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs b/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs index 0f5a4d3c574..95f03fe4906 100644 --- a/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs +++ b/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs @@ -447,8 +447,7 @@ impl ExecutionEvent<'_> { } StateTransitionAction::ShieldAction(shield_action) => { let user_fee_increase = shield_action.user_fee_increase(); - let input_current_balances = - shield_action.inputs_with_remaining_balance().clone(); + let input_current_balances = shield_action.inputs_with_remaining_balance().clone(); let added_to_balance_outputs = BTreeMap::new(); let fee_strategy = shield_action.fee_strategy().clone(); let operations = diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/basic_structure.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/basic_structure.rs index a32ae2c4a14..3738e64774c 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/basic_structure.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/basic_structure.rs @@ -240,12 +240,8 @@ impl StateTransitionBasicStructureValidationV0 for StateTransition { StateTransition::Shield(st) => Ok(st.validate_structure(platform_version)), StateTransition::ShieldedTransfer(st) => Ok(st.validate_structure(platform_version)), StateTransition::Unshield(st) => Ok(st.validate_structure(platform_version)), - StateTransition::ShieldFromAssetLock(st) => { - Ok(st.validate_structure(platform_version)) - } - StateTransition::ShieldedWithdrawal(st) => { - Ok(st.validate_structure(platform_version)) - } + StateTransition::ShieldFromAssetLock(st) => Ok(st.validate_structure(platform_version)), + StateTransition::ShieldedWithdrawal(st) => Ok(st.validate_structure(platform_version)), } } fn has_basic_structure_validation(&self, platform_version: &PlatformVersion) -> bool { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs index 34f086a1eed..5ec952feba8 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/mod.rs @@ -43,14 +43,14 @@ mod identity_top_up_from_addresses; /// Module for shield transition validation pub mod shield; +/// Module for shield from asset lock transition validation +pub mod shield_from_asset_lock; /// Common validation logic shared by shielded transitions (proof verification) pub mod shielded_common; /// Module for shielded transfer transition validation pub mod shielded_transfer; /// Module for shielded withdrawal transition validation pub mod shielded_withdrawal; -/// Module for shield from asset lock transition validation -pub mod shield_from_asset_lock; /// Module for unshield transition validation pub mod unshield; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs index 5e037d9e269..6a5149b70f3 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs @@ -145,7 +145,7 @@ mod tests { 0x03, // spends_enabled | outputs_enabled -1000, vec![0u8; 100], // dummy proof bytes - [0u8; 64], // dummy binding signature + [0u8; 64], // dummy binding signature AddressFundsFeeStrategy::from(vec![AddressFundsFeeStrategyStep::DeductFromInput(0)]), ) } @@ -234,8 +234,7 @@ mod tests { let value_balance = *bundle.value_balance(); let anchor = bundle.anchor().to_bytes(); let proof = bundle.authorization().proof().as_ref().to_vec(); - let binding_sig = - <[u8; 64]>::from(bundle.authorization().binding_signature()); + let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); (actions, flags, value_balance, anchor, proof, binding_sig) } @@ -842,12 +841,7 @@ mod tests { // --- Set up input address with enough balance --- let mut signer = TestAddressSigner::new(); let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance( - &mut platform, - input_address, - 0, - dash_to_credits!(1.0), - ); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); // --- Build valid Orchard bundle (shield = outputs only) --- let mut rng = OsRng; @@ -876,16 +870,11 @@ mod tests { ) .unwrap(); - let (unauthorized, _) = - builder.build::(&mut rng).unwrap().unwrap(); + let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); let sighash = compute_platform_sighash(&bundle_commitment, &[]); - let proven = unauthorized - .create_proof(pk, &mut rng) - .unwrap(); - let bundle = proven - .apply_signatures(rng, sighash, &[]) - .unwrap(); + let proven = unauthorized.create_proof(pk, &mut rng).unwrap(); + let bundle = proven.apply_signatures(rng, sighash, &[]).unwrap(); // --- Extract serialized fields from the authorized bundle --- let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = @@ -1042,12 +1031,7 @@ mod tests { let mut signer = TestAddressSigner::new(); let input_address = signer.add_p2pkh([1u8; 32]); - setup_address_with_balance( - &mut platform, - input_address, - 0, - dash_to_credits!(1.0), - ); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); let mut rng = OsRng; let pk = get_proving_key(); @@ -1090,7 +1074,10 @@ mod tests { let mut inputs = BTreeMap::new(); inputs.insert( input_address, - (1 as AddressNonce, honest_shield_amount + dash_to_credits!(0.01)), + ( + 1 as AddressNonce, + honest_shield_amount + dash_to_credits!(0.01), + ), ); let mut st = StateTransition::Shield(ShieldTransition::V0(ShieldTransitionV0 { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs index 12a602c5368..0439508554b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs @@ -7,9 +7,7 @@ use dpp::fee::Credits; use dpp::prelude::{AddressNonce, ConsensusValidationResult}; use dpp::state_transition::shield_transition::ShieldTransition; use dpp::version::PlatformVersion; -use drive::drive::shielded::paths::{ - shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY, -}; +use drive::drive::shielded::paths::{shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY}; use drive::drive::Drive; use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::shield::ShieldTransitionAction; @@ -65,11 +63,9 @@ impl ShieldStateTransitionTransformIntoActionValidationV0 for ShieldTransition { Some(positive) => positive as u64, None => { return Ok(ConsensusValidationResult::new_with_error( - StateError::InvalidShieldedProofError( - InvalidShieldedProofError::new( - "shield value_balance overflow (i64::MIN)".to_string(), - ), - ) + StateError::InvalidShieldedProofError(InvalidShieldedProofError::new( + "shield value_balance overflow (i64::MIN)".to_string(), + )) .into(), )); } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs index 295cc122145..2e2c08e62f7 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs @@ -300,15 +300,16 @@ impl ShieldFromAssetLockStateTransitionTransformIntoActionValidationV0 asset_lock_value_to_be_consumed.used_tags_ref().clone(); previous_transaction_hashes.push(signable_bytes_hash); - let remaining_after_penalty = remaining_credit_value.saturating_sub(desired_used_credits); + let remaining_after_penalty = + remaining_credit_value.saturating_sub(desired_used_credits); let used_credits = std::cmp::min(remaining_credit_value, desired_used_credits); let user_fee_increase = match self { ShieldFromAssetLockTransition::V0(v0) => v0.user_fee_increase, }; - let partially_use_action = PartiallyUseAssetLockAction::from( - PartiallyUseAssetLockActionV0 { + let partially_use_action = + PartiallyUseAssetLockAction::from(PartiallyUseAssetLockActionV0 { asset_lock_outpoint: Bytes36::new(asset_lock_outpoint.into()), initial_credit_value: asset_lock_value_to_be_consumed.initial_credit_value(), previous_transaction_hashes, @@ -318,8 +319,7 @@ impl ShieldFromAssetLockStateTransitionTransformIntoActionValidationV0 user_fee_increase, inputs_with_remaining_balance: None, fee_strategy: None, - }, - ); + }); return Ok(ConsensusValidationResult::new_with_data_and_errors( StateTransitionAction::PartiallyUseAssetLockAction(partially_use_action), diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs index f0d3eb8ae9d..6f470160ff8 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs @@ -71,7 +71,7 @@ mod tests { 0, // zero fee [42u8; 32], // non-zero anchor vec![0u8; 100], // dummy proof bytes - [0u8; 64], // dummy binding signature + [0u8; 64], // dummy binding signature 0, ) } @@ -392,10 +392,9 @@ mod tests { mod proof_verification { use super::*; use grovedb_commitment_tree::{ - Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - CommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, - NoteValue, Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, - SpendingKey, new_memory_store, + new_memory_store, Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + CommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, NoteValue, + Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, }; use orchard::note::RandomSeed; use rand::rngs::OsRng; @@ -432,8 +431,7 @@ mod tests { let value_balance = *bundle.value_balance(); let anchor = bundle.anchor().to_bytes(); let proof = bundle.authorization().proof().as_ref().to_vec(); - let binding_sig = - <[u8; 64]>::from(bundle.authorization().binding_signature()); + let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); (actions, flags, value_balance, anchor, proof, binding_sig) } @@ -483,8 +481,8 @@ mod tests { }; let rho = Rho::from_bytes(&rho_bytes).unwrap(); let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); - let note = Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed) - .unwrap(); + let note = + Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); // --- Build commitment tree and get anchor + merkle path --- let cmx = ExtractedNoteCommitment::from(note.commitment()); @@ -492,16 +490,11 @@ mod tests { tree.append(cmx, Retention::Marked).unwrap(); tree.checkpoint(0u32).unwrap(); let anchor = tree.anchor().unwrap(); - let merkle_path = tree - .orchard_witness(Position::from(0u64)) - .unwrap() - .unwrap(); + let merkle_path = tree.orchard_witness(Position::from(0u64)).unwrap().unwrap(); // --- Build bundle: spend 10_000 → output 10_000 (value_balance = 0) --- let mut builder = Builder::new(BundleType::DEFAULT, anchor); - builder - .add_spend(fvk.clone(), note, merkle_path) - .unwrap(); + builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); builder .add_output(None, recipient, NoteValue::from_raw(10_000), [0u8; 512]) .unwrap(); @@ -588,10 +581,9 @@ mod tests { mod security_audit { use super::*; use grovedb_commitment_tree::{ - Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - CommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, - NoteValue, Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, - SpendingKey, new_memory_store, + new_memory_store, Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + CommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, NoteValue, + Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, }; use orchard::note::RandomSeed; use rand::rngs::OsRng; @@ -628,14 +620,14 @@ mod tests { let value_balance = *bundle.value_balance(); let anchor = bundle.anchor().to_bytes(); let proof = bundle.authorization().proof().as_ref().to_vec(); - let binding_sig = - <[u8; 64]>::from(bundle.authorization().binding_signature()); + let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); (actions, flags, value_balance, anchor, proof, binding_sig) } /// Build a valid Orchard bundle for shielded transfer tests. /// Returns (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig). - fn build_valid_shielded_transfer_bundle() -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { + fn build_valid_shielded_transfer_bundle( + ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { let mut rng = OsRng; let pk = get_proving_key(); @@ -651,23 +643,18 @@ mod tests { }; let rho = Rho::from_bytes(&rho_bytes).unwrap(); let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); - let note = Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed) - .unwrap(); + let note = + Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); let cmx = ExtractedNoteCommitment::from(note.commitment()); let mut tree = CommitmentTree::new(new_memory_store(), 100); tree.append(cmx, Retention::Marked).unwrap(); tree.checkpoint(0u32).unwrap(); let anchor = tree.anchor().unwrap(); - let merkle_path = tree - .orchard_witness(Position::from(0u64)) - .unwrap() - .unwrap(); + let merkle_path = tree.orchard_witness(Position::from(0u64)).unwrap().unwrap(); let mut builder = Builder::new(BundleType::DEFAULT, anchor); - builder - .add_spend(fvk.clone(), note, merkle_path) - .unwrap(); + builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); builder .add_output(None, recipient, NoteValue::from_raw(10_000), [0u8; 512]) .unwrap(); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs index c35e95bd47b..f757662685d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs @@ -141,18 +141,25 @@ impl ShieldedWithdrawalStateTransitionTransformIntoActionValidationV0 // destination (output_script) and amount, preventing an attacker from // substituting a different output_script or amount while reusing a valid // Orchard bundle. - let (st_actions, st_flags, st_value_balance, st_proof, st_binding_sig, output_script, amount) = - match self { - ShieldedWithdrawalTransition::V0(v0) => ( - &v0.actions, - v0.flags, - v0.value_balance, - v0.proof.as_slice(), - &v0.binding_signature, - &v0.output_script, - v0.amount, - ), - }; + let ( + st_actions, + st_flags, + st_value_balance, + st_proof, + st_binding_sig, + output_script, + amount, + ) = match self { + ShieldedWithdrawalTransition::V0(v0) => ( + &v0.actions, + v0.flags, + v0.value_balance, + v0.proof.as_slice(), + &v0.binding_signature, + &v0.output_script, + v0.amount, + ), + }; // Serialize transparent fields to bind them to the Orchard sighash. // output_script.as_bytes() || amount.to_le_bytes() diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs index 42fc396945e..642f0c447ec 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs @@ -494,10 +494,9 @@ mod tests { mod proof_verification { use super::*; use grovedb_commitment_tree::{ - Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - CommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, - NoteValue, Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, - SpendingKey, new_memory_store, + new_memory_store, Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + CommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, NoteValue, + Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, }; use orchard::note::RandomSeed; use rand::rngs::OsRng; @@ -534,8 +533,7 @@ mod tests { let value_balance = *bundle.value_balance(); let anchor = bundle.anchor().to_bytes(); let proof = bundle.authorization().proof().as_ref().to_vec(); - let binding_sig = - <[u8; 64]>::from(bundle.authorization().binding_signature()); + let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); (actions, flags, value_balance, anchor, proof, binding_sig) } @@ -585,8 +583,8 @@ mod tests { }; let rho = Rho::from_bytes(&rho_bytes).unwrap(); let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); - let note = Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed) - .unwrap(); + let note = + Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); // --- Build commitment tree and get anchor + merkle path --- let cmx = ExtractedNoteCommitment::from(note.commitment()); @@ -594,16 +592,11 @@ mod tests { tree.append(cmx, Retention::Marked).unwrap(); tree.checkpoint(0u32).unwrap(); let anchor = tree.anchor().unwrap(); - let merkle_path = tree - .orchard_witness(Position::from(0u64)) - .unwrap() - .unwrap(); + let merkle_path = tree.orchard_witness(Position::from(0u64)).unwrap().unwrap(); // --- Build bundle: spend 10,000 → output 5,000 (value_balance = 5,000) --- let mut builder = Builder::new(BundleType::DEFAULT, anchor); - builder - .add_spend(fvk.clone(), note, merkle_path) - .unwrap(); + builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); builder .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 512]) .unwrap(); @@ -701,10 +694,9 @@ mod tests { mod security_audit { use super::*; use grovedb_commitment_tree::{ - Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - CommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, - NoteValue, Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, - SpendingKey, new_memory_store, + new_memory_store, Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + CommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, NoteValue, + Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, }; use orchard::note::RandomSeed; use rand::rngs::OsRng; @@ -741,8 +733,7 @@ mod tests { let value_balance = *bundle.value_balance(); let anchor = bundle.anchor().to_bytes(); let proof = bundle.authorization().proof().as_ref().to_vec(); - let binding_sig = - <[u8; 64]>::from(bundle.authorization().binding_signature()); + let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); (actions, flags, value_balance, anchor, proof, binding_sig) } @@ -750,7 +741,10 @@ mod tests { /// The `output_address` and `amount` are bound to the sighash so that /// the resulting bundle can only be used with those specific transparent fields. /// Returns (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig). - fn build_valid_unshield_bundle(output_address: &PlatformAddress, amount: u64) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { + fn build_valid_unshield_bundle( + output_address: &PlatformAddress, + amount: u64, + ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { let mut rng = OsRng; let pk = get_proving_key(); @@ -766,24 +760,19 @@ mod tests { }; let rho = Rho::from_bytes(&rho_bytes).unwrap(); let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); - let note = Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed) - .unwrap(); + let note = + Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); let cmx = ExtractedNoteCommitment::from(note.commitment()); let mut tree = CommitmentTree::new(new_memory_store(), 100); tree.append(cmx, Retention::Marked).unwrap(); tree.checkpoint(0u32).unwrap(); let anchor = tree.anchor().unwrap(); - let merkle_path = tree - .orchard_witness(Position::from(0u64)) - .unwrap() - .unwrap(); + let merkle_path = tree.orchard_witness(Position::from(0u64)).unwrap().unwrap(); // Spend 10,000 → output 5,000 → value_balance = 5,000 let mut builder = Builder::new(BundleType::DEFAULT, anchor); - builder - .add_spend(fvk.clone(), note, merkle_path) - .unwrap(); + builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); builder .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 512]) .unwrap(); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs index 261ffd01538..f86275c7dc2 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs @@ -108,7 +108,15 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti } // Verify the ZK proof, binding transparent fields to the sighash - let (st_actions, st_flags, st_value_balance, st_proof, st_binding_sig, output_address, amount) = match self { + let ( + st_actions, + st_flags, + st_value_balance, + st_proof, + st_binding_sig, + output_address, + amount, + ) = match self { UnshieldTransition::V0(v0) => ( &v0.actions, v0.flags, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs index 1203122375d..ba5ca5e135c 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs @@ -8,8 +8,8 @@ use crate::execution::validation::state_transition::identity_create::StateTransi use crate::execution::validation::state_transition::identity_create_from_addresses::StateTransitionActionTransformerForIdentityCreateFromAddressesTransitionV0; use crate::execution::validation::state_transition::identity_top_up::StateTransitionIdentityTopUpTransitionActionTransformer; use crate::execution::validation::state_transition::shield::StateTransitionShieldTransitionActionTransformer; -use crate::execution::validation::state_transition::shielded_transfer::StateTransitionShieldedTransferTransitionActionTransformer; use crate::execution::validation::state_transition::shield_from_asset_lock::StateTransitionShieldFromAssetLockTransitionActionTransformer; +use crate::execution::validation::state_transition::shielded_transfer::StateTransitionShieldedTransferTransitionActionTransformer; use crate::execution::validation::state_transition::shielded_withdrawal::StateTransitionShieldedWithdrawalTransitionActionTransformer; use crate::execution::validation::state_transition::unshield::StateTransitionUnshieldTransitionActionTransformer; use crate::execution::validation::state_transition::ValidationMode; @@ -263,13 +263,8 @@ impl StateTransitionActionTransformer for StateTransition { tx, ) } - StateTransition::ShieldedWithdrawal(st) => { - st.transform_into_action_for_shielded_withdrawal_transition( - platform, - block_info, - tx, - ) - } + StateTransition::ShieldedWithdrawal(st) => st + .transform_into_action_for_shielded_withdrawal_transition(platform, block_info, tx), } } } diff --git a/packages/rs-drive-abci/src/query/service.rs b/packages/rs-drive-abci/src/query/service.rs index 98b7a19b5b3..d36444bd9f1 100644 --- a/packages/rs-drive-abci/src/query/service.rs +++ b/packages/rs-drive-abci/src/query/service.rs @@ -44,16 +44,16 @@ use dapi_grpc::platform::v0::{ GetProtocolVersionUpgradeStateResponse, GetProtocolVersionUpgradeVoteStatusRequest, GetProtocolVersionUpgradeVoteStatusResponse, GetRecentAddressBalanceChangesRequest, GetRecentAddressBalanceChangesResponse, GetRecentCompactedAddressBalanceChangesRequest, - GetRecentCompactedAddressBalanceChangesResponse, GetStatusRequest, GetStatusResponse, + GetRecentCompactedAddressBalanceChangesResponse, GetShieldedAnchorsRequest, + GetShieldedAnchorsResponse, GetShieldedEncryptedNotesRequest, + GetShieldedEncryptedNotesResponse, GetShieldedNullifiersRequest, GetShieldedNullifiersResponse, + GetShieldedPoolStateRequest, GetShieldedPoolStateResponse, GetStatusRequest, GetStatusResponse, GetTokenContractInfoRequest, GetTokenContractInfoResponse, GetTokenDirectPurchasePricesRequest, GetTokenDirectPurchasePricesResponse, GetTokenPerpetualDistributionLastClaimRequest, GetTokenPerpetualDistributionLastClaimResponse, GetTokenPreProgrammedDistributionsRequest, GetTokenPreProgrammedDistributionsResponse, GetTokenStatusesRequest, GetTokenStatusesResponse, GetTokenTotalSupplyRequest, GetTokenTotalSupplyResponse, GetTotalCreditsInPlatformRequest, GetTotalCreditsInPlatformResponse, GetVotePollsByEndDateRequest, GetVotePollsByEndDateResponse, - GetShieldedAnchorsRequest, GetShieldedAnchorsResponse, GetShieldedEncryptedNotesRequest, - GetShieldedEncryptedNotesResponse, GetShieldedNullifiersRequest, GetShieldedNullifiersResponse, - GetShieldedPoolStateRequest, GetShieldedPoolStateResponse, WaitForStateTransitionResultRequest, WaitForStateTransitionResultResponse, }; use dapi_grpc::tonic::{Code, Request, Response, Status}; diff --git a/packages/rs-drive-abci/src/query/shielded/anchors/mod.rs b/packages/rs-drive-abci/src/query/shielded/anchors/mod.rs index c8b6d28b31c..f899099ceb7 100644 --- a/packages/rs-drive-abci/src/query/shielded/anchors/mod.rs +++ b/packages/rs-drive-abci/src/query/shielded/anchors/mod.rs @@ -20,17 +20,11 @@ impl Platform { ) -> Result, Error> { let Some(version) = version else { return Ok(QueryValidationResult::new_with_error( - QueryError::DecodingError( - "could not decode shielded anchors query".to_string(), - ), + QueryError::DecodingError("could not decode shielded anchors query".to_string()), )); }; - let feature_version_bounds = &platform_version - .drive_abci - .query - .shielded_queries - .anchors; + let feature_version_bounds = &platform_version.drive_abci.query.shielded_queries.anchors; let feature_version = match &version { RequestVersion::V0(_) => 0, @@ -48,11 +42,8 @@ impl Platform { } match version { RequestVersion::V0(request_v0) => { - let result = self.query_shielded_anchors_v0( - request_v0, - platform_state, - platform_version, - )?; + let result = + self.query_shielded_anchors_v0(request_v0, platform_state, platform_version)?; Ok(result.map(|response_v0| GetShieldedAnchorsResponse { version: Some(ResponseVersion::V0(response_v0)), diff --git a/packages/rs-drive-abci/src/query/shielded/anchors/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/anchors/v0/mod.rs index ee64514a842..de8f9b6bb18 100644 --- a/packages/rs-drive-abci/src/query/shielded/anchors/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/shielded/anchors/v0/mod.rs @@ -66,9 +66,7 @@ impl Platform { result: Some(get_shielded_anchors_response_v0::Result::Anchors(Anchors { anchors, })), - metadata: Some( - self.response_metadata_v0(platform_state, CheckpointUsed::Current), - ), + metadata: Some(self.response_metadata_v0(platform_state, CheckpointUsed::Current)), } }; diff --git a/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs index e85dfe054f3..63c036d3f48 100644 --- a/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs @@ -24,7 +24,7 @@ impl Platform { pub(super) fn query_shielded_encrypted_notes_v0( &self, GetShieldedEncryptedNotesRequestV0 { - start_cmx, + start_index, count, prove, }: GetShieldedEncryptedNotesRequestV0, @@ -47,11 +47,11 @@ impl Platform { ))); } - let query = if start_cmx.is_empty() { + let query = if start_index == 0 { Query::new_range_full() } else { let mut q = Query::new(); - q.insert_range_after(start_cmx..); + q.insert_range_from(start_index.to_be_bytes().to_vec()..); q }; @@ -93,14 +93,18 @@ impl Platform { let entries: Vec = results .to_key_elements() .into_iter() - .filter_map(|(key, element)| { - element - .into_item_bytes() - .ok() - .map(|encrypted_note| EncryptedNote { - cmx: key, - encrypted_note, - }) + .filter_map(|(_key, element)| { + element.into_item_bytes().ok().and_then(|value| { + // Value format: cmx (32 bytes) || encrypted_note (remaining bytes) + if value.len() > 32 { + Some(EncryptedNote { + cmx: value[..32].to_vec(), + encrypted_note: value[32..].to_vec(), + }) + } else { + None + } + }) }) .collect(); @@ -110,9 +114,7 @@ impl Platform { EncryptedNotes { entries }, ), ), - metadata: Some( - self.response_metadata_v0(platform_state, CheckpointUsed::Current), - ), + metadata: Some(self.response_metadata_v0(platform_state, CheckpointUsed::Current)), } }; diff --git a/packages/rs-drive-abci/src/query/shielded/nullifiers/mod.rs b/packages/rs-drive-abci/src/query/shielded/nullifiers/mod.rs index cab55f9eeb2..096a9820122 100644 --- a/packages/rs-drive-abci/src/query/shielded/nullifiers/mod.rs +++ b/packages/rs-drive-abci/src/query/shielded/nullifiers/mod.rs @@ -20,9 +20,7 @@ impl Platform { ) -> Result, Error> { let Some(version) = version else { return Ok(QueryValidationResult::new_with_error( - QueryError::DecodingError( - "could not decode shielded nullifiers query".to_string(), - ), + QueryError::DecodingError("could not decode shielded nullifiers query".to_string()), )); }; diff --git a/packages/rs-drive-abci/src/query/shielded/nullifiers/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/nullifiers/v0/mod.rs index 38fbb45b49d..0795200b328 100644 --- a/packages/rs-drive-abci/src/query/shielded/nullifiers/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/shielded/nullifiers/v0/mod.rs @@ -24,10 +24,7 @@ use drive::util::grove_operations::{DirectQueryType, GroveDBToUse}; impl Platform { pub(super) fn query_shielded_nullifiers_v0( &self, - GetShieldedNullifiersRequestV0 { - nullifiers, - prove, - }: GetShieldedNullifiersRequestV0, + GetShieldedNullifiersRequestV0 { nullifiers, prove }: GetShieldedNullifiersRequestV0, platform_state: &PlatformState, platform_version: &PlatformVersion, ) -> Result, Error> { @@ -104,9 +101,7 @@ impl Platform { NullifierStatuses { entries }, ), ), - metadata: Some( - self.response_metadata_v0(platform_state, CheckpointUsed::Current), - ), + metadata: Some(self.response_metadata_v0(platform_state, CheckpointUsed::Current)), } }; diff --git a/packages/rs-drive-abci/src/query/shielded/pool_state/mod.rs b/packages/rs-drive-abci/src/query/shielded/pool_state/mod.rs index 496c6e8162b..3ea9d875763 100644 --- a/packages/rs-drive-abci/src/query/shielded/pool_state/mod.rs +++ b/packages/rs-drive-abci/src/query/shielded/pool_state/mod.rs @@ -20,9 +20,7 @@ impl Platform { ) -> Result, Error> { let Some(version) = version else { return Ok(QueryValidationResult::new_with_error( - QueryError::DecodingError( - "could not decode shielded pool state query".to_string(), - ), + QueryError::DecodingError("could not decode shielded pool state query".to_string()), )); }; diff --git a/packages/rs-drive-abci/src/query/shielded/pool_state/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/pool_state/v0/mod.rs index cfdacc8af56..c71ef44fd2c 100644 --- a/packages/rs-drive-abci/src/query/shielded/pool_state/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/shielded/pool_state/v0/mod.rs @@ -66,9 +66,7 @@ impl Platform { result: Some(get_shielded_pool_state_response_v0::Result::TotalBalance( total_balance, )), - metadata: Some( - self.response_metadata_v0(platform_state, CheckpointUsed::Current), - ), + metadata: Some(self.response_metadata_v0(platform_state, CheckpointUsed::Current)), } }; diff --git a/packages/rs-drive-proof-verifier/src/proof.rs b/packages/rs-drive-proof-verifier/src/proof.rs index ddfbf089a3f..e930c2e23d2 100644 --- a/packages/rs-drive-proof-verifier/src/proof.rs +++ b/packages/rs-drive-proof-verifier/src/proof.rs @@ -2368,15 +2368,15 @@ impl FromProof for ShieldedEncrypted let proof = response.proof().or(Err(Error::NoProofInResult))?; let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?; - let (start_cmx, count) = match request.version.ok_or(Error::EmptyVersion)? { - get_shielded_encrypted_notes_request::Version::V0(v0) => (v0.start_cmx, v0.count), + let (start_index, count) = match request.version.ok_or(Error::EmptyVersion)? { + get_shielded_encrypted_notes_request::Version::V0(v0) => (v0.start_index, v0.count), }; let max_elements = platform_version.drive_abci.query.max_returned_elements as u32; let (root_hash, notes) = Drive::verify_shielded_encrypted_notes( &proof.grovedb_proof, - &start_cmx, + start_index, count, max_elements, platform_version, diff --git a/packages/rs-drive-proof-verifier/src/types.rs b/packages/rs-drive-proof-verifier/src/types.rs index 5798482789f..65d1194c7c2 100644 --- a/packages/rs-drive-proof-verifier/src/types.rs +++ b/packages/rs-drive-proof-verifier/src/types.rs @@ -832,8 +832,8 @@ pub struct ShieldedNullifierStatuses(pub Vec); platform_serialize(unversioned) )] pub struct ShieldedEncryptedNotesQuery { - /// Optional pagination cursor (32 bytes, exclusive start) - pub start_cmx: Option>, + /// Starting index in the encrypted notes count tree (inclusive, 0 = from beginning) + pub start_index: u64, /// Max number of notes to return pub count: u32, } diff --git a/packages/rs-drive/src/drive/initialization/v3/mod.rs b/packages/rs-drive/src/drive/initialization/v3/mod.rs index 7fdc1e0f736..fc45ad87db3 100644 --- a/packages/rs-drive/src/drive/initialization/v3/mod.rs +++ b/packages/rs-drive/src/drive/initialization/v3/mod.rs @@ -93,11 +93,11 @@ impl Drive { Element::empty_tree(), ); - // 4. Encrypted notes tree (NormalTree) + // 4. Encrypted notes tree (CountTree — count tracks the next sequential index) batch.add_insert( shielded_credit_pool_path_vec(), vec![SHIELDED_ENCRYPTED_NOTES_KEY], - Element::empty_tree(), + Element::empty_count_tree(), ); // 5. Params item diff --git a/packages/rs-drive/src/drive/shielded/estimated_costs.rs b/packages/rs-drive/src/drive/shielded/estimated_costs.rs index 30570c0b2c5..1337f7f6d08 100644 --- a/packages/rs-drive/src/drive/shielded/estimated_costs.rs +++ b/packages/rs-drive/src/drive/shielded/estimated_costs.rs @@ -1,7 +1,7 @@ use crate::drive::shielded::paths::{ - shielded_anchors_credit_pool_path, shielded_anchors_path, shielded_credit_pool_commitments_path, - shielded_credit_pool_encrypted_notes_path, shielded_credit_pool_nullifiers_path, - shielded_credit_pool_path, + shielded_anchors_credit_pool_path, shielded_anchors_path, + shielded_credit_pool_commitments_path, shielded_credit_pool_encrypted_notes_path, + shielded_credit_pool_nullifiers_path, shielded_credit_pool_path, }; use crate::drive::Drive; use grovedb::batch::KeyInfoPath; @@ -11,12 +11,15 @@ use grovedb::EstimatedSumTrees::{NoSumTrees, SomeSumTrees}; use grovedb::{EstimatedLayerInformation, TreeType}; use std::collections::HashMap; -/// Average size of an encrypted note (~692 bytes: 32 epk + 580 enc + 80 out) -const AVERAGE_ENCRYPTED_NOTE_SIZE: u32 = 692; +/// Average size of an encrypted note value: 32 cmx + 216 encrypted note = 248 bytes +const AVERAGE_ENCRYPTED_NOTE_VALUE_SIZE: u32 = 248; /// Size of a commitment or nullifier key (32 bytes) const COMMITMENT_KEY_SIZE: u8 = 32; +/// Size of an encrypted notes index key (u64 big-endian = 8 bytes) +const ENCRYPTED_NOTE_INDEX_KEY_SIZE: u8 = 8; + /// Size of an anchor key (32 bytes) const ANCHOR_KEY_SIZE: u8 = 32; @@ -42,9 +45,9 @@ impl Drive { SomeSumTrees { sum_trees_weight: 0, big_sum_trees_weight: 0, - count_trees_weight: 0, + count_trees_weight: 1, count_sum_trees_weight: 0, - non_sum_trees_weight: 3, + non_sum_trees_weight: 2, }, None, 3, // 3 subtrees: commitments, nullifiers, encrypted notes @@ -78,15 +81,15 @@ impl Drive { ); // Encrypted notes tree: [AddressBalances, "s", 3] - // NormalTree - stores encrypted notes (32-byte key → ~692-byte item) + // CountTree - stores encrypted notes (8-byte u64 index key → 248-byte cmx+encrypted_note) estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(shielded_credit_pool_encrypted_notes_path()), EstimatedLayerInformation { - tree_type: TreeType::NormalTree, + tree_type: TreeType::CountTree, estimated_layer_count: EstimatedLevel(10, false), estimated_layer_sizes: AllItems( - COMMITMENT_KEY_SIZE, - AVERAGE_ENCRYPTED_NOTE_SIZE, + ENCRYPTED_NOTE_INDEX_KEY_SIZE, + AVERAGE_ENCRYPTED_NOTE_VALUE_SIZE, None, ), }, diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs index 3bce1e6fd1e..1ed7ba86664 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs @@ -121,8 +121,7 @@ impl DriveHighLevelOperationConverter for StateTransitionAction { .into_high_level_drive_operations(epoch, platform_version) } StateTransitionAction::ShieldedWithdrawalAction(shielded_withdrawal_action) => { - shielded_withdrawal_action - .into_high_level_drive_operations(epoch, platform_version) + shielded_withdrawal_action.into_high_level_drive_operations(epoch, platform_version) } } } diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs index 53746f1ffc3..8c98eb892d3 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs @@ -1,7 +1,3 @@ -use crate::drive::shielded::paths::{ - shielded_credit_pool_encrypted_notes_path_vec, shielded_credit_pool_nullifiers_path_vec, - shielded_credit_pool_path_vec, SHIELDED_COMMITMENTS_KEY, SHIELDED_TOTAL_BALANCE_KEY, -}; use crate::error::Error; use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; use crate::state_transition_action::shielded::shield::ShieldTransitionAction; @@ -10,15 +6,32 @@ use crate::state_transition_action::shielded::shielded_transfer::ShieldedTransfe use crate::state_transition_action::shielded::shielded_withdrawal::ShieldedWithdrawalTransitionAction; use crate::state_transition_action::shielded::unshield::UnshieldTransitionAction; use crate::util::batch::drive_op_batch::finalize_task::DriveOperationFinalizeTask; -use crate::util::batch::drive_op_batch::AddressFundsOperationType; -use crate::util::batch::{DocumentOperationType, DriveOperation, SystemOperationType}; +use crate::util::batch::drive_op_batch::{ + AddressFundsOperationType, ShieldedPoolOperationType, SystemOperationType, +}; +use crate::util::batch::{DocumentOperationType, DriveOperation}; use crate::util::object_size_info::{DocumentInfo, OwnedDocumentInfo}; use dpp::asset_lock::reduced_asset_lock_value::AssetLockValue; use dpp::block::epoch::Epoch; use dpp::version::PlatformVersion; -use grovedb::batch::QualifiedGroveDbOp; use grovedb::Element; +/// Build the encrypted note items (cmx || encrypted_note) for auto-incremented insertion. +fn build_encrypted_note_items( + note_commitments: &[[u8; 32]], + encrypted_notes: &[Vec], +) -> Vec { + note_commitments + .iter() + .zip(encrypted_notes.iter()) + .map(|(cmx, encrypted_note)| { + let mut value = cmx.to_vec(); + value.extend_from_slice(encrypted_note); + Element::new_item(value) + }) + .collect() +} + impl DriveHighLevelOperationConverter for ShieldTransitionAction { fn into_high_level_drive_operations<'a>( self, @@ -40,46 +53,35 @@ impl DriveHighLevelOperationConverter for ShieldTransitionAction { )); } - let encrypted_notes_path = shielded_credit_pool_encrypted_notes_path_vec(); - let pool_path = shielded_credit_pool_path_vec(); - // 2. Append each note commitment to the commitment tree for cmx in v0.note_commitments.iter() { ops.push(DriveOperation::ShieldedPoolOperation( - QualifiedGroveDbOp::commitment_tree_append_op( - pool_path.clone(), - vec![SHIELDED_COMMITMENTS_KEY], - *cmx, - ), + ShieldedPoolOperationType::AppendNoteCommitment { cmx: *cmx }, )); } - // 3. Insert encrypted notes keyed by their commitment - for (cmx, encrypted_note) in - v0.note_commitments.iter().zip(v0.encrypted_notes.iter()) - { - ops.push(DriveOperation::ShieldedPoolOperation( - QualifiedGroveDbOp::insert_only_op( - encrypted_notes_path.clone(), - cmx.to_vec(), - Element::new_item(encrypted_note.clone()), + // 3. Insert encrypted notes with auto-incremented keys in count tree + ops.push(DriveOperation::ShieldedPoolOperation( + ShieldedPoolOperationType::InsertEncryptedNotes { + items: build_encrypted_note_items( + &v0.note_commitments, + &v0.encrypted_notes, ), - )); - } + }, + )); // 4. Update total balance SumItem: current_total_balance + shield_amount - let new_total_balance = v0.current_total_balance.checked_add(v0.shield_amount) - .ok_or_else(|| Error::Drive( - crate::error::drive::DriveError::CorruptedDriveState( - "shielded pool total balance overflow when adding shield amount".to_string(), - ), - ))?; + let new_total_balance = v0 + .current_total_balance + .checked_add(v0.shield_amount) + .ok_or_else(|| { + Error::Drive(crate::error::drive::DriveError::CorruptedDriveState( + "shielded pool total balance overflow when adding shield amount" + .to_string(), + )) + })?; ops.push(DriveOperation::ShieldedPoolOperation( - QualifiedGroveDbOp::insert_or_replace_op( - pool_path, - vec![SHIELDED_TOTAL_BALANCE_KEY], - Element::new_sum_item(new_total_balance as i64), - ), + ShieldedPoolOperationType::UpdateTotalBalance { new_total_balance }, )); // Checkpoint the commitment tree and record anchor after batch is applied @@ -103,60 +105,44 @@ impl DriveHighLevelOperationConverter for ShieldedTransferTransitionAction { ShieldedTransferTransitionAction::V0(v0) => { let mut ops: Vec> = Vec::new(); - let nullifiers_path = shielded_credit_pool_nullifiers_path_vec(); - let encrypted_notes_path = shielded_credit_pool_encrypted_notes_path_vec(); - let pool_path = shielded_credit_pool_path_vec(); - - // 1. Insert each nullifier (empty Item, InsertOnly to prevent double-spend) + // 1. Insert each nullifier (InsertOnly to prevent double-spend) for nullifier in v0.nullifiers.iter() { ops.push(DriveOperation::ShieldedPoolOperation( - QualifiedGroveDbOp::insert_only_op( - nullifiers_path.clone(), - nullifier.to_vec(), - Element::new_item(vec![]), - ), + ShieldedPoolOperationType::InsertNullifier { + nullifier: *nullifier, + }, )); } // 2. Append each note commitment to the commitment tree for cmx in v0.note_commitments.iter() { ops.push(DriveOperation::ShieldedPoolOperation( - QualifiedGroveDbOp::commitment_tree_append_op( - pool_path.clone(), - vec![SHIELDED_COMMITMENTS_KEY], - *cmx, - ), + ShieldedPoolOperationType::AppendNoteCommitment { cmx: *cmx }, )); } - // 3. Insert encrypted notes keyed by their commitment - for (cmx, encrypted_note) in - v0.note_commitments.iter().zip(v0.encrypted_notes.iter()) - { - ops.push(DriveOperation::ShieldedPoolOperation( - QualifiedGroveDbOp::insert_only_op( - encrypted_notes_path.clone(), - cmx.to_vec(), - Element::new_item(encrypted_note.clone()), + // 3. Insert encrypted notes with auto-incremented keys in count tree + ops.push(DriveOperation::ShieldedPoolOperation( + ShieldedPoolOperationType::InsertEncryptedNotes { + items: build_encrypted_note_items( + &v0.note_commitments, + &v0.encrypted_notes, ), - )); - } + }, + )); // 4. Update total balance SumItem: subtract fee_amount let new_total_balance = v0 .current_total_balance .checked_sub(v0.fee_amount) - .ok_or_else(|| Error::Drive( - crate::error::drive::DriveError::CorruptedDriveState( - "shielded pool total balance underflow when subtracting fee_amount".to_string(), - ), - ))?; + .ok_or_else(|| { + Error::Drive(crate::error::drive::DriveError::CorruptedDriveState( + "shielded pool total balance underflow when subtracting fee_amount" + .to_string(), + )) + })?; ops.push(DriveOperation::ShieldedPoolOperation( - QualifiedGroveDbOp::insert_or_replace_op( - pool_path, - vec![SHIELDED_TOTAL_BALANCE_KEY], - Element::new_sum_item(new_total_balance as i64), - ), + ShieldedPoolOperationType::UpdateTotalBalance { new_total_balance }, )); // Checkpoint the commitment tree and record anchor after batch is applied @@ -180,18 +166,12 @@ impl DriveHighLevelOperationConverter for UnshieldTransitionAction { UnshieldTransitionAction::V0(v0) => { let mut ops: Vec> = Vec::new(); - let nullifiers_path = shielded_credit_pool_nullifiers_path_vec(); - let encrypted_notes_path = shielded_credit_pool_encrypted_notes_path_vec(); - let pool_path = shielded_credit_pool_path_vec(); - - // 1. Insert each nullifier (empty Item, InsertOnly to prevent double-spend) + // 1. Insert each nullifier (InsertOnly to prevent double-spend) for nullifier in v0.nullifiers.iter() { ops.push(DriveOperation::ShieldedPoolOperation( - QualifiedGroveDbOp::insert_only_op( - nullifiers_path.clone(), - nullifier.to_vec(), - Element::new_item(vec![]), - ), + ShieldedPoolOperationType::InsertNullifier { + nullifier: *nullifier, + }, )); } @@ -206,26 +186,19 @@ impl DriveHighLevelOperationConverter for UnshieldTransitionAction { // 3. Append each note commitment (change outputs) to the commitment tree for cmx in v0.note_commitments.iter() { ops.push(DriveOperation::ShieldedPoolOperation( - QualifiedGroveDbOp::commitment_tree_append_op( - pool_path.clone(), - vec![SHIELDED_COMMITMENTS_KEY], - *cmx, - ), + ShieldedPoolOperationType::AppendNoteCommitment { cmx: *cmx }, )); } - // 4. Insert encrypted notes keyed by their commitment - for (cmx, encrypted_note) in - v0.note_commitments.iter().zip(v0.encrypted_notes.iter()) - { - ops.push(DriveOperation::ShieldedPoolOperation( - QualifiedGroveDbOp::insert_only_op( - encrypted_notes_path.clone(), - cmx.to_vec(), - Element::new_item(encrypted_note.clone()), + // 4. Insert encrypted notes with auto-incremented keys in count tree + ops.push(DriveOperation::ShieldedPoolOperation( + ShieldedPoolOperationType::InsertEncryptedNotes { + items: build_encrypted_note_items( + &v0.note_commitments, + &v0.encrypted_notes, ), - )); - } + }, + )); // 5. Update total balance SumItem: subtract the unshielded amount // (fee is handled separately by the fee system) @@ -238,11 +211,7 @@ impl DriveHighLevelOperationConverter for UnshieldTransitionAction { ), ))?; ops.push(DriveOperation::ShieldedPoolOperation( - QualifiedGroveDbOp::insert_or_replace_op( - pool_path, - vec![SHIELDED_TOTAL_BALANCE_KEY], - Element::new_sum_item(new_total_balance as i64), - ), + ShieldedPoolOperationType::UpdateTotalBalance { new_total_balance }, )); // Checkpoint the commitment tree and record anchor after batch is applied @@ -289,32 +258,22 @@ impl DriveHighLevelOperationConverter for ShieldFromAssetLockTransitionAction { }, )); - let encrypted_notes_path = shielded_credit_pool_encrypted_notes_path_vec(); - let pool_path = shielded_credit_pool_path_vec(); - // 3. Append note commitments to commitment tree for cmx in v0.note_commitments.iter() { ops.push(DriveOperation::ShieldedPoolOperation( - QualifiedGroveDbOp::commitment_tree_append_op( - pool_path.clone(), - vec![SHIELDED_COMMITMENTS_KEY], - *cmx, - ), + ShieldedPoolOperationType::AppendNoteCommitment { cmx: *cmx }, )); } - // 4. Insert encrypted notes keyed by their commitment - for (cmx, encrypted_note) in - v0.note_commitments.iter().zip(v0.encrypted_notes.iter()) - { - ops.push(DriveOperation::ShieldedPoolOperation( - QualifiedGroveDbOp::insert_only_op( - encrypted_notes_path.clone(), - cmx.to_vec(), - Element::new_item(encrypted_note.clone()), + // 4. Insert encrypted notes with auto-incremented keys in count tree + ops.push(DriveOperation::ShieldedPoolOperation( + ShieldedPoolOperationType::InsertEncryptedNotes { + items: build_encrypted_note_items( + &v0.note_commitments, + &v0.encrypted_notes, ), - )); - } + }, + )); // 5. Update total balance: current_total_balance + shield_amount let new_total_balance = v0.current_total_balance.checked_add(v0.shield_amount) @@ -324,11 +283,7 @@ impl DriveHighLevelOperationConverter for ShieldFromAssetLockTransitionAction { ), ))?; ops.push(DriveOperation::ShieldedPoolOperation( - QualifiedGroveDbOp::insert_or_replace_op( - pool_path, - vec![SHIELDED_TOTAL_BALANCE_KEY], - Element::new_sum_item(new_total_balance as i64), - ), + ShieldedPoolOperationType::UpdateTotalBalance { new_total_balance }, )); // 6. Record anchor after batch is applied @@ -352,44 +307,31 @@ impl DriveHighLevelOperationConverter for ShieldedWithdrawalTransitionAction { ShieldedWithdrawalTransitionAction::V0(v0) => { let mut ops: Vec> = Vec::new(); - let nullifiers_path = shielded_credit_pool_nullifiers_path_vec(); - let encrypted_notes_path = shielded_credit_pool_encrypted_notes_path_vec(); - let pool_path = shielded_credit_pool_path_vec(); - // 1. Insert nullifiers (prevent double-spend) for nullifier in v0.nullifiers.iter() { ops.push(DriveOperation::ShieldedPoolOperation( - QualifiedGroveDbOp::insert_only_op( - nullifiers_path.clone(), - nullifier.to_vec(), - Element::new_item(vec![]), - ), + ShieldedPoolOperationType::InsertNullifier { + nullifier: *nullifier, + }, )); } // 2. Append change note commitments to commitment tree for cmx in v0.note_commitments.iter() { ops.push(DriveOperation::ShieldedPoolOperation( - QualifiedGroveDbOp::commitment_tree_append_op( - pool_path.clone(), - vec![SHIELDED_COMMITMENTS_KEY], - *cmx, - ), + ShieldedPoolOperationType::AppendNoteCommitment { cmx: *cmx }, )); } - // 3. Insert encrypted change notes - for (cmx, encrypted_note) in - v0.note_commitments.iter().zip(v0.encrypted_notes.iter()) - { - ops.push(DriveOperation::ShieldedPoolOperation( - QualifiedGroveDbOp::insert_only_op( - encrypted_notes_path.clone(), - cmx.to_vec(), - Element::new_item(encrypted_note.clone()), + // 3. Insert encrypted change notes with auto-incremented keys in count tree + ops.push(DriveOperation::ShieldedPoolOperation( + ShieldedPoolOperationType::InsertEncryptedNotes { + items: build_encrypted_note_items( + &v0.note_commitments, + &v0.encrypted_notes, ), - )); - } + }, + )); // 4. Update total balance: subtract withdrawal amount let new_total_balance = v0 @@ -401,11 +343,7 @@ impl DriveHighLevelOperationConverter for ShieldedWithdrawalTransitionAction { ), ))?; ops.push(DriveOperation::ShieldedPoolOperation( - QualifiedGroveDbOp::insert_or_replace_op( - pool_path, - vec![SHIELDED_TOTAL_BALANCE_KEY], - Element::new_sum_item(new_total_balance as i64), - ), + ShieldedPoolOperationType::UpdateTotalBalance { new_total_balance }, )); // 5. Add withdrawal document @@ -423,9 +361,7 @@ impl DriveHighLevelOperationConverter for ShieldedWithdrawalTransitionAction { // 6. Remove credits from system (they leave the system to Core) ops.push(DriveOperation::SystemOperation( - SystemOperationType::RemoveFromSystemCredits { - amount: v0.amount, - }, + SystemOperationType::RemoveFromSystemCredits { amount: v0.amount }, )); // 7. Record anchor after batch is applied diff --git a/packages/rs-drive/src/state_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/mod.rs index b45a2d3dfb4..304bcc6c735 100644 --- a/packages/rs-drive/src/state_transition_action/mod.rs +++ b/packages/rs-drive/src/state_transition_action/mod.rs @@ -155,12 +155,8 @@ impl StateTransitionAction { StateTransitionAction::ShieldAction(action) => action.user_fee_increase(), StateTransitionAction::ShieldedTransferAction(action) => action.user_fee_increase(), StateTransitionAction::UnshieldAction(action) => action.user_fee_increase(), - StateTransitionAction::ShieldFromAssetLockAction(action) => { - action.user_fee_increase() - } - StateTransitionAction::ShieldedWithdrawalAction(action) => { - action.user_fee_increase() - } + StateTransitionAction::ShieldFromAssetLockAction(action) => action.user_fee_increase(), + StateTransitionAction::ShieldedWithdrawalAction(action) => action.user_fee_increase(), } } } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/mod.rs index ab7113c10c1..9a7d23dc9ba 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/mod.rs @@ -19,9 +19,7 @@ impl ShieldFromAssetLockTransitionAction { /// Get asset lock outpoint pub fn asset_lock_outpoint(&self) -> &[u8; 36] { match self { - ShieldFromAssetLockTransitionAction::V0(transition) => { - &transition.asset_lock_outpoint - } + ShieldFromAssetLockTransitionAction::V0(transition) => &transition.asset_lock_outpoint, } } /// Get remaining asset lock value to be consumed diff --git a/packages/rs-drive/src/state_transition_action/system/partially_use_asset_lock_action/mod.rs b/packages/rs-drive/src/state_transition_action/system/partially_use_asset_lock_action/mod.rs index c6e8106f89f..cccd20ef94a 100644 --- a/packages/rs-drive/src/state_transition_action/system/partially_use_asset_lock_action/mod.rs +++ b/packages/rs-drive/src/state_transition_action/system/partially_use_asset_lock_action/mod.rs @@ -8,9 +8,7 @@ use std::collections::BTreeMap; mod transformer; mod v0; -pub use v0::{ - PartiallyUseAssetLockActionAccessorsV0, PartiallyUseAssetLockActionV0, -}; +pub use v0::{PartiallyUseAssetLockActionAccessorsV0, PartiallyUseAssetLockActionV0}; #[derive(Debug, Clone, From)] /// An action expressing that an asset lock should be partially used diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs b/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs index 361a3fc5f64..eaee1184145 100644 --- a/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs +++ b/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs @@ -67,12 +67,13 @@ impl DriveOperationFinalizeTask { }; let (params, _): (ShieldedPoolParams, _) = - bincode::decode_from_slice(params_bytes, bincode::config::standard()) - .map_err(|e| { + bincode::decode_from_slice(params_bytes, bincode::config::standard()).map_err( + |e| { Error::Drive(crate::error::drive::DriveError::CorruptedSerialization( format!("could not decode shielded pool params: {e}"), )) - })?; + }, + )?; let new_checkpoint_id = params.checkpoint_id_counter + 1; @@ -122,11 +123,9 @@ impl DriveOperationFinalizeTask { let encoded_params = bincode::encode_to_vec(&new_params, bincode::config::standard()).map_err( |e| { - Error::Drive( - crate::error::drive::DriveError::CorruptedSerialization(format!( - "could not encode shielded pool params: {e}" - )), - ) + Error::Drive(crate::error::drive::DriveError::CorruptedSerialization( + format!("could not encode shielded pool params: {e}"), + )) }, )?; diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/mod.rs b/packages/rs-drive/src/util/batch/drive_op_batch/mod.rs index 0957d9c8f8e..ecaed96055b 100644 --- a/packages/rs-drive/src/util/batch/drive_op_batch/mod.rs +++ b/packages/rs-drive/src/util/batch/drive_op_batch/mod.rs @@ -6,6 +6,7 @@ pub(crate) mod finalize_task; mod group; mod identity; mod prefunded_specialized_balance; +mod shielded; mod system; mod token; mod withdrawals; @@ -26,6 +27,7 @@ pub use document::UpdateOperationInfo; pub use group::GroupOperationType; pub use identity::IdentityOperationType; pub use prefunded_specialized_balance::PrefundedSpecializedBalanceOperationType; +pub use shielded::ShieldedPoolOperationType; pub use system::SystemOperationType; pub use token::TokenOperationType; pub use withdrawals::WithdrawalOperationType; @@ -90,8 +92,8 @@ pub enum DriveOperation<'a> { GroupOperation(GroupOperationType), /// An address funds operation AddressFundsOperation(AddressFundsOperationType), - /// A shielded pool operation (groveDB op with estimation cost registration) - ShieldedPoolOperation(QualifiedGroveDbOp), + /// A shielded pool operation + ShieldedPoolOperation(ShieldedPoolOperationType), /// A single low level groveDB operation GroveDBOperation(QualifiedGroveDbOp), /// Multiple low level groveDB operations @@ -163,11 +165,14 @@ impl DriveLowLevelOperationConverter for DriveOperation<'_> { transaction, platform_version, ), - DriveOperation::ShieldedPoolOperation(op) => { - if let Some(ref mut estimated_costs) = estimated_costs_only_with_layer_info { - Drive::add_estimation_costs_for_shielded_pool_operations(estimated_costs); - } - Ok(vec![GroveOperation(op)]) + DriveOperation::ShieldedPoolOperation(shielded_pool_operation_type) => { + shielded_pool_operation_type.into_low_level_drive_operations( + drive, + estimated_costs_only_with_layer_info, + block_info, + transaction, + platform_version, + ) } DriveOperation::GroveDBOperation(op) => Ok(vec![GroveOperation(op)]), DriveOperation::GroveDBOpBatch(operations) => Ok(operations diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs b/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs new file mode 100644 index 00000000000..ba719339216 --- /dev/null +++ b/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs @@ -0,0 +1,99 @@ +use crate::drive::shielded::paths::{ + shielded_credit_pool_nullifiers_path_vec, shielded_credit_pool_path_vec, + SHIELDED_COMMITMENTS_KEY, SHIELDED_ENCRYPTED_NOTES_KEY, SHIELDED_TOTAL_BALANCE_KEY, +}; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::fees::op::LowLevelDriveOperation::GroveOperation; +use crate::util::batch::drive_op_batch::DriveLowLevelOperationConverter; +use dpp::block::block_info::BlockInfo; +use dpp::version::PlatformVersion; +use grovedb::batch::{KeyInfoPath, QualifiedGroveDbOp}; +use grovedb::{Element, EstimatedLayerInformation, TransactionArg}; +use std::collections::HashMap; + +/// Operations on the Shielded Pool +#[derive(Clone, Debug)] +pub enum ShieldedPoolOperationType { + /// Append a note commitment (cmx) to the commitment tree + AppendNoteCommitment { + /// The 32-byte note commitment + cmx: [u8; 32], + }, + /// Insert a nullifier to prevent double-spend + InsertNullifier { + /// The 32-byte nullifier + nullifier: [u8; 32], + }, + /// Update the shielded pool total balance + UpdateTotalBalance { + /// The new total balance value + new_total_balance: u64, + }, + /// Insert encrypted notes with auto-incremented keys in the count tree + InsertEncryptedNotes { + /// Items to insert: each is cmx (32 bytes) || encrypted_note, packed as Element + items: Vec, + }, +} + +impl DriveLowLevelOperationConverter for ShieldedPoolOperationType { + fn into_low_level_drive_operations( + self, + drive: &Drive, + estimated_costs_only_with_layer_info: &mut Option< + HashMap, + >, + _block_info: &BlockInfo, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + if let Some(ref mut estimated_costs) = estimated_costs_only_with_layer_info { + Drive::add_estimation_costs_for_shielded_pool_operations(estimated_costs); + } + + match self { + ShieldedPoolOperationType::AppendNoteCommitment { cmx } => { + let pool_path = shielded_credit_pool_path_vec(); + Ok(vec![GroveOperation( + QualifiedGroveDbOp::commitment_tree_append_op( + pool_path, + vec![SHIELDED_COMMITMENTS_KEY], + cmx, + ), + )]) + } + ShieldedPoolOperationType::InsertNullifier { nullifier } => { + let nullifiers_path = shielded_credit_pool_nullifiers_path_vec(); + Ok(vec![GroveOperation(QualifiedGroveDbOp::insert_only_op( + nullifiers_path, + nullifier.to_vec(), + Element::new_item(vec![]), + ))]) + } + ShieldedPoolOperationType::UpdateTotalBalance { new_total_balance } => { + let pool_path = shielded_credit_pool_path_vec(); + Ok(vec![GroveOperation( + QualifiedGroveDbOp::insert_or_replace_op( + pool_path, + vec![SHIELDED_TOTAL_BALANCE_KEY], + Element::new_sum_item(new_total_balance as i64), + ), + )]) + } + ShieldedPoolOperationType::InsertEncryptedNotes { items } => { + let mut ops = vec![]; + drive.batch_insert_auto_incremented_items_in_count_tree( + shielded_credit_pool_path_vec(), + &[SHIELDED_ENCRYPTED_NOTES_KEY], + items, + transaction, + &mut ops, + &platform_version.drive, + )?; + Ok(ops) + } + } + } +} diff --git a/packages/rs-drive/src/util/grove_operations/batch_insert_auto_incremented_items_in_count_tree/mod.rs b/packages/rs-drive/src/util/grove_operations/batch_insert_auto_incremented_items_in_count_tree/mod.rs new file mode 100644 index 00000000000..588876aeb4c --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/batch_insert_auto_incremented_items_in_count_tree/mod.rs @@ -0,0 +1,44 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::version::drive_versions::DriveVersion; +use grovedb::{Element, TransactionArg}; + +impl Drive { + /// Inserts multiple items into a count tree with auto-incremented u64 big-endian keys. + /// + /// Reads the current count from the count tree, then generates sequential insert + /// operations starting from that count. + pub fn batch_insert_auto_incremented_items_in_count_tree( + &self, + parent_path: Vec>, + count_tree_key: &[u8], + items: Vec, + transaction: TransactionArg, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result<(), Error> { + match drive_version + .grove_methods + .batch + .batch_insert_auto_incremented_items_in_count_tree + { + 0 => self.batch_insert_auto_incremented_items_in_count_tree_v0( + parent_path, + count_tree_key, + items, + transaction, + drive_operations, + drive_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "batch_insert_auto_incremented_items_in_count_tree".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/util/grove_operations/batch_insert_auto_incremented_items_in_count_tree/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/batch_insert_auto_incremented_items_in_count_tree/v0/mod.rs new file mode 100644 index 00000000000..d46442c815a --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/batch_insert_auto_incremented_items_in_count_tree/v0/mod.rs @@ -0,0 +1,64 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::DirectQueryType; +use dpp::version::drive_versions::DriveVersion; +use grovedb::{Element, TransactionArg}; + +impl Drive { + /// Inserts multiple items into a count tree with auto-incremented u64 big-endian keys. + /// + /// Reads the current count from the count tree, then generates sequential insert + /// operations starting from that count. + /// + /// # Parameters + /// * `parent_path` - Path to the parent tree containing the count tree + /// * `count_tree_key` - Key of the count tree under the parent path + /// * `items` - Items (Elements) to insert with auto-incremented keys + /// * `transaction` - GroveDB transaction + /// * `drive_operations` - Accumulator for low-level drive operations + /// * `drive_version` - Drive version for method dispatch + pub(crate) fn batch_insert_auto_incremented_items_in_count_tree_v0( + &self, + parent_path: Vec>, + count_tree_key: &[u8], + items: Vec, + transaction: TransactionArg, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result<(), Error> { + if items.is_empty() { + return Ok(()); + } + + // Read the current count from the count tree element + let current_count = self + .grove_get_raw_optional( + parent_path.as_slice().into(), + count_tree_key, + DirectQueryType::StatefulDirectQuery, + transaction, + drive_operations, + drive_version, + )? + .map(|element| element.count_value_or_default()) + .unwrap_or(0); + + // Build the full path to the count tree (parent_path + count_tree_key) + let mut insert_path = parent_path; + insert_path.push(count_tree_key.to_vec()); + + // Insert each item with a sequential key + for (i, element) in items.into_iter().enumerate() { + let index = current_count + i as u64; + drive_operations.push(LowLevelDriveOperation::insert_for_known_path_key_element( + insert_path.clone(), + index.to_be_bytes().to_vec(), + element, + )); + } + + Ok(()) + } +} diff --git a/packages/rs-drive/src/util/grove_operations/mod.rs b/packages/rs-drive/src/util/grove_operations/mod.rs index 8d8cd7f3c8a..e0cb4cff5dc 100644 --- a/packages/rs-drive/src/util/grove_operations/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/mod.rs @@ -140,6 +140,8 @@ pub mod batch_insert_sum_item_if_not_exists; /// Moved items that are found in a path query to a new path. pub mod batch_move_items_in_path_query; +/// Batch inserts items into a count tree with auto-incremented keys +pub mod batch_insert_auto_incremented_items_in_count_tree; /// Batch inserts item with sum item if not already existing pub mod batch_insert_item_with_sum_item_if_not_exists; /// Keeps the item, but inserts or adds to the sum item if it already exists diff --git a/packages/rs-drive/src/verify/mod.rs b/packages/rs-drive/src/verify/mod.rs index a8edff11378..5179fcef77c 100644 --- a/packages/rs-drive/src/verify/mod.rs +++ b/packages/rs-drive/src/verify/mod.rs @@ -16,14 +16,14 @@ pub mod system; pub mod address_funds; /// Group proof verification module pub mod group; +/// Shielded pool proof verification module +pub mod shielded; /// Verifies that a state transition contents exist in the proof pub mod state_transition; /// Token proof verification module pub mod tokens; /// Voting proof verification module pub mod voting; -/// Shielded pool proof verification module -pub mod shielded; /// Represents the root hash of the grovedb tree pub type RootHash = [u8; 32]; diff --git a/packages/rs-drive/src/verify/shielded/mod.rs b/packages/rs-drive/src/verify/shielded/mod.rs index fac116b3830..f7343add55f 100644 --- a/packages/rs-drive/src/verify/shielded/mod.rs +++ b/packages/rs-drive/src/verify/shielded/mod.rs @@ -1,8 +1,8 @@ -/// Module for verifying shielded pool state (total balance) -pub mod verify_shielded_pool_state; /// Module for verifying shielded anchors pub mod verify_shielded_anchors; /// Module for verifying shielded encrypted notes pub mod verify_shielded_encrypted_notes; /// Module for verifying shielded nullifiers pub mod verify_shielded_nullifiers; +/// Module for verifying shielded pool state (total balance) +pub mod verify_shielded_pool_state; diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs index af9c15b1a1e..0ca67408b4a 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs @@ -19,11 +19,8 @@ impl Drive { }, }; - let (root_hash, proved_key_values) = GroveDb::verify_query( - proof, - &path_query, - &platform_version.drive.grove_version, - )?; + let (root_hash, proved_key_values) = + GroveDb::verify_query(proof, &path_query, &platform_version.drive.grove_version)?; let anchors = proved_key_values .into_iter() diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/mod.rs index 5c4da081688..e558567a9ae 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/mod.rs @@ -10,7 +10,7 @@ impl Drive { /// Verifies a proof for shielded encrypted notes. pub fn verify_shielded_encrypted_notes( proof: &[u8], - start_cmx: &[u8], + start_index: u64, count: u32, max_elements: u32, platform_version: &PlatformVersion, @@ -24,7 +24,7 @@ impl Drive { { 0 => Self::verify_shielded_encrypted_notes_v0( proof, - start_cmx, + start_index, count, max_elements, platform_version, diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs index 32750854957..40039b8c0f8 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs @@ -8,7 +8,7 @@ use platform_version::version::PlatformVersion; impl Drive { pub(super) fn verify_shielded_encrypted_notes_v0( proof: &[u8], - start_cmx: &[u8], + start_index: u64, count: u32, max_elements: u32, platform_version: &PlatformVersion, @@ -19,11 +19,11 @@ impl Drive { count as u16 }; - let query = if start_cmx.is_empty() { + let query = if start_index == 0 { Query::new_range_full() } else { let mut q = Query::new(); - q.insert_range_after(start_cmx.to_vec()..); + q.insert_range_from(start_index.to_be_bytes().to_vec()..); q }; @@ -36,17 +36,19 @@ impl Drive { }, }; - let (root_hash, proved_key_values) = GroveDb::verify_query( - proof, - &path_query, - &platform_version.drive.grove_version, - )?; + let (root_hash, proved_key_values) = + GroveDb::verify_query(proof, &path_query, &platform_version.drive.grove_version)?; let notes = proved_key_values .into_iter() - .filter_map(|(_, key, maybe_element)| { - if let Some(Element::Item(bytes, _)) = maybe_element { - Some((key, bytes)) + .filter_map(|(_, _key, maybe_element)| { + if let Some(Element::Item(value, _)) = maybe_element { + // Value format: cmx (32 bytes) || encrypted_note (remaining bytes) + if value.len() > 32 { + Some((value[..32].to_vec(), value[32..].to_vec())) + } else { + None + } } else { None } diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/mod.rs index dd0d2b64b6b..f10f99fc6d7 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/mod.rs @@ -60,6 +60,7 @@ pub struct DriveGroveBatchMethodVersions { pub batch_insert_empty_sum_tree: FeatureVersion, pub batch_move: FeatureVersion, pub batch_insert_item_with_sum_item_if_not_exists: FeatureVersion, + pub batch_insert_auto_incremented_items_in_count_tree: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/v1.rs index f6376001473..162d8bcfa0b 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/v1.rs @@ -51,6 +51,7 @@ pub const DRIVE_GROVE_METHOD_VERSIONS_V1: DriveGroveMethodVersions = DriveGroveM batch_insert_empty_sum_tree: 0, batch_move: 0, batch_insert_item_with_sum_item_if_not_exists: 0, + batch_insert_auto_incremented_items_in_count_tree: 0, }, apply: DriveGroveApplyMethodVersions { grove_apply_operation: 0, diff --git a/packages/rs-sdk/src/platform/query.rs b/packages/rs-sdk/src/platform/query.rs index 763fe6b579b..2d4e9e78682 100644 --- a/packages/rs-sdk/src/platform/query.rs +++ b/packages/rs-sdk/src/platform/query.rs @@ -1027,7 +1027,7 @@ impl Query for ShieldedEncryptedNotesQuery { Ok(GetShieldedEncryptedNotesRequest { version: Some(get_shielded_encrypted_notes_request::Version::V0( get_shielded_encrypted_notes_request::GetShieldedEncryptedNotesRequestV0 { - start_cmx: self.start_cmx.unwrap_or_default(), + start_index: self.start_index, count: self.count, prove, }, diff --git a/packages/rs-sdk/src/platform/types/shielded.rs b/packages/rs-sdk/src/platform/types/shielded.rs index 8aed8506b9a..38b41f0ab4b 100644 --- a/packages/rs-sdk/src/platform/types/shielded.rs +++ b/packages/rs-sdk/src/platform/types/shielded.rs @@ -15,9 +15,7 @@ impl FetchCurrent for ShieldedPoolState { async fn fetch_current_with_metadata(sdk: &Sdk) -> Result<(Self, ResponseMetadata), Error> { let (state, metadata) = Self::fetch_with_metadata(sdk, NoParamQuery {}, None).await?; Ok(( - state.ok_or(Error::Generic( - "shielded pool state not found".to_string(), - ))?, + state.ok_or(Error::Generic("shielded pool state not found".to_string()))?, metadata, )) } @@ -28,9 +26,7 @@ impl FetchCurrent for ShieldedPoolState { let (state, metadata, proof) = Self::fetch_with_metadata_and_proof(sdk, NoParamQuery {}, None).await?; Ok(( - state.ok_or(Error::Generic( - "shielded pool state not found".to_string(), - ))?, + state.ok_or(Error::Generic("shielded pool state not found".to_string()))?, metadata, proof, )) @@ -47,9 +43,7 @@ impl FetchCurrent for ShieldedAnchors { async fn fetch_current_with_metadata(sdk: &Sdk) -> Result<(Self, ResponseMetadata), Error> { let (anchors, metadata) = Self::fetch_with_metadata(sdk, NoParamQuery {}, None).await?; Ok(( - anchors.ok_or(Error::Generic( - "shielded anchors not found".to_string(), - ))?, + anchors.ok_or(Error::Generic("shielded anchors not found".to_string()))?, metadata, )) } @@ -60,9 +54,7 @@ impl FetchCurrent for ShieldedAnchors { let (anchors, metadata, proof) = Self::fetch_with_metadata_and_proof(sdk, NoParamQuery {}, None).await?; Ok(( - anchors.ok_or(Error::Generic( - "shielded anchors not found".to_string(), - ))?, + anchors.ok_or(Error::Generic("shielded anchors not found".to_string()))?, metadata, proof, )) From 5c34e02601cd150dc1e21b4eb6bf25907b2c3cae Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 11 Feb 2026 20:29:02 +0000 Subject: [PATCH 10/40] more work --- .../clients/drive/v0/nodejs/drive_pbjs.js | 4834 +++++++++++++++++ .../dash/platform/dapi/v0/PlatformGrpc.java | 296 + .../platform/v0/nodejs/platform_pbjs.js | 4834 +++++++++++++++++ .../platform/v0/nodejs/platform_protoc.js | 4547 ++++++++++++++++ .../platform/v0/objective-c/Platform.pbobjc.h | 468 ++ .../platform/v0/objective-c/Platform.pbobjc.m | 1261 +++++ .../platform/v0/objective-c/Platform.pbrpc.h | 52 + .../platform/v0/objective-c/Platform.pbrpc.m | 80 + .../platform/v0/python/platform_pb2.py | 1111 +++- .../platform/v0/python/platform_pb2_grpc.py | 132 + .../clients/platform/v0/web/platform_pb.d.ts | 606 +++ .../clients/platform/v0/web/platform_pb.js | 4547 ++++++++++++++++ .../platform/v0/web/platform_pb_service.d.ts | 76 + .../platform/v0/web/platform_pb_service.js | 160 + .../src/services/platform_service/mod.rs | 25 + packages/rs-dpp/src/shielded/mod.rs | 25 + .../src/state_transition/proof_result.rs | 1 + .../methods/mod.rs | 60 + .../methods/v0/mod.rs | 35 + .../shield_from_asset_lock_transition/mod.rs | 1 + .../v0/mod.rs | 1 + .../v0/v0_methods.rs | 57 + .../shielded/shield_transition/methods/mod.rs | 66 + .../shield_transition/methods/v0/mod.rs | 42 + .../shielded/shield_transition/mod.rs | 1 + .../shielded/shield_transition/v0/mod.rs | 2 + .../shield_transition/v0/v0_methods.rs | 66 + .../methods/mod.rs | 50 + .../methods/v0/mod.rs | 26 + .../shielded_transfer_transition/mod.rs | 1 + .../shielded_transfer_transition/v0/mod.rs | 1 + .../v0/v0_methods.rs | 33 + .../methods/mod.rs | 60 + .../methods/v0/mod.rs | 33 + .../shielded_withdrawal_transition/mod.rs | 1 + .../shielded_withdrawal_transition/v0/mod.rs | 1 + .../v0/v0_methods.rs | 43 + .../unshield_transition/methods/mod.rs | 55 + .../unshield_transition/methods/v0/mod.rs | 29 + .../shielded/unshield_transition/mod.rs | 1 + .../shielded/unshield_transition/v0/mod.rs | 1 + .../unshield_transition/v0/v0_methods.rs | 38 + .../shield_from_asset_lock/mod.rs | 3 + .../shield_from_asset_lock/tests.rs | 794 +++ .../state_transitions/shielded_common/mod.rs | 26 +- .../shielded_transfer/tests.rs | 20 +- .../transform_into_action/v0/mod.rs | 15 +- .../shielded_withdrawal/mod.rs | 1 + .../shielded_withdrawal/tests.rs | 1114 ++++ .../transform_into_action/v0/mod.rs | 15 +- .../state_transitions/unshield/tests.rs | 12 +- .../unshield/transform_into_action/v0/mod.rs | 15 +- .../verify_state_transitions.rs | 7 + .../v0/mod.rs | 43 +- .../src/system/queries/path_elements.rs | 2 + packages/rs-sdk/src/platform/transition.rs | 5 + .../rs-sdk/src/platform/transition/shield.rs | 120 + .../transition/shield_from_asset_lock.rs | 68 + .../platform/transition/shielded_transfer.rs | 59 + .../transition/shielded_withdrawal.rs | 73 + .../src/platform/transition/unshield.rs | 66 + packages/strategy-tests/src/lib.rs | 14 + packages/strategy-tests/src/operations.rs | 30 + .../src/errors/consensus/consensus_error.rs | 30 +- .../state_transition/transition_types.rs | 10 + .../state_transition_factory.rs | 15 + .../base/state_transition.rs | 46 +- 67 files changed, 26291 insertions(+), 71 deletions(-) create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/methods/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/methods/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/methods/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/methods/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/v0_methods.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/v0_methods.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs create mode 100644 packages/rs-sdk/src/platform/transition/shield.rs create mode 100644 packages/rs-sdk/src/platform/transition/shield_from_asset_lock.rs create mode 100644 packages/rs-sdk/src/platform/transition/shielded_transfer.rs create mode 100644 packages/rs-sdk/src/platform/transition/shielded_withdrawal.rs create mode 100644 packages/rs-sdk/src/platform/transition/unshield.rs diff --git a/packages/dapi-grpc/clients/drive/v0/nodejs/drive_pbjs.js b/packages/dapi-grpc/clients/drive/v0/nodejs/drive_pbjs.js index c696c907dc6..6a3c8772fbc 100644 --- a/packages/dapi-grpc/clients/drive/v0/nodejs/drive_pbjs.js +++ b/packages/dapi-grpc/clients/drive/v0/nodejs/drive_pbjs.js @@ -2343,6 +2343,138 @@ $root.org = (function() { * @variation 2 */ + /** + * Callback as used by {@link org.dash.platform.dapi.v0.Platform#getShieldedEncryptedNotes}. + * @memberof org.dash.platform.dapi.v0.Platform + * @typedef getShieldedEncryptedNotesCallback + * @type {function} + * @param {Error|null} error Error, if any + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} [response] GetShieldedEncryptedNotesResponse + */ + + /** + * Calls getShieldedEncryptedNotes. + * @function getShieldedEncryptedNotes + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesRequest} request GetShieldedEncryptedNotesRequest message or plain object + * @param {org.dash.platform.dapi.v0.Platform.getShieldedEncryptedNotesCallback} callback Node-style callback called with the error, if any, and GetShieldedEncryptedNotesResponse + * @returns {undefined} + * @variation 1 + */ + Object.defineProperty(Platform.prototype.getShieldedEncryptedNotes = function getShieldedEncryptedNotes(request, callback) { + return this.rpcCall(getShieldedEncryptedNotes, $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest, $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse, request, callback); + }, "name", { value: "getShieldedEncryptedNotes" }); + + /** + * Calls getShieldedEncryptedNotes. + * @function getShieldedEncryptedNotes + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesRequest} request GetShieldedEncryptedNotesRequest message or plain object + * @returns {Promise} Promise + * @variation 2 + */ + + /** + * Callback as used by {@link org.dash.platform.dapi.v0.Platform#getShieldedAnchors}. + * @memberof org.dash.platform.dapi.v0.Platform + * @typedef getShieldedAnchorsCallback + * @type {function} + * @param {Error|null} error Error, if any + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} [response] GetShieldedAnchorsResponse + */ + + /** + * Calls getShieldedAnchors. + * @function getShieldedAnchors + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsRequest} request GetShieldedAnchorsRequest message or plain object + * @param {org.dash.platform.dapi.v0.Platform.getShieldedAnchorsCallback} callback Node-style callback called with the error, if any, and GetShieldedAnchorsResponse + * @returns {undefined} + * @variation 1 + */ + Object.defineProperty(Platform.prototype.getShieldedAnchors = function getShieldedAnchors(request, callback) { + return this.rpcCall(getShieldedAnchors, $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest, $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse, request, callback); + }, "name", { value: "getShieldedAnchors" }); + + /** + * Calls getShieldedAnchors. + * @function getShieldedAnchors + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsRequest} request GetShieldedAnchorsRequest message or plain object + * @returns {Promise} Promise + * @variation 2 + */ + + /** + * Callback as used by {@link org.dash.platform.dapi.v0.Platform#getShieldedPoolState}. + * @memberof org.dash.platform.dapi.v0.Platform + * @typedef getShieldedPoolStateCallback + * @type {function} + * @param {Error|null} error Error, if any + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} [response] GetShieldedPoolStateResponse + */ + + /** + * Calls getShieldedPoolState. + * @function getShieldedPoolState + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateRequest} request GetShieldedPoolStateRequest message or plain object + * @param {org.dash.platform.dapi.v0.Platform.getShieldedPoolStateCallback} callback Node-style callback called with the error, if any, and GetShieldedPoolStateResponse + * @returns {undefined} + * @variation 1 + */ + Object.defineProperty(Platform.prototype.getShieldedPoolState = function getShieldedPoolState(request, callback) { + return this.rpcCall(getShieldedPoolState, $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest, $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse, request, callback); + }, "name", { value: "getShieldedPoolState" }); + + /** + * Calls getShieldedPoolState. + * @function getShieldedPoolState + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateRequest} request GetShieldedPoolStateRequest message or plain object + * @returns {Promise} Promise + * @variation 2 + */ + + /** + * Callback as used by {@link org.dash.platform.dapi.v0.Platform#getShieldedNullifiers}. + * @memberof org.dash.platform.dapi.v0.Platform + * @typedef getShieldedNullifiersCallback + * @type {function} + * @param {Error|null} error Error, if any + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} [response] GetShieldedNullifiersResponse + */ + + /** + * Calls getShieldedNullifiers. + * @function getShieldedNullifiers + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersRequest} request GetShieldedNullifiersRequest message or plain object + * @param {org.dash.platform.dapi.v0.Platform.getShieldedNullifiersCallback} callback Node-style callback called with the error, if any, and GetShieldedNullifiersResponse + * @returns {undefined} + * @variation 1 + */ + Object.defineProperty(Platform.prototype.getShieldedNullifiers = function getShieldedNullifiers(request, callback) { + return this.rpcCall(getShieldedNullifiers, $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest, $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse, request, callback); + }, "name", { value: "getShieldedNullifiers" }); + + /** + * Calls getShieldedNullifiers. + * @function getShieldedNullifiers + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersRequest} request GetShieldedNullifiersRequest message or plain object + * @returns {Promise} Promise + * @variation 2 + */ + return Platform; })(); @@ -82642,6 +82774,4708 @@ $root.org = (function() { return GetRecentCompactedAddressBalanceChangesResponse; })(); + v0.GetShieldedEncryptedNotesRequest = (function() { + + /** + * Properties of a GetShieldedEncryptedNotesRequest. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetShieldedEncryptedNotesRequest + * @property {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.IGetShieldedEncryptedNotesRequestV0|null} [v0] GetShieldedEncryptedNotesRequest v0 + */ + + /** + * Constructs a new GetShieldedEncryptedNotesRequest. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetShieldedEncryptedNotesRequest. + * @implements IGetShieldedEncryptedNotesRequest + * @constructor + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesRequest=} [properties] Properties to set + */ + function GetShieldedEncryptedNotesRequest(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedEncryptedNotesRequest v0. + * @member {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.IGetShieldedEncryptedNotesRequestV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @instance + */ + GetShieldedEncryptedNotesRequest.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedEncryptedNotesRequest version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @instance + */ + Object.defineProperty(GetShieldedEncryptedNotesRequest.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedEncryptedNotesRequest instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesRequest=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} GetShieldedEncryptedNotesRequest instance + */ + GetShieldedEncryptedNotesRequest.create = function create(properties) { + return new GetShieldedEncryptedNotesRequest(properties); + }; + + /** + * Encodes the specified GetShieldedEncryptedNotesRequest message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesRequest} message GetShieldedEncryptedNotesRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedEncryptedNotesRequest.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedEncryptedNotesRequest message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesRequest} message GetShieldedEncryptedNotesRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedEncryptedNotesRequest.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedEncryptedNotesRequest message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} GetShieldedEncryptedNotesRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedEncryptedNotesRequest.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedEncryptedNotesRequest message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} GetShieldedEncryptedNotesRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedEncryptedNotesRequest.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedEncryptedNotesRequest message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedEncryptedNotesRequest.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetShieldedEncryptedNotesRequest message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} GetShieldedEncryptedNotesRequest + */ + GetShieldedEncryptedNotesRequest.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedEncryptedNotesRequest message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} message GetShieldedEncryptedNotesRequest + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedEncryptedNotesRequest.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetShieldedEncryptedNotesRequest to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @instance + * @returns {Object.} JSON object + */ + GetShieldedEncryptedNotesRequest.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 = (function() { + + /** + * Properties of a GetShieldedEncryptedNotesRequestV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @interface IGetShieldedEncryptedNotesRequestV0 + * @property {number|Long|null} [startIndex] GetShieldedEncryptedNotesRequestV0 startIndex + * @property {number|null} [count] GetShieldedEncryptedNotesRequestV0 count + * @property {boolean|null} [prove] GetShieldedEncryptedNotesRequestV0 prove + */ + + /** + * Constructs a new GetShieldedEncryptedNotesRequestV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @classdesc Represents a GetShieldedEncryptedNotesRequestV0. + * @implements IGetShieldedEncryptedNotesRequestV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.IGetShieldedEncryptedNotesRequestV0=} [properties] Properties to set + */ + function GetShieldedEncryptedNotesRequestV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedEncryptedNotesRequestV0 startIndex. + * @member {number|Long} startIndex + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @instance + */ + GetShieldedEncryptedNotesRequestV0.prototype.startIndex = $util.Long ? $util.Long.fromBits(0,0,true) : 0; + + /** + * GetShieldedEncryptedNotesRequestV0 count. + * @member {number} count + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @instance + */ + GetShieldedEncryptedNotesRequestV0.prototype.count = 0; + + /** + * GetShieldedEncryptedNotesRequestV0 prove. + * @member {boolean} prove + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @instance + */ + GetShieldedEncryptedNotesRequestV0.prototype.prove = false; + + /** + * Creates a new GetShieldedEncryptedNotesRequestV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.IGetShieldedEncryptedNotesRequestV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} GetShieldedEncryptedNotesRequestV0 instance + */ + GetShieldedEncryptedNotesRequestV0.create = function create(properties) { + return new GetShieldedEncryptedNotesRequestV0(properties); + }; + + /** + * Encodes the specified GetShieldedEncryptedNotesRequestV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.IGetShieldedEncryptedNotesRequestV0} message GetShieldedEncryptedNotesRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedEncryptedNotesRequestV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.startIndex != null && Object.hasOwnProperty.call(message, "startIndex")) + writer.uint32(/* id 1, wireType 0 =*/8).uint64(message.startIndex); + if (message.count != null && Object.hasOwnProperty.call(message, "count")) + writer.uint32(/* id 2, wireType 0 =*/16).uint32(message.count); + if (message.prove != null && Object.hasOwnProperty.call(message, "prove")) + writer.uint32(/* id 3, wireType 0 =*/24).bool(message.prove); + return writer; + }; + + /** + * Encodes the specified GetShieldedEncryptedNotesRequestV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.IGetShieldedEncryptedNotesRequestV0} message GetShieldedEncryptedNotesRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedEncryptedNotesRequestV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedEncryptedNotesRequestV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} GetShieldedEncryptedNotesRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedEncryptedNotesRequestV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.startIndex = reader.uint64(); + break; + case 2: + message.count = reader.uint32(); + break; + case 3: + message.prove = reader.bool(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedEncryptedNotesRequestV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} GetShieldedEncryptedNotesRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedEncryptedNotesRequestV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedEncryptedNotesRequestV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedEncryptedNotesRequestV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.startIndex != null && message.hasOwnProperty("startIndex")) + if (!$util.isInteger(message.startIndex) && !(message.startIndex && $util.isInteger(message.startIndex.low) && $util.isInteger(message.startIndex.high))) + return "startIndex: integer|Long expected"; + if (message.count != null && message.hasOwnProperty("count")) + if (!$util.isInteger(message.count)) + return "count: integer expected"; + if (message.prove != null && message.hasOwnProperty("prove")) + if (typeof message.prove !== "boolean") + return "prove: boolean expected"; + return null; + }; + + /** + * Creates a GetShieldedEncryptedNotesRequestV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} GetShieldedEncryptedNotesRequestV0 + */ + GetShieldedEncryptedNotesRequestV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0(); + if (object.startIndex != null) + if ($util.Long) + (message.startIndex = $util.Long.fromValue(object.startIndex)).unsigned = true; + else if (typeof object.startIndex === "string") + message.startIndex = parseInt(object.startIndex, 10); + else if (typeof object.startIndex === "number") + message.startIndex = object.startIndex; + else if (typeof object.startIndex === "object") + message.startIndex = new $util.LongBits(object.startIndex.low >>> 0, object.startIndex.high >>> 0).toNumber(true); + if (object.count != null) + message.count = object.count >>> 0; + if (object.prove != null) + message.prove = Boolean(object.prove); + return message; + }; + + /** + * Creates a plain object from a GetShieldedEncryptedNotesRequestV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} message GetShieldedEncryptedNotesRequestV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedEncryptedNotesRequestV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + if ($util.Long) { + var long = new $util.Long(0, 0, true); + object.startIndex = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.startIndex = options.longs === String ? "0" : 0; + object.count = 0; + object.prove = false; + } + if (message.startIndex != null && message.hasOwnProperty("startIndex")) + if (typeof message.startIndex === "number") + object.startIndex = options.longs === String ? String(message.startIndex) : message.startIndex; + else + object.startIndex = options.longs === String ? $util.Long.prototype.toString.call(message.startIndex) : options.longs === Number ? new $util.LongBits(message.startIndex.low >>> 0, message.startIndex.high >>> 0).toNumber(true) : message.startIndex; + if (message.count != null && message.hasOwnProperty("count")) + object.count = message.count; + if (message.prove != null && message.hasOwnProperty("prove")) + object.prove = message.prove; + return object; + }; + + /** + * Converts this GetShieldedEncryptedNotesRequestV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @instance + * @returns {Object.} JSON object + */ + GetShieldedEncryptedNotesRequestV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetShieldedEncryptedNotesRequestV0; + })(); + + return GetShieldedEncryptedNotesRequest; + })(); + + v0.GetShieldedEncryptedNotesResponse = (function() { + + /** + * Properties of a GetShieldedEncryptedNotesResponse. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetShieldedEncryptedNotesResponse + * @property {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.IGetShieldedEncryptedNotesResponseV0|null} [v0] GetShieldedEncryptedNotesResponse v0 + */ + + /** + * Constructs a new GetShieldedEncryptedNotesResponse. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetShieldedEncryptedNotesResponse. + * @implements IGetShieldedEncryptedNotesResponse + * @constructor + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesResponse=} [properties] Properties to set + */ + function GetShieldedEncryptedNotesResponse(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedEncryptedNotesResponse v0. + * @member {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.IGetShieldedEncryptedNotesResponseV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @instance + */ + GetShieldedEncryptedNotesResponse.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedEncryptedNotesResponse version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @instance + */ + Object.defineProperty(GetShieldedEncryptedNotesResponse.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedEncryptedNotesResponse instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesResponse=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} GetShieldedEncryptedNotesResponse instance + */ + GetShieldedEncryptedNotesResponse.create = function create(properties) { + return new GetShieldedEncryptedNotesResponse(properties); + }; + + /** + * Encodes the specified GetShieldedEncryptedNotesResponse message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesResponse} message GetShieldedEncryptedNotesResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedEncryptedNotesResponse.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedEncryptedNotesResponse message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesResponse} message GetShieldedEncryptedNotesResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedEncryptedNotesResponse.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedEncryptedNotesResponse message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} GetShieldedEncryptedNotesResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedEncryptedNotesResponse.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedEncryptedNotesResponse message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} GetShieldedEncryptedNotesResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedEncryptedNotesResponse.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedEncryptedNotesResponse message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedEncryptedNotesResponse.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetShieldedEncryptedNotesResponse message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} GetShieldedEncryptedNotesResponse + */ + GetShieldedEncryptedNotesResponse.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedEncryptedNotesResponse message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} message GetShieldedEncryptedNotesResponse + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedEncryptedNotesResponse.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetShieldedEncryptedNotesResponse to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @instance + * @returns {Object.} JSON object + */ + GetShieldedEncryptedNotesResponse.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 = (function() { + + /** + * Properties of a GetShieldedEncryptedNotesResponseV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @interface IGetShieldedEncryptedNotesResponseV0 + * @property {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNotes|null} [encryptedNotes] GetShieldedEncryptedNotesResponseV0 encryptedNotes + * @property {org.dash.platform.dapi.v0.IProof|null} [proof] GetShieldedEncryptedNotesResponseV0 proof + * @property {org.dash.platform.dapi.v0.IResponseMetadata|null} [metadata] GetShieldedEncryptedNotesResponseV0 metadata + */ + + /** + * Constructs a new GetShieldedEncryptedNotesResponseV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @classdesc Represents a GetShieldedEncryptedNotesResponseV0. + * @implements IGetShieldedEncryptedNotesResponseV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.IGetShieldedEncryptedNotesResponseV0=} [properties] Properties to set + */ + function GetShieldedEncryptedNotesResponseV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedEncryptedNotesResponseV0 encryptedNotes. + * @member {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNotes|null|undefined} encryptedNotes + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @instance + */ + GetShieldedEncryptedNotesResponseV0.prototype.encryptedNotes = null; + + /** + * GetShieldedEncryptedNotesResponseV0 proof. + * @member {org.dash.platform.dapi.v0.IProof|null|undefined} proof + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @instance + */ + GetShieldedEncryptedNotesResponseV0.prototype.proof = null; + + /** + * GetShieldedEncryptedNotesResponseV0 metadata. + * @member {org.dash.platform.dapi.v0.IResponseMetadata|null|undefined} metadata + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @instance + */ + GetShieldedEncryptedNotesResponseV0.prototype.metadata = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedEncryptedNotesResponseV0 result. + * @member {"encryptedNotes"|"proof"|undefined} result + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @instance + */ + Object.defineProperty(GetShieldedEncryptedNotesResponseV0.prototype, "result", { + get: $util.oneOfGetter($oneOfFields = ["encryptedNotes", "proof"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedEncryptedNotesResponseV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.IGetShieldedEncryptedNotesResponseV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} GetShieldedEncryptedNotesResponseV0 instance + */ + GetShieldedEncryptedNotesResponseV0.create = function create(properties) { + return new GetShieldedEncryptedNotesResponseV0(properties); + }; + + /** + * Encodes the specified GetShieldedEncryptedNotesResponseV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.IGetShieldedEncryptedNotesResponseV0} message GetShieldedEncryptedNotesResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedEncryptedNotesResponseV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.encryptedNotes != null && Object.hasOwnProperty.call(message, "encryptedNotes")) + $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.encode(message.encryptedNotes, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + if (message.proof != null && Object.hasOwnProperty.call(message, "proof")) + $root.org.dash.platform.dapi.v0.Proof.encode(message.proof, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + if (message.metadata != null && Object.hasOwnProperty.call(message, "metadata")) + $root.org.dash.platform.dapi.v0.ResponseMetadata.encode(message.metadata, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedEncryptedNotesResponseV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.IGetShieldedEncryptedNotesResponseV0} message GetShieldedEncryptedNotesResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedEncryptedNotesResponseV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedEncryptedNotesResponseV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} GetShieldedEncryptedNotesResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedEncryptedNotesResponseV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.encryptedNotes = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.decode(reader, reader.uint32()); + break; + case 2: + message.proof = $root.org.dash.platform.dapi.v0.Proof.decode(reader, reader.uint32()); + break; + case 3: + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedEncryptedNotesResponseV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} GetShieldedEncryptedNotesResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedEncryptedNotesResponseV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedEncryptedNotesResponseV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedEncryptedNotesResponseV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.encryptedNotes != null && message.hasOwnProperty("encryptedNotes")) { + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.verify(message.encryptedNotes); + if (error) + return "encryptedNotes." + error; + } + } + if (message.proof != null && message.hasOwnProperty("proof")) { + if (properties.result === 1) + return "result: multiple values"; + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.Proof.verify(message.proof); + if (error) + return "proof." + error; + } + } + if (message.metadata != null && message.hasOwnProperty("metadata")) { + var error = $root.org.dash.platform.dapi.v0.ResponseMetadata.verify(message.metadata); + if (error) + return "metadata." + error; + } + return null; + }; + + /** + * Creates a GetShieldedEncryptedNotesResponseV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} GetShieldedEncryptedNotesResponseV0 + */ + GetShieldedEncryptedNotesResponseV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0(); + if (object.encryptedNotes != null) { + if (typeof object.encryptedNotes !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.encryptedNotes: object expected"); + message.encryptedNotes = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.fromObject(object.encryptedNotes); + } + if (object.proof != null) { + if (typeof object.proof !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.proof: object expected"); + message.proof = $root.org.dash.platform.dapi.v0.Proof.fromObject(object.proof); + } + if (object.metadata != null) { + if (typeof object.metadata !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.metadata: object expected"); + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.fromObject(object.metadata); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedEncryptedNotesResponseV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} message GetShieldedEncryptedNotesResponseV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedEncryptedNotesResponseV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.metadata = null; + if (message.encryptedNotes != null && message.hasOwnProperty("encryptedNotes")) { + object.encryptedNotes = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.toObject(message.encryptedNotes, options); + if (options.oneofs) + object.result = "encryptedNotes"; + } + if (message.proof != null && message.hasOwnProperty("proof")) { + object.proof = $root.org.dash.platform.dapi.v0.Proof.toObject(message.proof, options); + if (options.oneofs) + object.result = "proof"; + } + if (message.metadata != null && message.hasOwnProperty("metadata")) + object.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.toObject(message.metadata, options); + return object; + }; + + /** + * Converts this GetShieldedEncryptedNotesResponseV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @instance + * @returns {Object.} JSON object + */ + GetShieldedEncryptedNotesResponseV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedEncryptedNotesResponseV0.EncryptedNote = (function() { + + /** + * Properties of an EncryptedNote. + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @interface IEncryptedNote + * @property {Uint8Array|null} [cmx] EncryptedNote cmx + * @property {Uint8Array|null} [encryptedNote] EncryptedNote encryptedNote + */ + + /** + * Constructs a new EncryptedNote. + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @classdesc Represents an EncryptedNote. + * @implements IEncryptedNote + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNote=} [properties] Properties to set + */ + function EncryptedNote(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * EncryptedNote cmx. + * @member {Uint8Array} cmx + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @instance + */ + EncryptedNote.prototype.cmx = $util.newBuffer([]); + + /** + * EncryptedNote encryptedNote. + * @member {Uint8Array} encryptedNote + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @instance + */ + EncryptedNote.prototype.encryptedNote = $util.newBuffer([]); + + /** + * Creates a new EncryptedNote instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNote=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} EncryptedNote instance + */ + EncryptedNote.create = function create(properties) { + return new EncryptedNote(properties); + }; + + /** + * Encodes the specified EncryptedNote message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNote} message EncryptedNote message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + EncryptedNote.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.cmx != null && Object.hasOwnProperty.call(message, "cmx")) + writer.uint32(/* id 1, wireType 2 =*/10).bytes(message.cmx); + if (message.encryptedNote != null && Object.hasOwnProperty.call(message, "encryptedNote")) + writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.encryptedNote); + return writer; + }; + + /** + * Encodes the specified EncryptedNote message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNote} message EncryptedNote message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + EncryptedNote.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes an EncryptedNote message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} EncryptedNote + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + EncryptedNote.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.cmx = reader.bytes(); + break; + case 2: + message.encryptedNote = reader.bytes(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes an EncryptedNote message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} EncryptedNote + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + EncryptedNote.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies an EncryptedNote message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + EncryptedNote.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.cmx != null && message.hasOwnProperty("cmx")) + if (!(message.cmx && typeof message.cmx.length === "number" || $util.isString(message.cmx))) + return "cmx: buffer expected"; + if (message.encryptedNote != null && message.hasOwnProperty("encryptedNote")) + if (!(message.encryptedNote && typeof message.encryptedNote.length === "number" || $util.isString(message.encryptedNote))) + return "encryptedNote: buffer expected"; + return null; + }; + + /** + * Creates an EncryptedNote message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} EncryptedNote + */ + EncryptedNote.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote(); + if (object.cmx != null) + if (typeof object.cmx === "string") + $util.base64.decode(object.cmx, message.cmx = $util.newBuffer($util.base64.length(object.cmx)), 0); + else if (object.cmx.length >= 0) + message.cmx = object.cmx; + if (object.encryptedNote != null) + if (typeof object.encryptedNote === "string") + $util.base64.decode(object.encryptedNote, message.encryptedNote = $util.newBuffer($util.base64.length(object.encryptedNote)), 0); + else if (object.encryptedNote.length >= 0) + message.encryptedNote = object.encryptedNote; + return message; + }; + + /** + * Creates a plain object from an EncryptedNote message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} message EncryptedNote + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + EncryptedNote.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + if (options.bytes === String) + object.cmx = ""; + else { + object.cmx = []; + if (options.bytes !== Array) + object.cmx = $util.newBuffer(object.cmx); + } + if (options.bytes === String) + object.encryptedNote = ""; + else { + object.encryptedNote = []; + if (options.bytes !== Array) + object.encryptedNote = $util.newBuffer(object.encryptedNote); + } + } + if (message.cmx != null && message.hasOwnProperty("cmx")) + object.cmx = options.bytes === String ? $util.base64.encode(message.cmx, 0, message.cmx.length) : options.bytes === Array ? Array.prototype.slice.call(message.cmx) : message.cmx; + if (message.encryptedNote != null && message.hasOwnProperty("encryptedNote")) + object.encryptedNote = options.bytes === String ? $util.base64.encode(message.encryptedNote, 0, message.encryptedNote.length) : options.bytes === Array ? Array.prototype.slice.call(message.encryptedNote) : message.encryptedNote; + return object; + }; + + /** + * Converts this EncryptedNote to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @instance + * @returns {Object.} JSON object + */ + EncryptedNote.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return EncryptedNote; + })(); + + GetShieldedEncryptedNotesResponseV0.EncryptedNotes = (function() { + + /** + * Properties of an EncryptedNotes. + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @interface IEncryptedNotes + * @property {Array.|null} [entries] EncryptedNotes entries + */ + + /** + * Constructs a new EncryptedNotes. + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @classdesc Represents an EncryptedNotes. + * @implements IEncryptedNotes + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNotes=} [properties] Properties to set + */ + function EncryptedNotes(properties) { + this.entries = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * EncryptedNotes entries. + * @member {Array.} entries + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @instance + */ + EncryptedNotes.prototype.entries = $util.emptyArray; + + /** + * Creates a new EncryptedNotes instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNotes=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} EncryptedNotes instance + */ + EncryptedNotes.create = function create(properties) { + return new EncryptedNotes(properties); + }; + + /** + * Encodes the specified EncryptedNotes message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNotes} message EncryptedNotes message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + EncryptedNotes.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.entries != null && message.entries.length) + for (var i = 0; i < message.entries.length; ++i) + $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.encode(message.entries[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified EncryptedNotes message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNotes} message EncryptedNotes message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + EncryptedNotes.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes an EncryptedNotes message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} EncryptedNotes + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + EncryptedNotes.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (!(message.entries && message.entries.length)) + message.entries = []; + message.entries.push($root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.decode(reader, reader.uint32())); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes an EncryptedNotes message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} EncryptedNotes + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + EncryptedNotes.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies an EncryptedNotes message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + EncryptedNotes.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.entries != null && message.hasOwnProperty("entries")) { + if (!Array.isArray(message.entries)) + return "entries: array expected"; + for (var i = 0; i < message.entries.length; ++i) { + var error = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.verify(message.entries[i]); + if (error) + return "entries." + error; + } + } + return null; + }; + + /** + * Creates an EncryptedNotes message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} EncryptedNotes + */ + EncryptedNotes.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes(); + if (object.entries) { + if (!Array.isArray(object.entries)) + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.entries: array expected"); + message.entries = []; + for (var i = 0; i < object.entries.length; ++i) { + if (typeof object.entries[i] !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.entries: object expected"); + message.entries[i] = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.fromObject(object.entries[i]); + } + } + return message; + }; + + /** + * Creates a plain object from an EncryptedNotes message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} message EncryptedNotes + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + EncryptedNotes.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.entries = []; + if (message.entries && message.entries.length) { + object.entries = []; + for (var j = 0; j < message.entries.length; ++j) + object.entries[j] = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.toObject(message.entries[j], options); + } + return object; + }; + + /** + * Converts this EncryptedNotes to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @instance + * @returns {Object.} JSON object + */ + EncryptedNotes.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return EncryptedNotes; + })(); + + return GetShieldedEncryptedNotesResponseV0; + })(); + + return GetShieldedEncryptedNotesResponse; + })(); + + v0.GetShieldedAnchorsRequest = (function() { + + /** + * Properties of a GetShieldedAnchorsRequest. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetShieldedAnchorsRequest + * @property {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.IGetShieldedAnchorsRequestV0|null} [v0] GetShieldedAnchorsRequest v0 + */ + + /** + * Constructs a new GetShieldedAnchorsRequest. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetShieldedAnchorsRequest. + * @implements IGetShieldedAnchorsRequest + * @constructor + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsRequest=} [properties] Properties to set + */ + function GetShieldedAnchorsRequest(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedAnchorsRequest v0. + * @member {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.IGetShieldedAnchorsRequestV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @instance + */ + GetShieldedAnchorsRequest.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedAnchorsRequest version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @instance + */ + Object.defineProperty(GetShieldedAnchorsRequest.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedAnchorsRequest instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsRequest=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} GetShieldedAnchorsRequest instance + */ + GetShieldedAnchorsRequest.create = function create(properties) { + return new GetShieldedAnchorsRequest(properties); + }; + + /** + * Encodes the specified GetShieldedAnchorsRequest message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsRequest} message GetShieldedAnchorsRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedAnchorsRequest.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedAnchorsRequest message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsRequest} message GetShieldedAnchorsRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedAnchorsRequest.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedAnchorsRequest message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} GetShieldedAnchorsRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedAnchorsRequest.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedAnchorsRequest message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} GetShieldedAnchorsRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedAnchorsRequest.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedAnchorsRequest message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedAnchorsRequest.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetShieldedAnchorsRequest message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} GetShieldedAnchorsRequest + */ + GetShieldedAnchorsRequest.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedAnchorsRequest message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} message GetShieldedAnchorsRequest + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedAnchorsRequest.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetShieldedAnchorsRequest to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @instance + * @returns {Object.} JSON object + */ + GetShieldedAnchorsRequest.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 = (function() { + + /** + * Properties of a GetShieldedAnchorsRequestV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @interface IGetShieldedAnchorsRequestV0 + * @property {boolean|null} [prove] GetShieldedAnchorsRequestV0 prove + */ + + /** + * Constructs a new GetShieldedAnchorsRequestV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @classdesc Represents a GetShieldedAnchorsRequestV0. + * @implements IGetShieldedAnchorsRequestV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.IGetShieldedAnchorsRequestV0=} [properties] Properties to set + */ + function GetShieldedAnchorsRequestV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedAnchorsRequestV0 prove. + * @member {boolean} prove + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @instance + */ + GetShieldedAnchorsRequestV0.prototype.prove = false; + + /** + * Creates a new GetShieldedAnchorsRequestV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.IGetShieldedAnchorsRequestV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} GetShieldedAnchorsRequestV0 instance + */ + GetShieldedAnchorsRequestV0.create = function create(properties) { + return new GetShieldedAnchorsRequestV0(properties); + }; + + /** + * Encodes the specified GetShieldedAnchorsRequestV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.IGetShieldedAnchorsRequestV0} message GetShieldedAnchorsRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedAnchorsRequestV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.prove != null && Object.hasOwnProperty.call(message, "prove")) + writer.uint32(/* id 1, wireType 0 =*/8).bool(message.prove); + return writer; + }; + + /** + * Encodes the specified GetShieldedAnchorsRequestV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.IGetShieldedAnchorsRequestV0} message GetShieldedAnchorsRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedAnchorsRequestV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedAnchorsRequestV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} GetShieldedAnchorsRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedAnchorsRequestV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.prove = reader.bool(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedAnchorsRequestV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} GetShieldedAnchorsRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedAnchorsRequestV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedAnchorsRequestV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedAnchorsRequestV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.prove != null && message.hasOwnProperty("prove")) + if (typeof message.prove !== "boolean") + return "prove: boolean expected"; + return null; + }; + + /** + * Creates a GetShieldedAnchorsRequestV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} GetShieldedAnchorsRequestV0 + */ + GetShieldedAnchorsRequestV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0(); + if (object.prove != null) + message.prove = Boolean(object.prove); + return message; + }; + + /** + * Creates a plain object from a GetShieldedAnchorsRequestV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} message GetShieldedAnchorsRequestV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedAnchorsRequestV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.prove = false; + if (message.prove != null && message.hasOwnProperty("prove")) + object.prove = message.prove; + return object; + }; + + /** + * Converts this GetShieldedAnchorsRequestV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @instance + * @returns {Object.} JSON object + */ + GetShieldedAnchorsRequestV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetShieldedAnchorsRequestV0; + })(); + + return GetShieldedAnchorsRequest; + })(); + + v0.GetShieldedAnchorsResponse = (function() { + + /** + * Properties of a GetShieldedAnchorsResponse. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetShieldedAnchorsResponse + * @property {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.IGetShieldedAnchorsResponseV0|null} [v0] GetShieldedAnchorsResponse v0 + */ + + /** + * Constructs a new GetShieldedAnchorsResponse. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetShieldedAnchorsResponse. + * @implements IGetShieldedAnchorsResponse + * @constructor + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsResponse=} [properties] Properties to set + */ + function GetShieldedAnchorsResponse(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedAnchorsResponse v0. + * @member {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.IGetShieldedAnchorsResponseV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @instance + */ + GetShieldedAnchorsResponse.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedAnchorsResponse version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @instance + */ + Object.defineProperty(GetShieldedAnchorsResponse.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedAnchorsResponse instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsResponse=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} GetShieldedAnchorsResponse instance + */ + GetShieldedAnchorsResponse.create = function create(properties) { + return new GetShieldedAnchorsResponse(properties); + }; + + /** + * Encodes the specified GetShieldedAnchorsResponse message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsResponse} message GetShieldedAnchorsResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedAnchorsResponse.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedAnchorsResponse message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsResponse} message GetShieldedAnchorsResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedAnchorsResponse.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedAnchorsResponse message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} GetShieldedAnchorsResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedAnchorsResponse.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedAnchorsResponse message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} GetShieldedAnchorsResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedAnchorsResponse.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedAnchorsResponse message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedAnchorsResponse.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetShieldedAnchorsResponse message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} GetShieldedAnchorsResponse + */ + GetShieldedAnchorsResponse.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedAnchorsResponse message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} message GetShieldedAnchorsResponse + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedAnchorsResponse.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetShieldedAnchorsResponse to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @instance + * @returns {Object.} JSON object + */ + GetShieldedAnchorsResponse.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 = (function() { + + /** + * Properties of a GetShieldedAnchorsResponseV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @interface IGetShieldedAnchorsResponseV0 + * @property {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.IAnchors|null} [anchors] GetShieldedAnchorsResponseV0 anchors + * @property {org.dash.platform.dapi.v0.IProof|null} [proof] GetShieldedAnchorsResponseV0 proof + * @property {org.dash.platform.dapi.v0.IResponseMetadata|null} [metadata] GetShieldedAnchorsResponseV0 metadata + */ + + /** + * Constructs a new GetShieldedAnchorsResponseV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @classdesc Represents a GetShieldedAnchorsResponseV0. + * @implements IGetShieldedAnchorsResponseV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.IGetShieldedAnchorsResponseV0=} [properties] Properties to set + */ + function GetShieldedAnchorsResponseV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedAnchorsResponseV0 anchors. + * @member {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.IAnchors|null|undefined} anchors + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @instance + */ + GetShieldedAnchorsResponseV0.prototype.anchors = null; + + /** + * GetShieldedAnchorsResponseV0 proof. + * @member {org.dash.platform.dapi.v0.IProof|null|undefined} proof + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @instance + */ + GetShieldedAnchorsResponseV0.prototype.proof = null; + + /** + * GetShieldedAnchorsResponseV0 metadata. + * @member {org.dash.platform.dapi.v0.IResponseMetadata|null|undefined} metadata + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @instance + */ + GetShieldedAnchorsResponseV0.prototype.metadata = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedAnchorsResponseV0 result. + * @member {"anchors"|"proof"|undefined} result + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @instance + */ + Object.defineProperty(GetShieldedAnchorsResponseV0.prototype, "result", { + get: $util.oneOfGetter($oneOfFields = ["anchors", "proof"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedAnchorsResponseV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.IGetShieldedAnchorsResponseV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} GetShieldedAnchorsResponseV0 instance + */ + GetShieldedAnchorsResponseV0.create = function create(properties) { + return new GetShieldedAnchorsResponseV0(properties); + }; + + /** + * Encodes the specified GetShieldedAnchorsResponseV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.IGetShieldedAnchorsResponseV0} message GetShieldedAnchorsResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedAnchorsResponseV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.anchors != null && Object.hasOwnProperty.call(message, "anchors")) + $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.encode(message.anchors, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + if (message.proof != null && Object.hasOwnProperty.call(message, "proof")) + $root.org.dash.platform.dapi.v0.Proof.encode(message.proof, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + if (message.metadata != null && Object.hasOwnProperty.call(message, "metadata")) + $root.org.dash.platform.dapi.v0.ResponseMetadata.encode(message.metadata, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedAnchorsResponseV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.IGetShieldedAnchorsResponseV0} message GetShieldedAnchorsResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedAnchorsResponseV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedAnchorsResponseV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} GetShieldedAnchorsResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedAnchorsResponseV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.anchors = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.decode(reader, reader.uint32()); + break; + case 2: + message.proof = $root.org.dash.platform.dapi.v0.Proof.decode(reader, reader.uint32()); + break; + case 3: + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedAnchorsResponseV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} GetShieldedAnchorsResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedAnchorsResponseV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedAnchorsResponseV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedAnchorsResponseV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.anchors != null && message.hasOwnProperty("anchors")) { + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.verify(message.anchors); + if (error) + return "anchors." + error; + } + } + if (message.proof != null && message.hasOwnProperty("proof")) { + if (properties.result === 1) + return "result: multiple values"; + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.Proof.verify(message.proof); + if (error) + return "proof." + error; + } + } + if (message.metadata != null && message.hasOwnProperty("metadata")) { + var error = $root.org.dash.platform.dapi.v0.ResponseMetadata.verify(message.metadata); + if (error) + return "metadata." + error; + } + return null; + }; + + /** + * Creates a GetShieldedAnchorsResponseV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} GetShieldedAnchorsResponseV0 + */ + GetShieldedAnchorsResponseV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0(); + if (object.anchors != null) { + if (typeof object.anchors !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.anchors: object expected"); + message.anchors = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.fromObject(object.anchors); + } + if (object.proof != null) { + if (typeof object.proof !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.proof: object expected"); + message.proof = $root.org.dash.platform.dapi.v0.Proof.fromObject(object.proof); + } + if (object.metadata != null) { + if (typeof object.metadata !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.metadata: object expected"); + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.fromObject(object.metadata); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedAnchorsResponseV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} message GetShieldedAnchorsResponseV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedAnchorsResponseV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.metadata = null; + if (message.anchors != null && message.hasOwnProperty("anchors")) { + object.anchors = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.toObject(message.anchors, options); + if (options.oneofs) + object.result = "anchors"; + } + if (message.proof != null && message.hasOwnProperty("proof")) { + object.proof = $root.org.dash.platform.dapi.v0.Proof.toObject(message.proof, options); + if (options.oneofs) + object.result = "proof"; + } + if (message.metadata != null && message.hasOwnProperty("metadata")) + object.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.toObject(message.metadata, options); + return object; + }; + + /** + * Converts this GetShieldedAnchorsResponseV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @instance + * @returns {Object.} JSON object + */ + GetShieldedAnchorsResponseV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedAnchorsResponseV0.Anchors = (function() { + + /** + * Properties of an Anchors. + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @interface IAnchors + * @property {Array.|null} [anchors] Anchors anchors + */ + + /** + * Constructs a new Anchors. + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @classdesc Represents an Anchors. + * @implements IAnchors + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.IAnchors=} [properties] Properties to set + */ + function Anchors(properties) { + this.anchors = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * Anchors anchors. + * @member {Array.} anchors + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @instance + */ + Anchors.prototype.anchors = $util.emptyArray; + + /** + * Creates a new Anchors instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.IAnchors=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} Anchors instance + */ + Anchors.create = function create(properties) { + return new Anchors(properties); + }; + + /** + * Encodes the specified Anchors message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.IAnchors} message Anchors message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Anchors.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.anchors != null && message.anchors.length) + for (var i = 0; i < message.anchors.length; ++i) + writer.uint32(/* id 1, wireType 2 =*/10).bytes(message.anchors[i]); + return writer; + }; + + /** + * Encodes the specified Anchors message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.IAnchors} message Anchors message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Anchors.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes an Anchors message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} Anchors + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Anchors.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (!(message.anchors && message.anchors.length)) + message.anchors = []; + message.anchors.push(reader.bytes()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes an Anchors message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} Anchors + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Anchors.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies an Anchors message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Anchors.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.anchors != null && message.hasOwnProperty("anchors")) { + if (!Array.isArray(message.anchors)) + return "anchors: array expected"; + for (var i = 0; i < message.anchors.length; ++i) + if (!(message.anchors[i] && typeof message.anchors[i].length === "number" || $util.isString(message.anchors[i]))) + return "anchors: buffer[] expected"; + } + return null; + }; + + /** + * Creates an Anchors message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} Anchors + */ + Anchors.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors(); + if (object.anchors) { + if (!Array.isArray(object.anchors)) + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.anchors: array expected"); + message.anchors = []; + for (var i = 0; i < object.anchors.length; ++i) + if (typeof object.anchors[i] === "string") + $util.base64.decode(object.anchors[i], message.anchors[i] = $util.newBuffer($util.base64.length(object.anchors[i])), 0); + else if (object.anchors[i].length >= 0) + message.anchors[i] = object.anchors[i]; + } + return message; + }; + + /** + * Creates a plain object from an Anchors message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} message Anchors + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Anchors.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.anchors = []; + if (message.anchors && message.anchors.length) { + object.anchors = []; + for (var j = 0; j < message.anchors.length; ++j) + object.anchors[j] = options.bytes === String ? $util.base64.encode(message.anchors[j], 0, message.anchors[j].length) : options.bytes === Array ? Array.prototype.slice.call(message.anchors[j]) : message.anchors[j]; + } + return object; + }; + + /** + * Converts this Anchors to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @instance + * @returns {Object.} JSON object + */ + Anchors.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return Anchors; + })(); + + return GetShieldedAnchorsResponseV0; + })(); + + return GetShieldedAnchorsResponse; + })(); + + v0.GetShieldedPoolStateRequest = (function() { + + /** + * Properties of a GetShieldedPoolStateRequest. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetShieldedPoolStateRequest + * @property {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.IGetShieldedPoolStateRequestV0|null} [v0] GetShieldedPoolStateRequest v0 + */ + + /** + * Constructs a new GetShieldedPoolStateRequest. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetShieldedPoolStateRequest. + * @implements IGetShieldedPoolStateRequest + * @constructor + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateRequest=} [properties] Properties to set + */ + function GetShieldedPoolStateRequest(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedPoolStateRequest v0. + * @member {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.IGetShieldedPoolStateRequestV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @instance + */ + GetShieldedPoolStateRequest.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedPoolStateRequest version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @instance + */ + Object.defineProperty(GetShieldedPoolStateRequest.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedPoolStateRequest instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateRequest=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} GetShieldedPoolStateRequest instance + */ + GetShieldedPoolStateRequest.create = function create(properties) { + return new GetShieldedPoolStateRequest(properties); + }; + + /** + * Encodes the specified GetShieldedPoolStateRequest message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateRequest} message GetShieldedPoolStateRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedPoolStateRequest.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedPoolStateRequest message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateRequest} message GetShieldedPoolStateRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedPoolStateRequest.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedPoolStateRequest message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} GetShieldedPoolStateRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedPoolStateRequest.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedPoolStateRequest message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} GetShieldedPoolStateRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedPoolStateRequest.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedPoolStateRequest message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedPoolStateRequest.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetShieldedPoolStateRequest message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} GetShieldedPoolStateRequest + */ + GetShieldedPoolStateRequest.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedPoolStateRequest message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} message GetShieldedPoolStateRequest + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedPoolStateRequest.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetShieldedPoolStateRequest to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @instance + * @returns {Object.} JSON object + */ + GetShieldedPoolStateRequest.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 = (function() { + + /** + * Properties of a GetShieldedPoolStateRequestV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @interface IGetShieldedPoolStateRequestV0 + * @property {boolean|null} [prove] GetShieldedPoolStateRequestV0 prove + */ + + /** + * Constructs a new GetShieldedPoolStateRequestV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @classdesc Represents a GetShieldedPoolStateRequestV0. + * @implements IGetShieldedPoolStateRequestV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.IGetShieldedPoolStateRequestV0=} [properties] Properties to set + */ + function GetShieldedPoolStateRequestV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedPoolStateRequestV0 prove. + * @member {boolean} prove + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @instance + */ + GetShieldedPoolStateRequestV0.prototype.prove = false; + + /** + * Creates a new GetShieldedPoolStateRequestV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.IGetShieldedPoolStateRequestV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} GetShieldedPoolStateRequestV0 instance + */ + GetShieldedPoolStateRequestV0.create = function create(properties) { + return new GetShieldedPoolStateRequestV0(properties); + }; + + /** + * Encodes the specified GetShieldedPoolStateRequestV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.IGetShieldedPoolStateRequestV0} message GetShieldedPoolStateRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedPoolStateRequestV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.prove != null && Object.hasOwnProperty.call(message, "prove")) + writer.uint32(/* id 1, wireType 0 =*/8).bool(message.prove); + return writer; + }; + + /** + * Encodes the specified GetShieldedPoolStateRequestV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.IGetShieldedPoolStateRequestV0} message GetShieldedPoolStateRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedPoolStateRequestV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedPoolStateRequestV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} GetShieldedPoolStateRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedPoolStateRequestV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.prove = reader.bool(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedPoolStateRequestV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} GetShieldedPoolStateRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedPoolStateRequestV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedPoolStateRequestV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedPoolStateRequestV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.prove != null && message.hasOwnProperty("prove")) + if (typeof message.prove !== "boolean") + return "prove: boolean expected"; + return null; + }; + + /** + * Creates a GetShieldedPoolStateRequestV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} GetShieldedPoolStateRequestV0 + */ + GetShieldedPoolStateRequestV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0(); + if (object.prove != null) + message.prove = Boolean(object.prove); + return message; + }; + + /** + * Creates a plain object from a GetShieldedPoolStateRequestV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} message GetShieldedPoolStateRequestV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedPoolStateRequestV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.prove = false; + if (message.prove != null && message.hasOwnProperty("prove")) + object.prove = message.prove; + return object; + }; + + /** + * Converts this GetShieldedPoolStateRequestV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @instance + * @returns {Object.} JSON object + */ + GetShieldedPoolStateRequestV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetShieldedPoolStateRequestV0; + })(); + + return GetShieldedPoolStateRequest; + })(); + + v0.GetShieldedPoolStateResponse = (function() { + + /** + * Properties of a GetShieldedPoolStateResponse. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetShieldedPoolStateResponse + * @property {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.IGetShieldedPoolStateResponseV0|null} [v0] GetShieldedPoolStateResponse v0 + */ + + /** + * Constructs a new GetShieldedPoolStateResponse. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetShieldedPoolStateResponse. + * @implements IGetShieldedPoolStateResponse + * @constructor + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateResponse=} [properties] Properties to set + */ + function GetShieldedPoolStateResponse(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedPoolStateResponse v0. + * @member {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.IGetShieldedPoolStateResponseV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @instance + */ + GetShieldedPoolStateResponse.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedPoolStateResponse version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @instance + */ + Object.defineProperty(GetShieldedPoolStateResponse.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedPoolStateResponse instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateResponse=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} GetShieldedPoolStateResponse instance + */ + GetShieldedPoolStateResponse.create = function create(properties) { + return new GetShieldedPoolStateResponse(properties); + }; + + /** + * Encodes the specified GetShieldedPoolStateResponse message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateResponse} message GetShieldedPoolStateResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedPoolStateResponse.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedPoolStateResponse message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateResponse} message GetShieldedPoolStateResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedPoolStateResponse.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedPoolStateResponse message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} GetShieldedPoolStateResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedPoolStateResponse.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedPoolStateResponse message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} GetShieldedPoolStateResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedPoolStateResponse.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedPoolStateResponse message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedPoolStateResponse.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetShieldedPoolStateResponse message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} GetShieldedPoolStateResponse + */ + GetShieldedPoolStateResponse.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedPoolStateResponse message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} message GetShieldedPoolStateResponse + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedPoolStateResponse.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetShieldedPoolStateResponse to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @instance + * @returns {Object.} JSON object + */ + GetShieldedPoolStateResponse.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 = (function() { + + /** + * Properties of a GetShieldedPoolStateResponseV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @interface IGetShieldedPoolStateResponseV0 + * @property {number|Long|null} [totalBalance] GetShieldedPoolStateResponseV0 totalBalance + * @property {org.dash.platform.dapi.v0.IProof|null} [proof] GetShieldedPoolStateResponseV0 proof + * @property {org.dash.platform.dapi.v0.IResponseMetadata|null} [metadata] GetShieldedPoolStateResponseV0 metadata + */ + + /** + * Constructs a new GetShieldedPoolStateResponseV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @classdesc Represents a GetShieldedPoolStateResponseV0. + * @implements IGetShieldedPoolStateResponseV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.IGetShieldedPoolStateResponseV0=} [properties] Properties to set + */ + function GetShieldedPoolStateResponseV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedPoolStateResponseV0 totalBalance. + * @member {number|Long} totalBalance + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @instance + */ + GetShieldedPoolStateResponseV0.prototype.totalBalance = $util.Long ? $util.Long.fromBits(0,0,true) : 0; + + /** + * GetShieldedPoolStateResponseV0 proof. + * @member {org.dash.platform.dapi.v0.IProof|null|undefined} proof + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @instance + */ + GetShieldedPoolStateResponseV0.prototype.proof = null; + + /** + * GetShieldedPoolStateResponseV0 metadata. + * @member {org.dash.platform.dapi.v0.IResponseMetadata|null|undefined} metadata + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @instance + */ + GetShieldedPoolStateResponseV0.prototype.metadata = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedPoolStateResponseV0 result. + * @member {"totalBalance"|"proof"|undefined} result + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @instance + */ + Object.defineProperty(GetShieldedPoolStateResponseV0.prototype, "result", { + get: $util.oneOfGetter($oneOfFields = ["totalBalance", "proof"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedPoolStateResponseV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.IGetShieldedPoolStateResponseV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} GetShieldedPoolStateResponseV0 instance + */ + GetShieldedPoolStateResponseV0.create = function create(properties) { + return new GetShieldedPoolStateResponseV0(properties); + }; + + /** + * Encodes the specified GetShieldedPoolStateResponseV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.IGetShieldedPoolStateResponseV0} message GetShieldedPoolStateResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedPoolStateResponseV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.totalBalance != null && Object.hasOwnProperty.call(message, "totalBalance")) + writer.uint32(/* id 1, wireType 0 =*/8).uint64(message.totalBalance); + if (message.proof != null && Object.hasOwnProperty.call(message, "proof")) + $root.org.dash.platform.dapi.v0.Proof.encode(message.proof, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + if (message.metadata != null && Object.hasOwnProperty.call(message, "metadata")) + $root.org.dash.platform.dapi.v0.ResponseMetadata.encode(message.metadata, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedPoolStateResponseV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.IGetShieldedPoolStateResponseV0} message GetShieldedPoolStateResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedPoolStateResponseV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedPoolStateResponseV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} GetShieldedPoolStateResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedPoolStateResponseV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.totalBalance = reader.uint64(); + break; + case 2: + message.proof = $root.org.dash.platform.dapi.v0.Proof.decode(reader, reader.uint32()); + break; + case 3: + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedPoolStateResponseV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} GetShieldedPoolStateResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedPoolStateResponseV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedPoolStateResponseV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedPoolStateResponseV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.totalBalance != null && message.hasOwnProperty("totalBalance")) { + properties.result = 1; + if (!$util.isInteger(message.totalBalance) && !(message.totalBalance && $util.isInteger(message.totalBalance.low) && $util.isInteger(message.totalBalance.high))) + return "totalBalance: integer|Long expected"; + } + if (message.proof != null && message.hasOwnProperty("proof")) { + if (properties.result === 1) + return "result: multiple values"; + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.Proof.verify(message.proof); + if (error) + return "proof." + error; + } + } + if (message.metadata != null && message.hasOwnProperty("metadata")) { + var error = $root.org.dash.platform.dapi.v0.ResponseMetadata.verify(message.metadata); + if (error) + return "metadata." + error; + } + return null; + }; + + /** + * Creates a GetShieldedPoolStateResponseV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} GetShieldedPoolStateResponseV0 + */ + GetShieldedPoolStateResponseV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0(); + if (object.totalBalance != null) + if ($util.Long) + (message.totalBalance = $util.Long.fromValue(object.totalBalance)).unsigned = true; + else if (typeof object.totalBalance === "string") + message.totalBalance = parseInt(object.totalBalance, 10); + else if (typeof object.totalBalance === "number") + message.totalBalance = object.totalBalance; + else if (typeof object.totalBalance === "object") + message.totalBalance = new $util.LongBits(object.totalBalance.low >>> 0, object.totalBalance.high >>> 0).toNumber(true); + if (object.proof != null) { + if (typeof object.proof !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.proof: object expected"); + message.proof = $root.org.dash.platform.dapi.v0.Proof.fromObject(object.proof); + } + if (object.metadata != null) { + if (typeof object.metadata !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.metadata: object expected"); + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.fromObject(object.metadata); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedPoolStateResponseV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} message GetShieldedPoolStateResponseV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedPoolStateResponseV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.metadata = null; + if (message.totalBalance != null && message.hasOwnProperty("totalBalance")) { + if (typeof message.totalBalance === "number") + object.totalBalance = options.longs === String ? String(message.totalBalance) : message.totalBalance; + else + object.totalBalance = options.longs === String ? $util.Long.prototype.toString.call(message.totalBalance) : options.longs === Number ? new $util.LongBits(message.totalBalance.low >>> 0, message.totalBalance.high >>> 0).toNumber(true) : message.totalBalance; + if (options.oneofs) + object.result = "totalBalance"; + } + if (message.proof != null && message.hasOwnProperty("proof")) { + object.proof = $root.org.dash.platform.dapi.v0.Proof.toObject(message.proof, options); + if (options.oneofs) + object.result = "proof"; + } + if (message.metadata != null && message.hasOwnProperty("metadata")) + object.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.toObject(message.metadata, options); + return object; + }; + + /** + * Converts this GetShieldedPoolStateResponseV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @instance + * @returns {Object.} JSON object + */ + GetShieldedPoolStateResponseV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetShieldedPoolStateResponseV0; + })(); + + return GetShieldedPoolStateResponse; + })(); + + v0.GetShieldedNullifiersRequest = (function() { + + /** + * Properties of a GetShieldedNullifiersRequest. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetShieldedNullifiersRequest + * @property {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.IGetShieldedNullifiersRequestV0|null} [v0] GetShieldedNullifiersRequest v0 + */ + + /** + * Constructs a new GetShieldedNullifiersRequest. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetShieldedNullifiersRequest. + * @implements IGetShieldedNullifiersRequest + * @constructor + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersRequest=} [properties] Properties to set + */ + function GetShieldedNullifiersRequest(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedNullifiersRequest v0. + * @member {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.IGetShieldedNullifiersRequestV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @instance + */ + GetShieldedNullifiersRequest.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedNullifiersRequest version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @instance + */ + Object.defineProperty(GetShieldedNullifiersRequest.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedNullifiersRequest instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersRequest=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} GetShieldedNullifiersRequest instance + */ + GetShieldedNullifiersRequest.create = function create(properties) { + return new GetShieldedNullifiersRequest(properties); + }; + + /** + * Encodes the specified GetShieldedNullifiersRequest message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersRequest} message GetShieldedNullifiersRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedNullifiersRequest.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedNullifiersRequest message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersRequest} message GetShieldedNullifiersRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedNullifiersRequest.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedNullifiersRequest message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} GetShieldedNullifiersRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedNullifiersRequest.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedNullifiersRequest message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} GetShieldedNullifiersRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedNullifiersRequest.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedNullifiersRequest message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedNullifiersRequest.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetShieldedNullifiersRequest message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} GetShieldedNullifiersRequest + */ + GetShieldedNullifiersRequest.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedNullifiersRequest message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} message GetShieldedNullifiersRequest + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedNullifiersRequest.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetShieldedNullifiersRequest to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @instance + * @returns {Object.} JSON object + */ + GetShieldedNullifiersRequest.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 = (function() { + + /** + * Properties of a GetShieldedNullifiersRequestV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @interface IGetShieldedNullifiersRequestV0 + * @property {Array.|null} [nullifiers] GetShieldedNullifiersRequestV0 nullifiers + * @property {boolean|null} [prove] GetShieldedNullifiersRequestV0 prove + */ + + /** + * Constructs a new GetShieldedNullifiersRequestV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @classdesc Represents a GetShieldedNullifiersRequestV0. + * @implements IGetShieldedNullifiersRequestV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.IGetShieldedNullifiersRequestV0=} [properties] Properties to set + */ + function GetShieldedNullifiersRequestV0(properties) { + this.nullifiers = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedNullifiersRequestV0 nullifiers. + * @member {Array.} nullifiers + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @instance + */ + GetShieldedNullifiersRequestV0.prototype.nullifiers = $util.emptyArray; + + /** + * GetShieldedNullifiersRequestV0 prove. + * @member {boolean} prove + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @instance + */ + GetShieldedNullifiersRequestV0.prototype.prove = false; + + /** + * Creates a new GetShieldedNullifiersRequestV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.IGetShieldedNullifiersRequestV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} GetShieldedNullifiersRequestV0 instance + */ + GetShieldedNullifiersRequestV0.create = function create(properties) { + return new GetShieldedNullifiersRequestV0(properties); + }; + + /** + * Encodes the specified GetShieldedNullifiersRequestV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.IGetShieldedNullifiersRequestV0} message GetShieldedNullifiersRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedNullifiersRequestV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.nullifiers != null && message.nullifiers.length) + for (var i = 0; i < message.nullifiers.length; ++i) + writer.uint32(/* id 1, wireType 2 =*/10).bytes(message.nullifiers[i]); + if (message.prove != null && Object.hasOwnProperty.call(message, "prove")) + writer.uint32(/* id 2, wireType 0 =*/16).bool(message.prove); + return writer; + }; + + /** + * Encodes the specified GetShieldedNullifiersRequestV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.IGetShieldedNullifiersRequestV0} message GetShieldedNullifiersRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedNullifiersRequestV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedNullifiersRequestV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} GetShieldedNullifiersRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedNullifiersRequestV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (!(message.nullifiers && message.nullifiers.length)) + message.nullifiers = []; + message.nullifiers.push(reader.bytes()); + break; + case 2: + message.prove = reader.bool(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedNullifiersRequestV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} GetShieldedNullifiersRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedNullifiersRequestV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedNullifiersRequestV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedNullifiersRequestV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.nullifiers != null && message.hasOwnProperty("nullifiers")) { + if (!Array.isArray(message.nullifiers)) + return "nullifiers: array expected"; + for (var i = 0; i < message.nullifiers.length; ++i) + if (!(message.nullifiers[i] && typeof message.nullifiers[i].length === "number" || $util.isString(message.nullifiers[i]))) + return "nullifiers: buffer[] expected"; + } + if (message.prove != null && message.hasOwnProperty("prove")) + if (typeof message.prove !== "boolean") + return "prove: boolean expected"; + return null; + }; + + /** + * Creates a GetShieldedNullifiersRequestV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} GetShieldedNullifiersRequestV0 + */ + GetShieldedNullifiersRequestV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0(); + if (object.nullifiers) { + if (!Array.isArray(object.nullifiers)) + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.nullifiers: array expected"); + message.nullifiers = []; + for (var i = 0; i < object.nullifiers.length; ++i) + if (typeof object.nullifiers[i] === "string") + $util.base64.decode(object.nullifiers[i], message.nullifiers[i] = $util.newBuffer($util.base64.length(object.nullifiers[i])), 0); + else if (object.nullifiers[i].length >= 0) + message.nullifiers[i] = object.nullifiers[i]; + } + if (object.prove != null) + message.prove = Boolean(object.prove); + return message; + }; + + /** + * Creates a plain object from a GetShieldedNullifiersRequestV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} message GetShieldedNullifiersRequestV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedNullifiersRequestV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.nullifiers = []; + if (options.defaults) + object.prove = false; + if (message.nullifiers && message.nullifiers.length) { + object.nullifiers = []; + for (var j = 0; j < message.nullifiers.length; ++j) + object.nullifiers[j] = options.bytes === String ? $util.base64.encode(message.nullifiers[j], 0, message.nullifiers[j].length) : options.bytes === Array ? Array.prototype.slice.call(message.nullifiers[j]) : message.nullifiers[j]; + } + if (message.prove != null && message.hasOwnProperty("prove")) + object.prove = message.prove; + return object; + }; + + /** + * Converts this GetShieldedNullifiersRequestV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @instance + * @returns {Object.} JSON object + */ + GetShieldedNullifiersRequestV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetShieldedNullifiersRequestV0; + })(); + + return GetShieldedNullifiersRequest; + })(); + + v0.GetShieldedNullifiersResponse = (function() { + + /** + * Properties of a GetShieldedNullifiersResponse. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetShieldedNullifiersResponse + * @property {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.IGetShieldedNullifiersResponseV0|null} [v0] GetShieldedNullifiersResponse v0 + */ + + /** + * Constructs a new GetShieldedNullifiersResponse. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetShieldedNullifiersResponse. + * @implements IGetShieldedNullifiersResponse + * @constructor + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersResponse=} [properties] Properties to set + */ + function GetShieldedNullifiersResponse(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedNullifiersResponse v0. + * @member {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.IGetShieldedNullifiersResponseV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @instance + */ + GetShieldedNullifiersResponse.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedNullifiersResponse version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @instance + */ + Object.defineProperty(GetShieldedNullifiersResponse.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedNullifiersResponse instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersResponse=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} GetShieldedNullifiersResponse instance + */ + GetShieldedNullifiersResponse.create = function create(properties) { + return new GetShieldedNullifiersResponse(properties); + }; + + /** + * Encodes the specified GetShieldedNullifiersResponse message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersResponse} message GetShieldedNullifiersResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedNullifiersResponse.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedNullifiersResponse message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersResponse} message GetShieldedNullifiersResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedNullifiersResponse.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedNullifiersResponse message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} GetShieldedNullifiersResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedNullifiersResponse.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedNullifiersResponse message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} GetShieldedNullifiersResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedNullifiersResponse.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedNullifiersResponse message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedNullifiersResponse.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetShieldedNullifiersResponse message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} GetShieldedNullifiersResponse + */ + GetShieldedNullifiersResponse.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedNullifiersResponse message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} message GetShieldedNullifiersResponse + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedNullifiersResponse.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetShieldedNullifiersResponse to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @instance + * @returns {Object.} JSON object + */ + GetShieldedNullifiersResponse.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 = (function() { + + /** + * Properties of a GetShieldedNullifiersResponseV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @interface IGetShieldedNullifiersResponseV0 + * @property {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatuses|null} [nullifierStatuses] GetShieldedNullifiersResponseV0 nullifierStatuses + * @property {org.dash.platform.dapi.v0.IProof|null} [proof] GetShieldedNullifiersResponseV0 proof + * @property {org.dash.platform.dapi.v0.IResponseMetadata|null} [metadata] GetShieldedNullifiersResponseV0 metadata + */ + + /** + * Constructs a new GetShieldedNullifiersResponseV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @classdesc Represents a GetShieldedNullifiersResponseV0. + * @implements IGetShieldedNullifiersResponseV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.IGetShieldedNullifiersResponseV0=} [properties] Properties to set + */ + function GetShieldedNullifiersResponseV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedNullifiersResponseV0 nullifierStatuses. + * @member {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatuses|null|undefined} nullifierStatuses + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @instance + */ + GetShieldedNullifiersResponseV0.prototype.nullifierStatuses = null; + + /** + * GetShieldedNullifiersResponseV0 proof. + * @member {org.dash.platform.dapi.v0.IProof|null|undefined} proof + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @instance + */ + GetShieldedNullifiersResponseV0.prototype.proof = null; + + /** + * GetShieldedNullifiersResponseV0 metadata. + * @member {org.dash.platform.dapi.v0.IResponseMetadata|null|undefined} metadata + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @instance + */ + GetShieldedNullifiersResponseV0.prototype.metadata = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedNullifiersResponseV0 result. + * @member {"nullifierStatuses"|"proof"|undefined} result + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @instance + */ + Object.defineProperty(GetShieldedNullifiersResponseV0.prototype, "result", { + get: $util.oneOfGetter($oneOfFields = ["nullifierStatuses", "proof"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedNullifiersResponseV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.IGetShieldedNullifiersResponseV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} GetShieldedNullifiersResponseV0 instance + */ + GetShieldedNullifiersResponseV0.create = function create(properties) { + return new GetShieldedNullifiersResponseV0(properties); + }; + + /** + * Encodes the specified GetShieldedNullifiersResponseV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.IGetShieldedNullifiersResponseV0} message GetShieldedNullifiersResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedNullifiersResponseV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.nullifierStatuses != null && Object.hasOwnProperty.call(message, "nullifierStatuses")) + $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.encode(message.nullifierStatuses, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + if (message.proof != null && Object.hasOwnProperty.call(message, "proof")) + $root.org.dash.platform.dapi.v0.Proof.encode(message.proof, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + if (message.metadata != null && Object.hasOwnProperty.call(message, "metadata")) + $root.org.dash.platform.dapi.v0.ResponseMetadata.encode(message.metadata, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedNullifiersResponseV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.IGetShieldedNullifiersResponseV0} message GetShieldedNullifiersResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedNullifiersResponseV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedNullifiersResponseV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} GetShieldedNullifiersResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedNullifiersResponseV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.nullifierStatuses = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.decode(reader, reader.uint32()); + break; + case 2: + message.proof = $root.org.dash.platform.dapi.v0.Proof.decode(reader, reader.uint32()); + break; + case 3: + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedNullifiersResponseV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} GetShieldedNullifiersResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedNullifiersResponseV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedNullifiersResponseV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedNullifiersResponseV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.nullifierStatuses != null && message.hasOwnProperty("nullifierStatuses")) { + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.verify(message.nullifierStatuses); + if (error) + return "nullifierStatuses." + error; + } + } + if (message.proof != null && message.hasOwnProperty("proof")) { + if (properties.result === 1) + return "result: multiple values"; + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.Proof.verify(message.proof); + if (error) + return "proof." + error; + } + } + if (message.metadata != null && message.hasOwnProperty("metadata")) { + var error = $root.org.dash.platform.dapi.v0.ResponseMetadata.verify(message.metadata); + if (error) + return "metadata." + error; + } + return null; + }; + + /** + * Creates a GetShieldedNullifiersResponseV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} GetShieldedNullifiersResponseV0 + */ + GetShieldedNullifiersResponseV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0(); + if (object.nullifierStatuses != null) { + if (typeof object.nullifierStatuses !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.nullifierStatuses: object expected"); + message.nullifierStatuses = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.fromObject(object.nullifierStatuses); + } + if (object.proof != null) { + if (typeof object.proof !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.proof: object expected"); + message.proof = $root.org.dash.platform.dapi.v0.Proof.fromObject(object.proof); + } + if (object.metadata != null) { + if (typeof object.metadata !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.metadata: object expected"); + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.fromObject(object.metadata); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedNullifiersResponseV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} message GetShieldedNullifiersResponseV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedNullifiersResponseV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.metadata = null; + if (message.nullifierStatuses != null && message.hasOwnProperty("nullifierStatuses")) { + object.nullifierStatuses = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.toObject(message.nullifierStatuses, options); + if (options.oneofs) + object.result = "nullifierStatuses"; + } + if (message.proof != null && message.hasOwnProperty("proof")) { + object.proof = $root.org.dash.platform.dapi.v0.Proof.toObject(message.proof, options); + if (options.oneofs) + object.result = "proof"; + } + if (message.metadata != null && message.hasOwnProperty("metadata")) + object.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.toObject(message.metadata, options); + return object; + }; + + /** + * Converts this GetShieldedNullifiersResponseV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @instance + * @returns {Object.} JSON object + */ + GetShieldedNullifiersResponseV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedNullifiersResponseV0.NullifierStatus = (function() { + + /** + * Properties of a NullifierStatus. + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @interface INullifierStatus + * @property {Uint8Array|null} [nullifier] NullifierStatus nullifier + * @property {boolean|null} [isSpent] NullifierStatus isSpent + */ + + /** + * Constructs a new NullifierStatus. + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @classdesc Represents a NullifierStatus. + * @implements INullifierStatus + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatus=} [properties] Properties to set + */ + function NullifierStatus(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * NullifierStatus nullifier. + * @member {Uint8Array} nullifier + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @instance + */ + NullifierStatus.prototype.nullifier = $util.newBuffer([]); + + /** + * NullifierStatus isSpent. + * @member {boolean} isSpent + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @instance + */ + NullifierStatus.prototype.isSpent = false; + + /** + * Creates a new NullifierStatus instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatus=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} NullifierStatus instance + */ + NullifierStatus.create = function create(properties) { + return new NullifierStatus(properties); + }; + + /** + * Encodes the specified NullifierStatus message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatus} message NullifierStatus message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + NullifierStatus.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.nullifier != null && Object.hasOwnProperty.call(message, "nullifier")) + writer.uint32(/* id 1, wireType 2 =*/10).bytes(message.nullifier); + if (message.isSpent != null && Object.hasOwnProperty.call(message, "isSpent")) + writer.uint32(/* id 2, wireType 0 =*/16).bool(message.isSpent); + return writer; + }; + + /** + * Encodes the specified NullifierStatus message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatus} message NullifierStatus message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + NullifierStatus.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a NullifierStatus message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} NullifierStatus + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + NullifierStatus.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.nullifier = reader.bytes(); + break; + case 2: + message.isSpent = reader.bool(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a NullifierStatus message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} NullifierStatus + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + NullifierStatus.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a NullifierStatus message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + NullifierStatus.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.nullifier != null && message.hasOwnProperty("nullifier")) + if (!(message.nullifier && typeof message.nullifier.length === "number" || $util.isString(message.nullifier))) + return "nullifier: buffer expected"; + if (message.isSpent != null && message.hasOwnProperty("isSpent")) + if (typeof message.isSpent !== "boolean") + return "isSpent: boolean expected"; + return null; + }; + + /** + * Creates a NullifierStatus message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} NullifierStatus + */ + NullifierStatus.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus(); + if (object.nullifier != null) + if (typeof object.nullifier === "string") + $util.base64.decode(object.nullifier, message.nullifier = $util.newBuffer($util.base64.length(object.nullifier)), 0); + else if (object.nullifier.length >= 0) + message.nullifier = object.nullifier; + if (object.isSpent != null) + message.isSpent = Boolean(object.isSpent); + return message; + }; + + /** + * Creates a plain object from a NullifierStatus message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} message NullifierStatus + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + NullifierStatus.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + if (options.bytes === String) + object.nullifier = ""; + else { + object.nullifier = []; + if (options.bytes !== Array) + object.nullifier = $util.newBuffer(object.nullifier); + } + object.isSpent = false; + } + if (message.nullifier != null && message.hasOwnProperty("nullifier")) + object.nullifier = options.bytes === String ? $util.base64.encode(message.nullifier, 0, message.nullifier.length) : options.bytes === Array ? Array.prototype.slice.call(message.nullifier) : message.nullifier; + if (message.isSpent != null && message.hasOwnProperty("isSpent")) + object.isSpent = message.isSpent; + return object; + }; + + /** + * Converts this NullifierStatus to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @instance + * @returns {Object.} JSON object + */ + NullifierStatus.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return NullifierStatus; + })(); + + GetShieldedNullifiersResponseV0.NullifierStatuses = (function() { + + /** + * Properties of a NullifierStatuses. + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @interface INullifierStatuses + * @property {Array.|null} [entries] NullifierStatuses entries + */ + + /** + * Constructs a new NullifierStatuses. + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @classdesc Represents a NullifierStatuses. + * @implements INullifierStatuses + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatuses=} [properties] Properties to set + */ + function NullifierStatuses(properties) { + this.entries = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * NullifierStatuses entries. + * @member {Array.} entries + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @instance + */ + NullifierStatuses.prototype.entries = $util.emptyArray; + + /** + * Creates a new NullifierStatuses instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatuses=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} NullifierStatuses instance + */ + NullifierStatuses.create = function create(properties) { + return new NullifierStatuses(properties); + }; + + /** + * Encodes the specified NullifierStatuses message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatuses} message NullifierStatuses message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + NullifierStatuses.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.entries != null && message.entries.length) + for (var i = 0; i < message.entries.length; ++i) + $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.encode(message.entries[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified NullifierStatuses message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatuses} message NullifierStatuses message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + NullifierStatuses.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a NullifierStatuses message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} NullifierStatuses + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + NullifierStatuses.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (!(message.entries && message.entries.length)) + message.entries = []; + message.entries.push($root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.decode(reader, reader.uint32())); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a NullifierStatuses message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} NullifierStatuses + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + NullifierStatuses.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a NullifierStatuses message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + NullifierStatuses.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.entries != null && message.hasOwnProperty("entries")) { + if (!Array.isArray(message.entries)) + return "entries: array expected"; + for (var i = 0; i < message.entries.length; ++i) { + var error = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.verify(message.entries[i]); + if (error) + return "entries." + error; + } + } + return null; + }; + + /** + * Creates a NullifierStatuses message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} NullifierStatuses + */ + NullifierStatuses.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses(); + if (object.entries) { + if (!Array.isArray(object.entries)) + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.entries: array expected"); + message.entries = []; + for (var i = 0; i < object.entries.length; ++i) { + if (typeof object.entries[i] !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.entries: object expected"); + message.entries[i] = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.fromObject(object.entries[i]); + } + } + return message; + }; + + /** + * Creates a plain object from a NullifierStatuses message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} message NullifierStatuses + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + NullifierStatuses.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.entries = []; + if (message.entries && message.entries.length) { + object.entries = []; + for (var j = 0; j < message.entries.length; ++j) + object.entries[j] = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.toObject(message.entries[j], options); + } + return object; + }; + + /** + * Converts this NullifierStatuses to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @instance + * @returns {Object.} JSON object + */ + NullifierStatuses.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return NullifierStatuses; + })(); + + return GetShieldedNullifiersResponseV0; + })(); + + return GetShieldedNullifiersResponse; + })(); + return v0; })(); diff --git a/packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java b/packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java index b7cb841f8e0..5edefc94451 100644 --- a/packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java +++ b/packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java @@ -1658,6 +1658,130 @@ org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentCompactedAddressBalanceCha return getGetRecentCompactedAddressBalanceChangesMethod; } + private static volatile io.grpc.MethodDescriptor getGetShieldedEncryptedNotesMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "getShieldedEncryptedNotes", + requestType = org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedEncryptedNotesRequest.class, + responseType = org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedEncryptedNotesResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getGetShieldedEncryptedNotesMethod() { + io.grpc.MethodDescriptor getGetShieldedEncryptedNotesMethod; + if ((getGetShieldedEncryptedNotesMethod = PlatformGrpc.getGetShieldedEncryptedNotesMethod) == null) { + synchronized (PlatformGrpc.class) { + if ((getGetShieldedEncryptedNotesMethod = PlatformGrpc.getGetShieldedEncryptedNotesMethod) == null) { + PlatformGrpc.getGetShieldedEncryptedNotesMethod = getGetShieldedEncryptedNotesMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "getShieldedEncryptedNotes")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedEncryptedNotesRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedEncryptedNotesResponse.getDefaultInstance())) + .setSchemaDescriptor(new PlatformMethodDescriptorSupplier("getShieldedEncryptedNotes")) + .build(); + } + } + } + return getGetShieldedEncryptedNotesMethod; + } + + private static volatile io.grpc.MethodDescriptor getGetShieldedAnchorsMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "getShieldedAnchors", + requestType = org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedAnchorsRequest.class, + responseType = org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedAnchorsResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getGetShieldedAnchorsMethod() { + io.grpc.MethodDescriptor getGetShieldedAnchorsMethod; + if ((getGetShieldedAnchorsMethod = PlatformGrpc.getGetShieldedAnchorsMethod) == null) { + synchronized (PlatformGrpc.class) { + if ((getGetShieldedAnchorsMethod = PlatformGrpc.getGetShieldedAnchorsMethod) == null) { + PlatformGrpc.getGetShieldedAnchorsMethod = getGetShieldedAnchorsMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "getShieldedAnchors")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedAnchorsRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedAnchorsResponse.getDefaultInstance())) + .setSchemaDescriptor(new PlatformMethodDescriptorSupplier("getShieldedAnchors")) + .build(); + } + } + } + return getGetShieldedAnchorsMethod; + } + + private static volatile io.grpc.MethodDescriptor getGetShieldedPoolStateMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "getShieldedPoolState", + requestType = org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedPoolStateRequest.class, + responseType = org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedPoolStateResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getGetShieldedPoolStateMethod() { + io.grpc.MethodDescriptor getGetShieldedPoolStateMethod; + if ((getGetShieldedPoolStateMethod = PlatformGrpc.getGetShieldedPoolStateMethod) == null) { + synchronized (PlatformGrpc.class) { + if ((getGetShieldedPoolStateMethod = PlatformGrpc.getGetShieldedPoolStateMethod) == null) { + PlatformGrpc.getGetShieldedPoolStateMethod = getGetShieldedPoolStateMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "getShieldedPoolState")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedPoolStateRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedPoolStateResponse.getDefaultInstance())) + .setSchemaDescriptor(new PlatformMethodDescriptorSupplier("getShieldedPoolState")) + .build(); + } + } + } + return getGetShieldedPoolStateMethod; + } + + private static volatile io.grpc.MethodDescriptor getGetShieldedNullifiersMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "getShieldedNullifiers", + requestType = org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedNullifiersRequest.class, + responseType = org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedNullifiersResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getGetShieldedNullifiersMethod() { + io.grpc.MethodDescriptor getGetShieldedNullifiersMethod; + if ((getGetShieldedNullifiersMethod = PlatformGrpc.getGetShieldedNullifiersMethod) == null) { + synchronized (PlatformGrpc.class) { + if ((getGetShieldedNullifiersMethod = PlatformGrpc.getGetShieldedNullifiersMethod) == null) { + PlatformGrpc.getGetShieldedNullifiersMethod = getGetShieldedNullifiersMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "getShieldedNullifiers")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedNullifiersRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedNullifiersResponse.getDefaultInstance())) + .setSchemaDescriptor(new PlatformMethodDescriptorSupplier("getShieldedNullifiers")) + .build(); + } + } + } + return getGetShieldedNullifiersMethod; + } + /** * Creates a new async stub that supports all call types for the service */ @@ -2092,6 +2216,34 @@ public void getRecentCompactedAddressBalanceChanges(org.dash.platform.dapi.v0.Pl io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetRecentCompactedAddressBalanceChangesMethod(), responseObserver); } + /** + */ + public void getShieldedEncryptedNotes(org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedEncryptedNotesRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetShieldedEncryptedNotesMethod(), responseObserver); + } + + /** + */ + public void getShieldedAnchors(org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedAnchorsRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetShieldedAnchorsMethod(), responseObserver); + } + + /** + */ + public void getShieldedPoolState(org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedPoolStateRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetShieldedPoolStateMethod(), responseObserver); + } + + /** + */ + public void getShieldedNullifiers(org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedNullifiersRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetShieldedNullifiersMethod(), responseObserver); + } + @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() { return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) .addMethod( @@ -2465,6 +2617,34 @@ public void getRecentCompactedAddressBalanceChanges(org.dash.platform.dapi.v0.Pl org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentCompactedAddressBalanceChangesRequest, org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentCompactedAddressBalanceChangesResponse>( this, METHODID_GET_RECENT_COMPACTED_ADDRESS_BALANCE_CHANGES))) + .addMethod( + getGetShieldedEncryptedNotesMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedEncryptedNotesRequest, + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedEncryptedNotesResponse>( + this, METHODID_GET_SHIELDED_ENCRYPTED_NOTES))) + .addMethod( + getGetShieldedAnchorsMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedAnchorsRequest, + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedAnchorsResponse>( + this, METHODID_GET_SHIELDED_ANCHORS))) + .addMethod( + getGetShieldedPoolStateMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedPoolStateRequest, + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedPoolStateResponse>( + this, METHODID_GET_SHIELDED_POOL_STATE))) + .addMethod( + getGetShieldedNullifiersMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedNullifiersRequest, + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedNullifiersResponse>( + this, METHODID_GET_SHIELDED_NULLIFIERS))) .build(); } } @@ -2921,6 +3101,38 @@ public void getRecentCompactedAddressBalanceChanges(org.dash.platform.dapi.v0.Pl io.grpc.stub.ClientCalls.asyncUnaryCall( getChannel().newCall(getGetRecentCompactedAddressBalanceChangesMethod(), getCallOptions()), request, responseObserver); } + + /** + */ + public void getShieldedEncryptedNotes(org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedEncryptedNotesRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getGetShieldedEncryptedNotesMethod(), getCallOptions()), request, responseObserver); + } + + /** + */ + public void getShieldedAnchors(org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedAnchorsRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getGetShieldedAnchorsMethod(), getCallOptions()), request, responseObserver); + } + + /** + */ + public void getShieldedPoolState(org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedPoolStateRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getGetShieldedPoolStateMethod(), getCallOptions()), request, responseObserver); + } + + /** + */ + public void getShieldedNullifiers(org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedNullifiersRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getGetShieldedNullifiersMethod(), getCallOptions()), request, responseObserver); + } } /** @@ -3322,6 +3534,34 @@ public org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentCompactedAddressBal return io.grpc.stub.ClientCalls.blockingUnaryCall( getChannel(), getGetRecentCompactedAddressBalanceChangesMethod(), getCallOptions(), request); } + + /** + */ + public org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedEncryptedNotesResponse getShieldedEncryptedNotes(org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedEncryptedNotesRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getGetShieldedEncryptedNotesMethod(), getCallOptions(), request); + } + + /** + */ + public org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedAnchorsResponse getShieldedAnchors(org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedAnchorsRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getGetShieldedAnchorsMethod(), getCallOptions(), request); + } + + /** + */ + public org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedPoolStateResponse getShieldedPoolState(org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedPoolStateRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getGetShieldedPoolStateMethod(), getCallOptions(), request); + } + + /** + */ + public org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedNullifiersResponse getShieldedNullifiers(org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedNullifiersRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getGetShieldedNullifiersMethod(), getCallOptions(), request); + } } /** @@ -3776,6 +4016,38 @@ public com.google.common.util.concurrent.ListenableFuture getShieldedEncryptedNotes( + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedEncryptedNotesRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getGetShieldedEncryptedNotesMethod(), getCallOptions()), request); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture getShieldedAnchors( + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedAnchorsRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getGetShieldedAnchorsMethod(), getCallOptions()), request); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture getShieldedPoolState( + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedPoolStateRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getGetShieldedPoolStateMethod(), getCallOptions()), request); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture getShieldedNullifiers( + org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedNullifiersRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getGetShieldedNullifiersMethod(), getCallOptions()), request); + } } private static final int METHODID_BROADCAST_STATE_TRANSITION = 0; @@ -3831,6 +4103,10 @@ public com.google.common.util.concurrent.ListenableFuture implements io.grpc.stub.ServerCalls.UnaryMethod, @@ -4061,6 +4337,22 @@ public void invoke(Req request, io.grpc.stub.StreamObserver responseObserv serviceImpl.getRecentCompactedAddressBalanceChanges((org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentCompactedAddressBalanceChangesRequest) request, (io.grpc.stub.StreamObserver) responseObserver); break; + case METHODID_GET_SHIELDED_ENCRYPTED_NOTES: + serviceImpl.getShieldedEncryptedNotes((org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedEncryptedNotesRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_GET_SHIELDED_ANCHORS: + serviceImpl.getShieldedAnchors((org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedAnchorsRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_GET_SHIELDED_POOL_STATE: + serviceImpl.getShieldedPoolState((org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedPoolStateRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_GET_SHIELDED_NULLIFIERS: + serviceImpl.getShieldedNullifiers((org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedNullifiersRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; default: throw new AssertionError(); } @@ -4175,6 +4467,10 @@ public static io.grpc.ServiceDescriptor getServiceDescriptor() { .addMethod(getGetAddressesBranchStateMethod()) .addMethod(getGetRecentAddressBalanceChangesMethod()) .addMethod(getGetRecentCompactedAddressBalanceChangesMethod()) + .addMethod(getGetShieldedEncryptedNotesMethod()) + .addMethod(getGetShieldedAnchorsMethod()) + .addMethod(getGetShieldedPoolStateMethod()) + .addMethod(getGetShieldedNullifiersMethod()) .build(); } } diff --git a/packages/dapi-grpc/clients/platform/v0/nodejs/platform_pbjs.js b/packages/dapi-grpc/clients/platform/v0/nodejs/platform_pbjs.js index 750c3b2fbd0..58b3dab7793 100644 --- a/packages/dapi-grpc/clients/platform/v0/nodejs/platform_pbjs.js +++ b/packages/dapi-grpc/clients/platform/v0/nodejs/platform_pbjs.js @@ -1835,6 +1835,138 @@ $root.org = (function() { * @variation 2 */ + /** + * Callback as used by {@link org.dash.platform.dapi.v0.Platform#getShieldedEncryptedNotes}. + * @memberof org.dash.platform.dapi.v0.Platform + * @typedef getShieldedEncryptedNotesCallback + * @type {function} + * @param {Error|null} error Error, if any + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} [response] GetShieldedEncryptedNotesResponse + */ + + /** + * Calls getShieldedEncryptedNotes. + * @function getShieldedEncryptedNotes + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesRequest} request GetShieldedEncryptedNotesRequest message or plain object + * @param {org.dash.platform.dapi.v0.Platform.getShieldedEncryptedNotesCallback} callback Node-style callback called with the error, if any, and GetShieldedEncryptedNotesResponse + * @returns {undefined} + * @variation 1 + */ + Object.defineProperty(Platform.prototype.getShieldedEncryptedNotes = function getShieldedEncryptedNotes(request, callback) { + return this.rpcCall(getShieldedEncryptedNotes, $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest, $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse, request, callback); + }, "name", { value: "getShieldedEncryptedNotes" }); + + /** + * Calls getShieldedEncryptedNotes. + * @function getShieldedEncryptedNotes + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesRequest} request GetShieldedEncryptedNotesRequest message or plain object + * @returns {Promise} Promise + * @variation 2 + */ + + /** + * Callback as used by {@link org.dash.platform.dapi.v0.Platform#getShieldedAnchors}. + * @memberof org.dash.platform.dapi.v0.Platform + * @typedef getShieldedAnchorsCallback + * @type {function} + * @param {Error|null} error Error, if any + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} [response] GetShieldedAnchorsResponse + */ + + /** + * Calls getShieldedAnchors. + * @function getShieldedAnchors + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsRequest} request GetShieldedAnchorsRequest message or plain object + * @param {org.dash.platform.dapi.v0.Platform.getShieldedAnchorsCallback} callback Node-style callback called with the error, if any, and GetShieldedAnchorsResponse + * @returns {undefined} + * @variation 1 + */ + Object.defineProperty(Platform.prototype.getShieldedAnchors = function getShieldedAnchors(request, callback) { + return this.rpcCall(getShieldedAnchors, $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest, $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse, request, callback); + }, "name", { value: "getShieldedAnchors" }); + + /** + * Calls getShieldedAnchors. + * @function getShieldedAnchors + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsRequest} request GetShieldedAnchorsRequest message or plain object + * @returns {Promise} Promise + * @variation 2 + */ + + /** + * Callback as used by {@link org.dash.platform.dapi.v0.Platform#getShieldedPoolState}. + * @memberof org.dash.platform.dapi.v0.Platform + * @typedef getShieldedPoolStateCallback + * @type {function} + * @param {Error|null} error Error, if any + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} [response] GetShieldedPoolStateResponse + */ + + /** + * Calls getShieldedPoolState. + * @function getShieldedPoolState + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateRequest} request GetShieldedPoolStateRequest message or plain object + * @param {org.dash.platform.dapi.v0.Platform.getShieldedPoolStateCallback} callback Node-style callback called with the error, if any, and GetShieldedPoolStateResponse + * @returns {undefined} + * @variation 1 + */ + Object.defineProperty(Platform.prototype.getShieldedPoolState = function getShieldedPoolState(request, callback) { + return this.rpcCall(getShieldedPoolState, $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest, $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse, request, callback); + }, "name", { value: "getShieldedPoolState" }); + + /** + * Calls getShieldedPoolState. + * @function getShieldedPoolState + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateRequest} request GetShieldedPoolStateRequest message or plain object + * @returns {Promise} Promise + * @variation 2 + */ + + /** + * Callback as used by {@link org.dash.platform.dapi.v0.Platform#getShieldedNullifiers}. + * @memberof org.dash.platform.dapi.v0.Platform + * @typedef getShieldedNullifiersCallback + * @type {function} + * @param {Error|null} error Error, if any + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} [response] GetShieldedNullifiersResponse + */ + + /** + * Calls getShieldedNullifiers. + * @function getShieldedNullifiers + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersRequest} request GetShieldedNullifiersRequest message or plain object + * @param {org.dash.platform.dapi.v0.Platform.getShieldedNullifiersCallback} callback Node-style callback called with the error, if any, and GetShieldedNullifiersResponse + * @returns {undefined} + * @variation 1 + */ + Object.defineProperty(Platform.prototype.getShieldedNullifiers = function getShieldedNullifiers(request, callback) { + return this.rpcCall(getShieldedNullifiers, $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest, $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse, request, callback); + }, "name", { value: "getShieldedNullifiers" }); + + /** + * Calls getShieldedNullifiers. + * @function getShieldedNullifiers + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersRequest} request GetShieldedNullifiersRequest message or plain object + * @returns {Promise} Promise + * @variation 2 + */ + return Platform; })(); @@ -82134,6 +82266,4708 @@ $root.org = (function() { return GetRecentCompactedAddressBalanceChangesResponse; })(); + v0.GetShieldedEncryptedNotesRequest = (function() { + + /** + * Properties of a GetShieldedEncryptedNotesRequest. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetShieldedEncryptedNotesRequest + * @property {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.IGetShieldedEncryptedNotesRequestV0|null} [v0] GetShieldedEncryptedNotesRequest v0 + */ + + /** + * Constructs a new GetShieldedEncryptedNotesRequest. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetShieldedEncryptedNotesRequest. + * @implements IGetShieldedEncryptedNotesRequest + * @constructor + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesRequest=} [properties] Properties to set + */ + function GetShieldedEncryptedNotesRequest(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedEncryptedNotesRequest v0. + * @member {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.IGetShieldedEncryptedNotesRequestV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @instance + */ + GetShieldedEncryptedNotesRequest.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedEncryptedNotesRequest version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @instance + */ + Object.defineProperty(GetShieldedEncryptedNotesRequest.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedEncryptedNotesRequest instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesRequest=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} GetShieldedEncryptedNotesRequest instance + */ + GetShieldedEncryptedNotesRequest.create = function create(properties) { + return new GetShieldedEncryptedNotesRequest(properties); + }; + + /** + * Encodes the specified GetShieldedEncryptedNotesRequest message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesRequest} message GetShieldedEncryptedNotesRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedEncryptedNotesRequest.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedEncryptedNotesRequest message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesRequest} message GetShieldedEncryptedNotesRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedEncryptedNotesRequest.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedEncryptedNotesRequest message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} GetShieldedEncryptedNotesRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedEncryptedNotesRequest.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedEncryptedNotesRequest message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} GetShieldedEncryptedNotesRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedEncryptedNotesRequest.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedEncryptedNotesRequest message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedEncryptedNotesRequest.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetShieldedEncryptedNotesRequest message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} GetShieldedEncryptedNotesRequest + */ + GetShieldedEncryptedNotesRequest.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedEncryptedNotesRequest message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} message GetShieldedEncryptedNotesRequest + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedEncryptedNotesRequest.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetShieldedEncryptedNotesRequest to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @instance + * @returns {Object.} JSON object + */ + GetShieldedEncryptedNotesRequest.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 = (function() { + + /** + * Properties of a GetShieldedEncryptedNotesRequestV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @interface IGetShieldedEncryptedNotesRequestV0 + * @property {number|Long|null} [startIndex] GetShieldedEncryptedNotesRequestV0 startIndex + * @property {number|null} [count] GetShieldedEncryptedNotesRequestV0 count + * @property {boolean|null} [prove] GetShieldedEncryptedNotesRequestV0 prove + */ + + /** + * Constructs a new GetShieldedEncryptedNotesRequestV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest + * @classdesc Represents a GetShieldedEncryptedNotesRequestV0. + * @implements IGetShieldedEncryptedNotesRequestV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.IGetShieldedEncryptedNotesRequestV0=} [properties] Properties to set + */ + function GetShieldedEncryptedNotesRequestV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedEncryptedNotesRequestV0 startIndex. + * @member {number|Long} startIndex + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @instance + */ + GetShieldedEncryptedNotesRequestV0.prototype.startIndex = $util.Long ? $util.Long.fromBits(0,0,true) : 0; + + /** + * GetShieldedEncryptedNotesRequestV0 count. + * @member {number} count + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @instance + */ + GetShieldedEncryptedNotesRequestV0.prototype.count = 0; + + /** + * GetShieldedEncryptedNotesRequestV0 prove. + * @member {boolean} prove + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @instance + */ + GetShieldedEncryptedNotesRequestV0.prototype.prove = false; + + /** + * Creates a new GetShieldedEncryptedNotesRequestV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.IGetShieldedEncryptedNotesRequestV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} GetShieldedEncryptedNotesRequestV0 instance + */ + GetShieldedEncryptedNotesRequestV0.create = function create(properties) { + return new GetShieldedEncryptedNotesRequestV0(properties); + }; + + /** + * Encodes the specified GetShieldedEncryptedNotesRequestV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.IGetShieldedEncryptedNotesRequestV0} message GetShieldedEncryptedNotesRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedEncryptedNotesRequestV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.startIndex != null && Object.hasOwnProperty.call(message, "startIndex")) + writer.uint32(/* id 1, wireType 0 =*/8).uint64(message.startIndex); + if (message.count != null && Object.hasOwnProperty.call(message, "count")) + writer.uint32(/* id 2, wireType 0 =*/16).uint32(message.count); + if (message.prove != null && Object.hasOwnProperty.call(message, "prove")) + writer.uint32(/* id 3, wireType 0 =*/24).bool(message.prove); + return writer; + }; + + /** + * Encodes the specified GetShieldedEncryptedNotesRequestV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.IGetShieldedEncryptedNotesRequestV0} message GetShieldedEncryptedNotesRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedEncryptedNotesRequestV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedEncryptedNotesRequestV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} GetShieldedEncryptedNotesRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedEncryptedNotesRequestV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.startIndex = reader.uint64(); + break; + case 2: + message.count = reader.uint32(); + break; + case 3: + message.prove = reader.bool(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedEncryptedNotesRequestV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} GetShieldedEncryptedNotesRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedEncryptedNotesRequestV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedEncryptedNotesRequestV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedEncryptedNotesRequestV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.startIndex != null && message.hasOwnProperty("startIndex")) + if (!$util.isInteger(message.startIndex) && !(message.startIndex && $util.isInteger(message.startIndex.low) && $util.isInteger(message.startIndex.high))) + return "startIndex: integer|Long expected"; + if (message.count != null && message.hasOwnProperty("count")) + if (!$util.isInteger(message.count)) + return "count: integer expected"; + if (message.prove != null && message.hasOwnProperty("prove")) + if (typeof message.prove !== "boolean") + return "prove: boolean expected"; + return null; + }; + + /** + * Creates a GetShieldedEncryptedNotesRequestV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} GetShieldedEncryptedNotesRequestV0 + */ + GetShieldedEncryptedNotesRequestV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0(); + if (object.startIndex != null) + if ($util.Long) + (message.startIndex = $util.Long.fromValue(object.startIndex)).unsigned = true; + else if (typeof object.startIndex === "string") + message.startIndex = parseInt(object.startIndex, 10); + else if (typeof object.startIndex === "number") + message.startIndex = object.startIndex; + else if (typeof object.startIndex === "object") + message.startIndex = new $util.LongBits(object.startIndex.low >>> 0, object.startIndex.high >>> 0).toNumber(true); + if (object.count != null) + message.count = object.count >>> 0; + if (object.prove != null) + message.prove = Boolean(object.prove); + return message; + }; + + /** + * Creates a plain object from a GetShieldedEncryptedNotesRequestV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} message GetShieldedEncryptedNotesRequestV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedEncryptedNotesRequestV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + if ($util.Long) { + var long = new $util.Long(0, 0, true); + object.startIndex = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.startIndex = options.longs === String ? "0" : 0; + object.count = 0; + object.prove = false; + } + if (message.startIndex != null && message.hasOwnProperty("startIndex")) + if (typeof message.startIndex === "number") + object.startIndex = options.longs === String ? String(message.startIndex) : message.startIndex; + else + object.startIndex = options.longs === String ? $util.Long.prototype.toString.call(message.startIndex) : options.longs === Number ? new $util.LongBits(message.startIndex.low >>> 0, message.startIndex.high >>> 0).toNumber(true) : message.startIndex; + if (message.count != null && message.hasOwnProperty("count")) + object.count = message.count; + if (message.prove != null && message.hasOwnProperty("prove")) + object.prove = message.prove; + return object; + }; + + /** + * Converts this GetShieldedEncryptedNotesRequestV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 + * @instance + * @returns {Object.} JSON object + */ + GetShieldedEncryptedNotesRequestV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetShieldedEncryptedNotesRequestV0; + })(); + + return GetShieldedEncryptedNotesRequest; + })(); + + v0.GetShieldedEncryptedNotesResponse = (function() { + + /** + * Properties of a GetShieldedEncryptedNotesResponse. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetShieldedEncryptedNotesResponse + * @property {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.IGetShieldedEncryptedNotesResponseV0|null} [v0] GetShieldedEncryptedNotesResponse v0 + */ + + /** + * Constructs a new GetShieldedEncryptedNotesResponse. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetShieldedEncryptedNotesResponse. + * @implements IGetShieldedEncryptedNotesResponse + * @constructor + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesResponse=} [properties] Properties to set + */ + function GetShieldedEncryptedNotesResponse(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedEncryptedNotesResponse v0. + * @member {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.IGetShieldedEncryptedNotesResponseV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @instance + */ + GetShieldedEncryptedNotesResponse.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedEncryptedNotesResponse version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @instance + */ + Object.defineProperty(GetShieldedEncryptedNotesResponse.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedEncryptedNotesResponse instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesResponse=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} GetShieldedEncryptedNotesResponse instance + */ + GetShieldedEncryptedNotesResponse.create = function create(properties) { + return new GetShieldedEncryptedNotesResponse(properties); + }; + + /** + * Encodes the specified GetShieldedEncryptedNotesResponse message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesResponse} message GetShieldedEncryptedNotesResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedEncryptedNotesResponse.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedEncryptedNotesResponse message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedEncryptedNotesResponse} message GetShieldedEncryptedNotesResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedEncryptedNotesResponse.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedEncryptedNotesResponse message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} GetShieldedEncryptedNotesResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedEncryptedNotesResponse.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedEncryptedNotesResponse message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} GetShieldedEncryptedNotesResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedEncryptedNotesResponse.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedEncryptedNotesResponse message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedEncryptedNotesResponse.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetShieldedEncryptedNotesResponse message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} GetShieldedEncryptedNotesResponse + */ + GetShieldedEncryptedNotesResponse.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedEncryptedNotesResponse message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} message GetShieldedEncryptedNotesResponse + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedEncryptedNotesResponse.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetShieldedEncryptedNotesResponse to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @instance + * @returns {Object.} JSON object + */ + GetShieldedEncryptedNotesResponse.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 = (function() { + + /** + * Properties of a GetShieldedEncryptedNotesResponseV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @interface IGetShieldedEncryptedNotesResponseV0 + * @property {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNotes|null} [encryptedNotes] GetShieldedEncryptedNotesResponseV0 encryptedNotes + * @property {org.dash.platform.dapi.v0.IProof|null} [proof] GetShieldedEncryptedNotesResponseV0 proof + * @property {org.dash.platform.dapi.v0.IResponseMetadata|null} [metadata] GetShieldedEncryptedNotesResponseV0 metadata + */ + + /** + * Constructs a new GetShieldedEncryptedNotesResponseV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse + * @classdesc Represents a GetShieldedEncryptedNotesResponseV0. + * @implements IGetShieldedEncryptedNotesResponseV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.IGetShieldedEncryptedNotesResponseV0=} [properties] Properties to set + */ + function GetShieldedEncryptedNotesResponseV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedEncryptedNotesResponseV0 encryptedNotes. + * @member {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNotes|null|undefined} encryptedNotes + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @instance + */ + GetShieldedEncryptedNotesResponseV0.prototype.encryptedNotes = null; + + /** + * GetShieldedEncryptedNotesResponseV0 proof. + * @member {org.dash.platform.dapi.v0.IProof|null|undefined} proof + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @instance + */ + GetShieldedEncryptedNotesResponseV0.prototype.proof = null; + + /** + * GetShieldedEncryptedNotesResponseV0 metadata. + * @member {org.dash.platform.dapi.v0.IResponseMetadata|null|undefined} metadata + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @instance + */ + GetShieldedEncryptedNotesResponseV0.prototype.metadata = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedEncryptedNotesResponseV0 result. + * @member {"encryptedNotes"|"proof"|undefined} result + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @instance + */ + Object.defineProperty(GetShieldedEncryptedNotesResponseV0.prototype, "result", { + get: $util.oneOfGetter($oneOfFields = ["encryptedNotes", "proof"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedEncryptedNotesResponseV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.IGetShieldedEncryptedNotesResponseV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} GetShieldedEncryptedNotesResponseV0 instance + */ + GetShieldedEncryptedNotesResponseV0.create = function create(properties) { + return new GetShieldedEncryptedNotesResponseV0(properties); + }; + + /** + * Encodes the specified GetShieldedEncryptedNotesResponseV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.IGetShieldedEncryptedNotesResponseV0} message GetShieldedEncryptedNotesResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedEncryptedNotesResponseV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.encryptedNotes != null && Object.hasOwnProperty.call(message, "encryptedNotes")) + $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.encode(message.encryptedNotes, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + if (message.proof != null && Object.hasOwnProperty.call(message, "proof")) + $root.org.dash.platform.dapi.v0.Proof.encode(message.proof, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + if (message.metadata != null && Object.hasOwnProperty.call(message, "metadata")) + $root.org.dash.platform.dapi.v0.ResponseMetadata.encode(message.metadata, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedEncryptedNotesResponseV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.IGetShieldedEncryptedNotesResponseV0} message GetShieldedEncryptedNotesResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedEncryptedNotesResponseV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedEncryptedNotesResponseV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} GetShieldedEncryptedNotesResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedEncryptedNotesResponseV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.encryptedNotes = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.decode(reader, reader.uint32()); + break; + case 2: + message.proof = $root.org.dash.platform.dapi.v0.Proof.decode(reader, reader.uint32()); + break; + case 3: + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedEncryptedNotesResponseV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} GetShieldedEncryptedNotesResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedEncryptedNotesResponseV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedEncryptedNotesResponseV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedEncryptedNotesResponseV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.encryptedNotes != null && message.hasOwnProperty("encryptedNotes")) { + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.verify(message.encryptedNotes); + if (error) + return "encryptedNotes." + error; + } + } + if (message.proof != null && message.hasOwnProperty("proof")) { + if (properties.result === 1) + return "result: multiple values"; + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.Proof.verify(message.proof); + if (error) + return "proof." + error; + } + } + if (message.metadata != null && message.hasOwnProperty("metadata")) { + var error = $root.org.dash.platform.dapi.v0.ResponseMetadata.verify(message.metadata); + if (error) + return "metadata." + error; + } + return null; + }; + + /** + * Creates a GetShieldedEncryptedNotesResponseV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} GetShieldedEncryptedNotesResponseV0 + */ + GetShieldedEncryptedNotesResponseV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0(); + if (object.encryptedNotes != null) { + if (typeof object.encryptedNotes !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.encryptedNotes: object expected"); + message.encryptedNotes = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.fromObject(object.encryptedNotes); + } + if (object.proof != null) { + if (typeof object.proof !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.proof: object expected"); + message.proof = $root.org.dash.platform.dapi.v0.Proof.fromObject(object.proof); + } + if (object.metadata != null) { + if (typeof object.metadata !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.metadata: object expected"); + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.fromObject(object.metadata); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedEncryptedNotesResponseV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} message GetShieldedEncryptedNotesResponseV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedEncryptedNotesResponseV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.metadata = null; + if (message.encryptedNotes != null && message.hasOwnProperty("encryptedNotes")) { + object.encryptedNotes = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.toObject(message.encryptedNotes, options); + if (options.oneofs) + object.result = "encryptedNotes"; + } + if (message.proof != null && message.hasOwnProperty("proof")) { + object.proof = $root.org.dash.platform.dapi.v0.Proof.toObject(message.proof, options); + if (options.oneofs) + object.result = "proof"; + } + if (message.metadata != null && message.hasOwnProperty("metadata")) + object.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.toObject(message.metadata, options); + return object; + }; + + /** + * Converts this GetShieldedEncryptedNotesResponseV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @instance + * @returns {Object.} JSON object + */ + GetShieldedEncryptedNotesResponseV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedEncryptedNotesResponseV0.EncryptedNote = (function() { + + /** + * Properties of an EncryptedNote. + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @interface IEncryptedNote + * @property {Uint8Array|null} [cmx] EncryptedNote cmx + * @property {Uint8Array|null} [encryptedNote] EncryptedNote encryptedNote + */ + + /** + * Constructs a new EncryptedNote. + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @classdesc Represents an EncryptedNote. + * @implements IEncryptedNote + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNote=} [properties] Properties to set + */ + function EncryptedNote(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * EncryptedNote cmx. + * @member {Uint8Array} cmx + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @instance + */ + EncryptedNote.prototype.cmx = $util.newBuffer([]); + + /** + * EncryptedNote encryptedNote. + * @member {Uint8Array} encryptedNote + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @instance + */ + EncryptedNote.prototype.encryptedNote = $util.newBuffer([]); + + /** + * Creates a new EncryptedNote instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNote=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} EncryptedNote instance + */ + EncryptedNote.create = function create(properties) { + return new EncryptedNote(properties); + }; + + /** + * Encodes the specified EncryptedNote message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNote} message EncryptedNote message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + EncryptedNote.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.cmx != null && Object.hasOwnProperty.call(message, "cmx")) + writer.uint32(/* id 1, wireType 2 =*/10).bytes(message.cmx); + if (message.encryptedNote != null && Object.hasOwnProperty.call(message, "encryptedNote")) + writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.encryptedNote); + return writer; + }; + + /** + * Encodes the specified EncryptedNote message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNote} message EncryptedNote message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + EncryptedNote.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes an EncryptedNote message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} EncryptedNote + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + EncryptedNote.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.cmx = reader.bytes(); + break; + case 2: + message.encryptedNote = reader.bytes(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes an EncryptedNote message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} EncryptedNote + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + EncryptedNote.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies an EncryptedNote message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + EncryptedNote.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.cmx != null && message.hasOwnProperty("cmx")) + if (!(message.cmx && typeof message.cmx.length === "number" || $util.isString(message.cmx))) + return "cmx: buffer expected"; + if (message.encryptedNote != null && message.hasOwnProperty("encryptedNote")) + if (!(message.encryptedNote && typeof message.encryptedNote.length === "number" || $util.isString(message.encryptedNote))) + return "encryptedNote: buffer expected"; + return null; + }; + + /** + * Creates an EncryptedNote message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} EncryptedNote + */ + EncryptedNote.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote(); + if (object.cmx != null) + if (typeof object.cmx === "string") + $util.base64.decode(object.cmx, message.cmx = $util.newBuffer($util.base64.length(object.cmx)), 0); + else if (object.cmx.length >= 0) + message.cmx = object.cmx; + if (object.encryptedNote != null) + if (typeof object.encryptedNote === "string") + $util.base64.decode(object.encryptedNote, message.encryptedNote = $util.newBuffer($util.base64.length(object.encryptedNote)), 0); + else if (object.encryptedNote.length >= 0) + message.encryptedNote = object.encryptedNote; + return message; + }; + + /** + * Creates a plain object from an EncryptedNote message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} message EncryptedNote + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + EncryptedNote.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + if (options.bytes === String) + object.cmx = ""; + else { + object.cmx = []; + if (options.bytes !== Array) + object.cmx = $util.newBuffer(object.cmx); + } + if (options.bytes === String) + object.encryptedNote = ""; + else { + object.encryptedNote = []; + if (options.bytes !== Array) + object.encryptedNote = $util.newBuffer(object.encryptedNote); + } + } + if (message.cmx != null && message.hasOwnProperty("cmx")) + object.cmx = options.bytes === String ? $util.base64.encode(message.cmx, 0, message.cmx.length) : options.bytes === Array ? Array.prototype.slice.call(message.cmx) : message.cmx; + if (message.encryptedNote != null && message.hasOwnProperty("encryptedNote")) + object.encryptedNote = options.bytes === String ? $util.base64.encode(message.encryptedNote, 0, message.encryptedNote.length) : options.bytes === Array ? Array.prototype.slice.call(message.encryptedNote) : message.encryptedNote; + return object; + }; + + /** + * Converts this EncryptedNote to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @instance + * @returns {Object.} JSON object + */ + EncryptedNote.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return EncryptedNote; + })(); + + GetShieldedEncryptedNotesResponseV0.EncryptedNotes = (function() { + + /** + * Properties of an EncryptedNotes. + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @interface IEncryptedNotes + * @property {Array.|null} [entries] EncryptedNotes entries + */ + + /** + * Constructs a new EncryptedNotes. + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 + * @classdesc Represents an EncryptedNotes. + * @implements IEncryptedNotes + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNotes=} [properties] Properties to set + */ + function EncryptedNotes(properties) { + this.entries = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * EncryptedNotes entries. + * @member {Array.} entries + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @instance + */ + EncryptedNotes.prototype.entries = $util.emptyArray; + + /** + * Creates a new EncryptedNotes instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNotes=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} EncryptedNotes instance + */ + EncryptedNotes.create = function create(properties) { + return new EncryptedNotes(properties); + }; + + /** + * Encodes the specified EncryptedNotes message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNotes} message EncryptedNotes message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + EncryptedNotes.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.entries != null && message.entries.length) + for (var i = 0; i < message.entries.length; ++i) + $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.encode(message.entries[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified EncryptedNotes message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.IEncryptedNotes} message EncryptedNotes message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + EncryptedNotes.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes an EncryptedNotes message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} EncryptedNotes + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + EncryptedNotes.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (!(message.entries && message.entries.length)) + message.entries = []; + message.entries.push($root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.decode(reader, reader.uint32())); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes an EncryptedNotes message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} EncryptedNotes + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + EncryptedNotes.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies an EncryptedNotes message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + EncryptedNotes.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.entries != null && message.hasOwnProperty("entries")) { + if (!Array.isArray(message.entries)) + return "entries: array expected"; + for (var i = 0; i < message.entries.length; ++i) { + var error = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.verify(message.entries[i]); + if (error) + return "entries." + error; + } + } + return null; + }; + + /** + * Creates an EncryptedNotes message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} EncryptedNotes + */ + EncryptedNotes.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes(); + if (object.entries) { + if (!Array.isArray(object.entries)) + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.entries: array expected"); + message.entries = []; + for (var i = 0; i < object.entries.length; ++i) { + if (typeof object.entries[i] !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.entries: object expected"); + message.entries[i] = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.fromObject(object.entries[i]); + } + } + return message; + }; + + /** + * Creates a plain object from an EncryptedNotes message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} message EncryptedNotes + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + EncryptedNotes.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.entries = []; + if (message.entries && message.entries.length) { + object.entries = []; + for (var j = 0; j < message.entries.length; ++j) + object.entries[j] = $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.toObject(message.entries[j], options); + } + return object; + }; + + /** + * Converts this EncryptedNotes to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes + * @instance + * @returns {Object.} JSON object + */ + EncryptedNotes.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return EncryptedNotes; + })(); + + return GetShieldedEncryptedNotesResponseV0; + })(); + + return GetShieldedEncryptedNotesResponse; + })(); + + v0.GetShieldedAnchorsRequest = (function() { + + /** + * Properties of a GetShieldedAnchorsRequest. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetShieldedAnchorsRequest + * @property {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.IGetShieldedAnchorsRequestV0|null} [v0] GetShieldedAnchorsRequest v0 + */ + + /** + * Constructs a new GetShieldedAnchorsRequest. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetShieldedAnchorsRequest. + * @implements IGetShieldedAnchorsRequest + * @constructor + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsRequest=} [properties] Properties to set + */ + function GetShieldedAnchorsRequest(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedAnchorsRequest v0. + * @member {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.IGetShieldedAnchorsRequestV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @instance + */ + GetShieldedAnchorsRequest.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedAnchorsRequest version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @instance + */ + Object.defineProperty(GetShieldedAnchorsRequest.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedAnchorsRequest instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsRequest=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} GetShieldedAnchorsRequest instance + */ + GetShieldedAnchorsRequest.create = function create(properties) { + return new GetShieldedAnchorsRequest(properties); + }; + + /** + * Encodes the specified GetShieldedAnchorsRequest message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsRequest} message GetShieldedAnchorsRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedAnchorsRequest.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedAnchorsRequest message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsRequest} message GetShieldedAnchorsRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedAnchorsRequest.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedAnchorsRequest message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} GetShieldedAnchorsRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedAnchorsRequest.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedAnchorsRequest message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} GetShieldedAnchorsRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedAnchorsRequest.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedAnchorsRequest message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedAnchorsRequest.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetShieldedAnchorsRequest message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} GetShieldedAnchorsRequest + */ + GetShieldedAnchorsRequest.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedAnchorsRequest message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} message GetShieldedAnchorsRequest + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedAnchorsRequest.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetShieldedAnchorsRequest to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @instance + * @returns {Object.} JSON object + */ + GetShieldedAnchorsRequest.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 = (function() { + + /** + * Properties of a GetShieldedAnchorsRequestV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @interface IGetShieldedAnchorsRequestV0 + * @property {boolean|null} [prove] GetShieldedAnchorsRequestV0 prove + */ + + /** + * Constructs a new GetShieldedAnchorsRequestV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest + * @classdesc Represents a GetShieldedAnchorsRequestV0. + * @implements IGetShieldedAnchorsRequestV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.IGetShieldedAnchorsRequestV0=} [properties] Properties to set + */ + function GetShieldedAnchorsRequestV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedAnchorsRequestV0 prove. + * @member {boolean} prove + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @instance + */ + GetShieldedAnchorsRequestV0.prototype.prove = false; + + /** + * Creates a new GetShieldedAnchorsRequestV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.IGetShieldedAnchorsRequestV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} GetShieldedAnchorsRequestV0 instance + */ + GetShieldedAnchorsRequestV0.create = function create(properties) { + return new GetShieldedAnchorsRequestV0(properties); + }; + + /** + * Encodes the specified GetShieldedAnchorsRequestV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.IGetShieldedAnchorsRequestV0} message GetShieldedAnchorsRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedAnchorsRequestV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.prove != null && Object.hasOwnProperty.call(message, "prove")) + writer.uint32(/* id 1, wireType 0 =*/8).bool(message.prove); + return writer; + }; + + /** + * Encodes the specified GetShieldedAnchorsRequestV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.IGetShieldedAnchorsRequestV0} message GetShieldedAnchorsRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedAnchorsRequestV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedAnchorsRequestV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} GetShieldedAnchorsRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedAnchorsRequestV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.prove = reader.bool(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedAnchorsRequestV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} GetShieldedAnchorsRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedAnchorsRequestV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedAnchorsRequestV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedAnchorsRequestV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.prove != null && message.hasOwnProperty("prove")) + if (typeof message.prove !== "boolean") + return "prove: boolean expected"; + return null; + }; + + /** + * Creates a GetShieldedAnchorsRequestV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} GetShieldedAnchorsRequestV0 + */ + GetShieldedAnchorsRequestV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0(); + if (object.prove != null) + message.prove = Boolean(object.prove); + return message; + }; + + /** + * Creates a plain object from a GetShieldedAnchorsRequestV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} message GetShieldedAnchorsRequestV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedAnchorsRequestV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.prove = false; + if (message.prove != null && message.hasOwnProperty("prove")) + object.prove = message.prove; + return object; + }; + + /** + * Converts this GetShieldedAnchorsRequestV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 + * @instance + * @returns {Object.} JSON object + */ + GetShieldedAnchorsRequestV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetShieldedAnchorsRequestV0; + })(); + + return GetShieldedAnchorsRequest; + })(); + + v0.GetShieldedAnchorsResponse = (function() { + + /** + * Properties of a GetShieldedAnchorsResponse. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetShieldedAnchorsResponse + * @property {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.IGetShieldedAnchorsResponseV0|null} [v0] GetShieldedAnchorsResponse v0 + */ + + /** + * Constructs a new GetShieldedAnchorsResponse. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetShieldedAnchorsResponse. + * @implements IGetShieldedAnchorsResponse + * @constructor + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsResponse=} [properties] Properties to set + */ + function GetShieldedAnchorsResponse(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedAnchorsResponse v0. + * @member {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.IGetShieldedAnchorsResponseV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @instance + */ + GetShieldedAnchorsResponse.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedAnchorsResponse version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @instance + */ + Object.defineProperty(GetShieldedAnchorsResponse.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedAnchorsResponse instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsResponse=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} GetShieldedAnchorsResponse instance + */ + GetShieldedAnchorsResponse.create = function create(properties) { + return new GetShieldedAnchorsResponse(properties); + }; + + /** + * Encodes the specified GetShieldedAnchorsResponse message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsResponse} message GetShieldedAnchorsResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedAnchorsResponse.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedAnchorsResponse message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedAnchorsResponse} message GetShieldedAnchorsResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedAnchorsResponse.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedAnchorsResponse message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} GetShieldedAnchorsResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedAnchorsResponse.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedAnchorsResponse message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} GetShieldedAnchorsResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedAnchorsResponse.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedAnchorsResponse message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedAnchorsResponse.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetShieldedAnchorsResponse message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} GetShieldedAnchorsResponse + */ + GetShieldedAnchorsResponse.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedAnchorsResponse message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} message GetShieldedAnchorsResponse + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedAnchorsResponse.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetShieldedAnchorsResponse to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @instance + * @returns {Object.} JSON object + */ + GetShieldedAnchorsResponse.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 = (function() { + + /** + * Properties of a GetShieldedAnchorsResponseV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @interface IGetShieldedAnchorsResponseV0 + * @property {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.IAnchors|null} [anchors] GetShieldedAnchorsResponseV0 anchors + * @property {org.dash.platform.dapi.v0.IProof|null} [proof] GetShieldedAnchorsResponseV0 proof + * @property {org.dash.platform.dapi.v0.IResponseMetadata|null} [metadata] GetShieldedAnchorsResponseV0 metadata + */ + + /** + * Constructs a new GetShieldedAnchorsResponseV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse + * @classdesc Represents a GetShieldedAnchorsResponseV0. + * @implements IGetShieldedAnchorsResponseV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.IGetShieldedAnchorsResponseV0=} [properties] Properties to set + */ + function GetShieldedAnchorsResponseV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedAnchorsResponseV0 anchors. + * @member {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.IAnchors|null|undefined} anchors + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @instance + */ + GetShieldedAnchorsResponseV0.prototype.anchors = null; + + /** + * GetShieldedAnchorsResponseV0 proof. + * @member {org.dash.platform.dapi.v0.IProof|null|undefined} proof + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @instance + */ + GetShieldedAnchorsResponseV0.prototype.proof = null; + + /** + * GetShieldedAnchorsResponseV0 metadata. + * @member {org.dash.platform.dapi.v0.IResponseMetadata|null|undefined} metadata + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @instance + */ + GetShieldedAnchorsResponseV0.prototype.metadata = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedAnchorsResponseV0 result. + * @member {"anchors"|"proof"|undefined} result + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @instance + */ + Object.defineProperty(GetShieldedAnchorsResponseV0.prototype, "result", { + get: $util.oneOfGetter($oneOfFields = ["anchors", "proof"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedAnchorsResponseV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.IGetShieldedAnchorsResponseV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} GetShieldedAnchorsResponseV0 instance + */ + GetShieldedAnchorsResponseV0.create = function create(properties) { + return new GetShieldedAnchorsResponseV0(properties); + }; + + /** + * Encodes the specified GetShieldedAnchorsResponseV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.IGetShieldedAnchorsResponseV0} message GetShieldedAnchorsResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedAnchorsResponseV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.anchors != null && Object.hasOwnProperty.call(message, "anchors")) + $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.encode(message.anchors, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + if (message.proof != null && Object.hasOwnProperty.call(message, "proof")) + $root.org.dash.platform.dapi.v0.Proof.encode(message.proof, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + if (message.metadata != null && Object.hasOwnProperty.call(message, "metadata")) + $root.org.dash.platform.dapi.v0.ResponseMetadata.encode(message.metadata, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedAnchorsResponseV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.IGetShieldedAnchorsResponseV0} message GetShieldedAnchorsResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedAnchorsResponseV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedAnchorsResponseV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} GetShieldedAnchorsResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedAnchorsResponseV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.anchors = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.decode(reader, reader.uint32()); + break; + case 2: + message.proof = $root.org.dash.platform.dapi.v0.Proof.decode(reader, reader.uint32()); + break; + case 3: + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedAnchorsResponseV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} GetShieldedAnchorsResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedAnchorsResponseV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedAnchorsResponseV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedAnchorsResponseV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.anchors != null && message.hasOwnProperty("anchors")) { + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.verify(message.anchors); + if (error) + return "anchors." + error; + } + } + if (message.proof != null && message.hasOwnProperty("proof")) { + if (properties.result === 1) + return "result: multiple values"; + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.Proof.verify(message.proof); + if (error) + return "proof." + error; + } + } + if (message.metadata != null && message.hasOwnProperty("metadata")) { + var error = $root.org.dash.platform.dapi.v0.ResponseMetadata.verify(message.metadata); + if (error) + return "metadata." + error; + } + return null; + }; + + /** + * Creates a GetShieldedAnchorsResponseV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} GetShieldedAnchorsResponseV0 + */ + GetShieldedAnchorsResponseV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0(); + if (object.anchors != null) { + if (typeof object.anchors !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.anchors: object expected"); + message.anchors = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.fromObject(object.anchors); + } + if (object.proof != null) { + if (typeof object.proof !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.proof: object expected"); + message.proof = $root.org.dash.platform.dapi.v0.Proof.fromObject(object.proof); + } + if (object.metadata != null) { + if (typeof object.metadata !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.metadata: object expected"); + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.fromObject(object.metadata); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedAnchorsResponseV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} message GetShieldedAnchorsResponseV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedAnchorsResponseV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.metadata = null; + if (message.anchors != null && message.hasOwnProperty("anchors")) { + object.anchors = $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.toObject(message.anchors, options); + if (options.oneofs) + object.result = "anchors"; + } + if (message.proof != null && message.hasOwnProperty("proof")) { + object.proof = $root.org.dash.platform.dapi.v0.Proof.toObject(message.proof, options); + if (options.oneofs) + object.result = "proof"; + } + if (message.metadata != null && message.hasOwnProperty("metadata")) + object.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.toObject(message.metadata, options); + return object; + }; + + /** + * Converts this GetShieldedAnchorsResponseV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @instance + * @returns {Object.} JSON object + */ + GetShieldedAnchorsResponseV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedAnchorsResponseV0.Anchors = (function() { + + /** + * Properties of an Anchors. + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @interface IAnchors + * @property {Array.|null} [anchors] Anchors anchors + */ + + /** + * Constructs a new Anchors. + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 + * @classdesc Represents an Anchors. + * @implements IAnchors + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.IAnchors=} [properties] Properties to set + */ + function Anchors(properties) { + this.anchors = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * Anchors anchors. + * @member {Array.} anchors + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @instance + */ + Anchors.prototype.anchors = $util.emptyArray; + + /** + * Creates a new Anchors instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.IAnchors=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} Anchors instance + */ + Anchors.create = function create(properties) { + return new Anchors(properties); + }; + + /** + * Encodes the specified Anchors message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.IAnchors} message Anchors message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Anchors.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.anchors != null && message.anchors.length) + for (var i = 0; i < message.anchors.length; ++i) + writer.uint32(/* id 1, wireType 2 =*/10).bytes(message.anchors[i]); + return writer; + }; + + /** + * Encodes the specified Anchors message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.IAnchors} message Anchors message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + Anchors.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes an Anchors message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} Anchors + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Anchors.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (!(message.anchors && message.anchors.length)) + message.anchors = []; + message.anchors.push(reader.bytes()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes an Anchors message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} Anchors + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + Anchors.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies an Anchors message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + Anchors.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.anchors != null && message.hasOwnProperty("anchors")) { + if (!Array.isArray(message.anchors)) + return "anchors: array expected"; + for (var i = 0; i < message.anchors.length; ++i) + if (!(message.anchors[i] && typeof message.anchors[i].length === "number" || $util.isString(message.anchors[i]))) + return "anchors: buffer[] expected"; + } + return null; + }; + + /** + * Creates an Anchors message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} Anchors + */ + Anchors.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors(); + if (object.anchors) { + if (!Array.isArray(object.anchors)) + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.anchors: array expected"); + message.anchors = []; + for (var i = 0; i < object.anchors.length; ++i) + if (typeof object.anchors[i] === "string") + $util.base64.decode(object.anchors[i], message.anchors[i] = $util.newBuffer($util.base64.length(object.anchors[i])), 0); + else if (object.anchors[i].length >= 0) + message.anchors[i] = object.anchors[i]; + } + return message; + }; + + /** + * Creates a plain object from an Anchors message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} message Anchors + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + Anchors.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.anchors = []; + if (message.anchors && message.anchors.length) { + object.anchors = []; + for (var j = 0; j < message.anchors.length; ++j) + object.anchors[j] = options.bytes === String ? $util.base64.encode(message.anchors[j], 0, message.anchors[j].length) : options.bytes === Array ? Array.prototype.slice.call(message.anchors[j]) : message.anchors[j]; + } + return object; + }; + + /** + * Converts this Anchors to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors + * @instance + * @returns {Object.} JSON object + */ + Anchors.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return Anchors; + })(); + + return GetShieldedAnchorsResponseV0; + })(); + + return GetShieldedAnchorsResponse; + })(); + + v0.GetShieldedPoolStateRequest = (function() { + + /** + * Properties of a GetShieldedPoolStateRequest. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetShieldedPoolStateRequest + * @property {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.IGetShieldedPoolStateRequestV0|null} [v0] GetShieldedPoolStateRequest v0 + */ + + /** + * Constructs a new GetShieldedPoolStateRequest. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetShieldedPoolStateRequest. + * @implements IGetShieldedPoolStateRequest + * @constructor + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateRequest=} [properties] Properties to set + */ + function GetShieldedPoolStateRequest(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedPoolStateRequest v0. + * @member {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.IGetShieldedPoolStateRequestV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @instance + */ + GetShieldedPoolStateRequest.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedPoolStateRequest version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @instance + */ + Object.defineProperty(GetShieldedPoolStateRequest.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedPoolStateRequest instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateRequest=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} GetShieldedPoolStateRequest instance + */ + GetShieldedPoolStateRequest.create = function create(properties) { + return new GetShieldedPoolStateRequest(properties); + }; + + /** + * Encodes the specified GetShieldedPoolStateRequest message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateRequest} message GetShieldedPoolStateRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedPoolStateRequest.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedPoolStateRequest message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateRequest} message GetShieldedPoolStateRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedPoolStateRequest.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedPoolStateRequest message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} GetShieldedPoolStateRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedPoolStateRequest.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedPoolStateRequest message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} GetShieldedPoolStateRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedPoolStateRequest.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedPoolStateRequest message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedPoolStateRequest.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetShieldedPoolStateRequest message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} GetShieldedPoolStateRequest + */ + GetShieldedPoolStateRequest.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedPoolStateRequest message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} message GetShieldedPoolStateRequest + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedPoolStateRequest.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetShieldedPoolStateRequest to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @instance + * @returns {Object.} JSON object + */ + GetShieldedPoolStateRequest.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 = (function() { + + /** + * Properties of a GetShieldedPoolStateRequestV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @interface IGetShieldedPoolStateRequestV0 + * @property {boolean|null} [prove] GetShieldedPoolStateRequestV0 prove + */ + + /** + * Constructs a new GetShieldedPoolStateRequestV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest + * @classdesc Represents a GetShieldedPoolStateRequestV0. + * @implements IGetShieldedPoolStateRequestV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.IGetShieldedPoolStateRequestV0=} [properties] Properties to set + */ + function GetShieldedPoolStateRequestV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedPoolStateRequestV0 prove. + * @member {boolean} prove + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @instance + */ + GetShieldedPoolStateRequestV0.prototype.prove = false; + + /** + * Creates a new GetShieldedPoolStateRequestV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.IGetShieldedPoolStateRequestV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} GetShieldedPoolStateRequestV0 instance + */ + GetShieldedPoolStateRequestV0.create = function create(properties) { + return new GetShieldedPoolStateRequestV0(properties); + }; + + /** + * Encodes the specified GetShieldedPoolStateRequestV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.IGetShieldedPoolStateRequestV0} message GetShieldedPoolStateRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedPoolStateRequestV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.prove != null && Object.hasOwnProperty.call(message, "prove")) + writer.uint32(/* id 1, wireType 0 =*/8).bool(message.prove); + return writer; + }; + + /** + * Encodes the specified GetShieldedPoolStateRequestV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.IGetShieldedPoolStateRequestV0} message GetShieldedPoolStateRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedPoolStateRequestV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedPoolStateRequestV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} GetShieldedPoolStateRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedPoolStateRequestV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.prove = reader.bool(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedPoolStateRequestV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} GetShieldedPoolStateRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedPoolStateRequestV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedPoolStateRequestV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedPoolStateRequestV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.prove != null && message.hasOwnProperty("prove")) + if (typeof message.prove !== "boolean") + return "prove: boolean expected"; + return null; + }; + + /** + * Creates a GetShieldedPoolStateRequestV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} GetShieldedPoolStateRequestV0 + */ + GetShieldedPoolStateRequestV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0(); + if (object.prove != null) + message.prove = Boolean(object.prove); + return message; + }; + + /** + * Creates a plain object from a GetShieldedPoolStateRequestV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} message GetShieldedPoolStateRequestV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedPoolStateRequestV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.prove = false; + if (message.prove != null && message.hasOwnProperty("prove")) + object.prove = message.prove; + return object; + }; + + /** + * Converts this GetShieldedPoolStateRequestV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 + * @instance + * @returns {Object.} JSON object + */ + GetShieldedPoolStateRequestV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetShieldedPoolStateRequestV0; + })(); + + return GetShieldedPoolStateRequest; + })(); + + v0.GetShieldedPoolStateResponse = (function() { + + /** + * Properties of a GetShieldedPoolStateResponse. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetShieldedPoolStateResponse + * @property {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.IGetShieldedPoolStateResponseV0|null} [v0] GetShieldedPoolStateResponse v0 + */ + + /** + * Constructs a new GetShieldedPoolStateResponse. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetShieldedPoolStateResponse. + * @implements IGetShieldedPoolStateResponse + * @constructor + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateResponse=} [properties] Properties to set + */ + function GetShieldedPoolStateResponse(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedPoolStateResponse v0. + * @member {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.IGetShieldedPoolStateResponseV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @instance + */ + GetShieldedPoolStateResponse.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedPoolStateResponse version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @instance + */ + Object.defineProperty(GetShieldedPoolStateResponse.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedPoolStateResponse instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateResponse=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} GetShieldedPoolStateResponse instance + */ + GetShieldedPoolStateResponse.create = function create(properties) { + return new GetShieldedPoolStateResponse(properties); + }; + + /** + * Encodes the specified GetShieldedPoolStateResponse message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateResponse} message GetShieldedPoolStateResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedPoolStateResponse.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedPoolStateResponse message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedPoolStateResponse} message GetShieldedPoolStateResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedPoolStateResponse.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedPoolStateResponse message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} GetShieldedPoolStateResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedPoolStateResponse.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedPoolStateResponse message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} GetShieldedPoolStateResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedPoolStateResponse.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedPoolStateResponse message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedPoolStateResponse.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetShieldedPoolStateResponse message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} GetShieldedPoolStateResponse + */ + GetShieldedPoolStateResponse.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedPoolStateResponse message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} message GetShieldedPoolStateResponse + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedPoolStateResponse.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetShieldedPoolStateResponse to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @instance + * @returns {Object.} JSON object + */ + GetShieldedPoolStateResponse.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 = (function() { + + /** + * Properties of a GetShieldedPoolStateResponseV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @interface IGetShieldedPoolStateResponseV0 + * @property {number|Long|null} [totalBalance] GetShieldedPoolStateResponseV0 totalBalance + * @property {org.dash.platform.dapi.v0.IProof|null} [proof] GetShieldedPoolStateResponseV0 proof + * @property {org.dash.platform.dapi.v0.IResponseMetadata|null} [metadata] GetShieldedPoolStateResponseV0 metadata + */ + + /** + * Constructs a new GetShieldedPoolStateResponseV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse + * @classdesc Represents a GetShieldedPoolStateResponseV0. + * @implements IGetShieldedPoolStateResponseV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.IGetShieldedPoolStateResponseV0=} [properties] Properties to set + */ + function GetShieldedPoolStateResponseV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedPoolStateResponseV0 totalBalance. + * @member {number|Long} totalBalance + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @instance + */ + GetShieldedPoolStateResponseV0.prototype.totalBalance = $util.Long ? $util.Long.fromBits(0,0,true) : 0; + + /** + * GetShieldedPoolStateResponseV0 proof. + * @member {org.dash.platform.dapi.v0.IProof|null|undefined} proof + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @instance + */ + GetShieldedPoolStateResponseV0.prototype.proof = null; + + /** + * GetShieldedPoolStateResponseV0 metadata. + * @member {org.dash.platform.dapi.v0.IResponseMetadata|null|undefined} metadata + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @instance + */ + GetShieldedPoolStateResponseV0.prototype.metadata = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedPoolStateResponseV0 result. + * @member {"totalBalance"|"proof"|undefined} result + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @instance + */ + Object.defineProperty(GetShieldedPoolStateResponseV0.prototype, "result", { + get: $util.oneOfGetter($oneOfFields = ["totalBalance", "proof"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedPoolStateResponseV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.IGetShieldedPoolStateResponseV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} GetShieldedPoolStateResponseV0 instance + */ + GetShieldedPoolStateResponseV0.create = function create(properties) { + return new GetShieldedPoolStateResponseV0(properties); + }; + + /** + * Encodes the specified GetShieldedPoolStateResponseV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.IGetShieldedPoolStateResponseV0} message GetShieldedPoolStateResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedPoolStateResponseV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.totalBalance != null && Object.hasOwnProperty.call(message, "totalBalance")) + writer.uint32(/* id 1, wireType 0 =*/8).uint64(message.totalBalance); + if (message.proof != null && Object.hasOwnProperty.call(message, "proof")) + $root.org.dash.platform.dapi.v0.Proof.encode(message.proof, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + if (message.metadata != null && Object.hasOwnProperty.call(message, "metadata")) + $root.org.dash.platform.dapi.v0.ResponseMetadata.encode(message.metadata, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedPoolStateResponseV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.IGetShieldedPoolStateResponseV0} message GetShieldedPoolStateResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedPoolStateResponseV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedPoolStateResponseV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} GetShieldedPoolStateResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedPoolStateResponseV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.totalBalance = reader.uint64(); + break; + case 2: + message.proof = $root.org.dash.platform.dapi.v0.Proof.decode(reader, reader.uint32()); + break; + case 3: + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedPoolStateResponseV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} GetShieldedPoolStateResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedPoolStateResponseV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedPoolStateResponseV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedPoolStateResponseV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.totalBalance != null && message.hasOwnProperty("totalBalance")) { + properties.result = 1; + if (!$util.isInteger(message.totalBalance) && !(message.totalBalance && $util.isInteger(message.totalBalance.low) && $util.isInteger(message.totalBalance.high))) + return "totalBalance: integer|Long expected"; + } + if (message.proof != null && message.hasOwnProperty("proof")) { + if (properties.result === 1) + return "result: multiple values"; + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.Proof.verify(message.proof); + if (error) + return "proof." + error; + } + } + if (message.metadata != null && message.hasOwnProperty("metadata")) { + var error = $root.org.dash.platform.dapi.v0.ResponseMetadata.verify(message.metadata); + if (error) + return "metadata." + error; + } + return null; + }; + + /** + * Creates a GetShieldedPoolStateResponseV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} GetShieldedPoolStateResponseV0 + */ + GetShieldedPoolStateResponseV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0(); + if (object.totalBalance != null) + if ($util.Long) + (message.totalBalance = $util.Long.fromValue(object.totalBalance)).unsigned = true; + else if (typeof object.totalBalance === "string") + message.totalBalance = parseInt(object.totalBalance, 10); + else if (typeof object.totalBalance === "number") + message.totalBalance = object.totalBalance; + else if (typeof object.totalBalance === "object") + message.totalBalance = new $util.LongBits(object.totalBalance.low >>> 0, object.totalBalance.high >>> 0).toNumber(true); + if (object.proof != null) { + if (typeof object.proof !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.proof: object expected"); + message.proof = $root.org.dash.platform.dapi.v0.Proof.fromObject(object.proof); + } + if (object.metadata != null) { + if (typeof object.metadata !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.metadata: object expected"); + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.fromObject(object.metadata); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedPoolStateResponseV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} message GetShieldedPoolStateResponseV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedPoolStateResponseV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.metadata = null; + if (message.totalBalance != null && message.hasOwnProperty("totalBalance")) { + if (typeof message.totalBalance === "number") + object.totalBalance = options.longs === String ? String(message.totalBalance) : message.totalBalance; + else + object.totalBalance = options.longs === String ? $util.Long.prototype.toString.call(message.totalBalance) : options.longs === Number ? new $util.LongBits(message.totalBalance.low >>> 0, message.totalBalance.high >>> 0).toNumber(true) : message.totalBalance; + if (options.oneofs) + object.result = "totalBalance"; + } + if (message.proof != null && message.hasOwnProperty("proof")) { + object.proof = $root.org.dash.platform.dapi.v0.Proof.toObject(message.proof, options); + if (options.oneofs) + object.result = "proof"; + } + if (message.metadata != null && message.hasOwnProperty("metadata")) + object.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.toObject(message.metadata, options); + return object; + }; + + /** + * Converts this GetShieldedPoolStateResponseV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 + * @instance + * @returns {Object.} JSON object + */ + GetShieldedPoolStateResponseV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetShieldedPoolStateResponseV0; + })(); + + return GetShieldedPoolStateResponse; + })(); + + v0.GetShieldedNullifiersRequest = (function() { + + /** + * Properties of a GetShieldedNullifiersRequest. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetShieldedNullifiersRequest + * @property {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.IGetShieldedNullifiersRequestV0|null} [v0] GetShieldedNullifiersRequest v0 + */ + + /** + * Constructs a new GetShieldedNullifiersRequest. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetShieldedNullifiersRequest. + * @implements IGetShieldedNullifiersRequest + * @constructor + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersRequest=} [properties] Properties to set + */ + function GetShieldedNullifiersRequest(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedNullifiersRequest v0. + * @member {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.IGetShieldedNullifiersRequestV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @instance + */ + GetShieldedNullifiersRequest.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedNullifiersRequest version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @instance + */ + Object.defineProperty(GetShieldedNullifiersRequest.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedNullifiersRequest instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersRequest=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} GetShieldedNullifiersRequest instance + */ + GetShieldedNullifiersRequest.create = function create(properties) { + return new GetShieldedNullifiersRequest(properties); + }; + + /** + * Encodes the specified GetShieldedNullifiersRequest message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersRequest} message GetShieldedNullifiersRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedNullifiersRequest.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedNullifiersRequest message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersRequest} message GetShieldedNullifiersRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedNullifiersRequest.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedNullifiersRequest message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} GetShieldedNullifiersRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedNullifiersRequest.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedNullifiersRequest message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} GetShieldedNullifiersRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedNullifiersRequest.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedNullifiersRequest message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedNullifiersRequest.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetShieldedNullifiersRequest message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} GetShieldedNullifiersRequest + */ + GetShieldedNullifiersRequest.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedNullifiersRequest message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} message GetShieldedNullifiersRequest + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedNullifiersRequest.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetShieldedNullifiersRequest to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @instance + * @returns {Object.} JSON object + */ + GetShieldedNullifiersRequest.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 = (function() { + + /** + * Properties of a GetShieldedNullifiersRequestV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @interface IGetShieldedNullifiersRequestV0 + * @property {Array.|null} [nullifiers] GetShieldedNullifiersRequestV0 nullifiers + * @property {boolean|null} [prove] GetShieldedNullifiersRequestV0 prove + */ + + /** + * Constructs a new GetShieldedNullifiersRequestV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest + * @classdesc Represents a GetShieldedNullifiersRequestV0. + * @implements IGetShieldedNullifiersRequestV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.IGetShieldedNullifiersRequestV0=} [properties] Properties to set + */ + function GetShieldedNullifiersRequestV0(properties) { + this.nullifiers = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedNullifiersRequestV0 nullifiers. + * @member {Array.} nullifiers + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @instance + */ + GetShieldedNullifiersRequestV0.prototype.nullifiers = $util.emptyArray; + + /** + * GetShieldedNullifiersRequestV0 prove. + * @member {boolean} prove + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @instance + */ + GetShieldedNullifiersRequestV0.prototype.prove = false; + + /** + * Creates a new GetShieldedNullifiersRequestV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.IGetShieldedNullifiersRequestV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} GetShieldedNullifiersRequestV0 instance + */ + GetShieldedNullifiersRequestV0.create = function create(properties) { + return new GetShieldedNullifiersRequestV0(properties); + }; + + /** + * Encodes the specified GetShieldedNullifiersRequestV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.IGetShieldedNullifiersRequestV0} message GetShieldedNullifiersRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedNullifiersRequestV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.nullifiers != null && message.nullifiers.length) + for (var i = 0; i < message.nullifiers.length; ++i) + writer.uint32(/* id 1, wireType 2 =*/10).bytes(message.nullifiers[i]); + if (message.prove != null && Object.hasOwnProperty.call(message, "prove")) + writer.uint32(/* id 2, wireType 0 =*/16).bool(message.prove); + return writer; + }; + + /** + * Encodes the specified GetShieldedNullifiersRequestV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.IGetShieldedNullifiersRequestV0} message GetShieldedNullifiersRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedNullifiersRequestV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedNullifiersRequestV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} GetShieldedNullifiersRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedNullifiersRequestV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (!(message.nullifiers && message.nullifiers.length)) + message.nullifiers = []; + message.nullifiers.push(reader.bytes()); + break; + case 2: + message.prove = reader.bool(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedNullifiersRequestV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} GetShieldedNullifiersRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedNullifiersRequestV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedNullifiersRequestV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedNullifiersRequestV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.nullifiers != null && message.hasOwnProperty("nullifiers")) { + if (!Array.isArray(message.nullifiers)) + return "nullifiers: array expected"; + for (var i = 0; i < message.nullifiers.length; ++i) + if (!(message.nullifiers[i] && typeof message.nullifiers[i].length === "number" || $util.isString(message.nullifiers[i]))) + return "nullifiers: buffer[] expected"; + } + if (message.prove != null && message.hasOwnProperty("prove")) + if (typeof message.prove !== "boolean") + return "prove: boolean expected"; + return null; + }; + + /** + * Creates a GetShieldedNullifiersRequestV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} GetShieldedNullifiersRequestV0 + */ + GetShieldedNullifiersRequestV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0(); + if (object.nullifiers) { + if (!Array.isArray(object.nullifiers)) + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.nullifiers: array expected"); + message.nullifiers = []; + for (var i = 0; i < object.nullifiers.length; ++i) + if (typeof object.nullifiers[i] === "string") + $util.base64.decode(object.nullifiers[i], message.nullifiers[i] = $util.newBuffer($util.base64.length(object.nullifiers[i])), 0); + else if (object.nullifiers[i].length >= 0) + message.nullifiers[i] = object.nullifiers[i]; + } + if (object.prove != null) + message.prove = Boolean(object.prove); + return message; + }; + + /** + * Creates a plain object from a GetShieldedNullifiersRequestV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} message GetShieldedNullifiersRequestV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedNullifiersRequestV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.nullifiers = []; + if (options.defaults) + object.prove = false; + if (message.nullifiers && message.nullifiers.length) { + object.nullifiers = []; + for (var j = 0; j < message.nullifiers.length; ++j) + object.nullifiers[j] = options.bytes === String ? $util.base64.encode(message.nullifiers[j], 0, message.nullifiers[j].length) : options.bytes === Array ? Array.prototype.slice.call(message.nullifiers[j]) : message.nullifiers[j]; + } + if (message.prove != null && message.hasOwnProperty("prove")) + object.prove = message.prove; + return object; + }; + + /** + * Converts this GetShieldedNullifiersRequestV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 + * @instance + * @returns {Object.} JSON object + */ + GetShieldedNullifiersRequestV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetShieldedNullifiersRequestV0; + })(); + + return GetShieldedNullifiersRequest; + })(); + + v0.GetShieldedNullifiersResponse = (function() { + + /** + * Properties of a GetShieldedNullifiersResponse. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetShieldedNullifiersResponse + * @property {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.IGetShieldedNullifiersResponseV0|null} [v0] GetShieldedNullifiersResponse v0 + */ + + /** + * Constructs a new GetShieldedNullifiersResponse. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetShieldedNullifiersResponse. + * @implements IGetShieldedNullifiersResponse + * @constructor + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersResponse=} [properties] Properties to set + */ + function GetShieldedNullifiersResponse(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedNullifiersResponse v0. + * @member {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.IGetShieldedNullifiersResponseV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @instance + */ + GetShieldedNullifiersResponse.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedNullifiersResponse version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @instance + */ + Object.defineProperty(GetShieldedNullifiersResponse.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedNullifiersResponse instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersResponse=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} GetShieldedNullifiersResponse instance + */ + GetShieldedNullifiersResponse.create = function create(properties) { + return new GetShieldedNullifiersResponse(properties); + }; + + /** + * Encodes the specified GetShieldedNullifiersResponse message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersResponse} message GetShieldedNullifiersResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedNullifiersResponse.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedNullifiersResponse message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetShieldedNullifiersResponse} message GetShieldedNullifiersResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedNullifiersResponse.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedNullifiersResponse message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} GetShieldedNullifiersResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedNullifiersResponse.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedNullifiersResponse message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} GetShieldedNullifiersResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedNullifiersResponse.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedNullifiersResponse message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedNullifiersResponse.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetShieldedNullifiersResponse message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} GetShieldedNullifiersResponse + */ + GetShieldedNullifiersResponse.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedNullifiersResponse message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} message GetShieldedNullifiersResponse + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedNullifiersResponse.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetShieldedNullifiersResponse to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @instance + * @returns {Object.} JSON object + */ + GetShieldedNullifiersResponse.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 = (function() { + + /** + * Properties of a GetShieldedNullifiersResponseV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @interface IGetShieldedNullifiersResponseV0 + * @property {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatuses|null} [nullifierStatuses] GetShieldedNullifiersResponseV0 nullifierStatuses + * @property {org.dash.platform.dapi.v0.IProof|null} [proof] GetShieldedNullifiersResponseV0 proof + * @property {org.dash.platform.dapi.v0.IResponseMetadata|null} [metadata] GetShieldedNullifiersResponseV0 metadata + */ + + /** + * Constructs a new GetShieldedNullifiersResponseV0. + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse + * @classdesc Represents a GetShieldedNullifiersResponseV0. + * @implements IGetShieldedNullifiersResponseV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.IGetShieldedNullifiersResponseV0=} [properties] Properties to set + */ + function GetShieldedNullifiersResponseV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetShieldedNullifiersResponseV0 nullifierStatuses. + * @member {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatuses|null|undefined} nullifierStatuses + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @instance + */ + GetShieldedNullifiersResponseV0.prototype.nullifierStatuses = null; + + /** + * GetShieldedNullifiersResponseV0 proof. + * @member {org.dash.platform.dapi.v0.IProof|null|undefined} proof + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @instance + */ + GetShieldedNullifiersResponseV0.prototype.proof = null; + + /** + * GetShieldedNullifiersResponseV0 metadata. + * @member {org.dash.platform.dapi.v0.IResponseMetadata|null|undefined} metadata + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @instance + */ + GetShieldedNullifiersResponseV0.prototype.metadata = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetShieldedNullifiersResponseV0 result. + * @member {"nullifierStatuses"|"proof"|undefined} result + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @instance + */ + Object.defineProperty(GetShieldedNullifiersResponseV0.prototype, "result", { + get: $util.oneOfGetter($oneOfFields = ["nullifierStatuses", "proof"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetShieldedNullifiersResponseV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.IGetShieldedNullifiersResponseV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} GetShieldedNullifiersResponseV0 instance + */ + GetShieldedNullifiersResponseV0.create = function create(properties) { + return new GetShieldedNullifiersResponseV0(properties); + }; + + /** + * Encodes the specified GetShieldedNullifiersResponseV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.IGetShieldedNullifiersResponseV0} message GetShieldedNullifiersResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedNullifiersResponseV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.nullifierStatuses != null && Object.hasOwnProperty.call(message, "nullifierStatuses")) + $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.encode(message.nullifierStatuses, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + if (message.proof != null && Object.hasOwnProperty.call(message, "proof")) + $root.org.dash.platform.dapi.v0.Proof.encode(message.proof, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + if (message.metadata != null && Object.hasOwnProperty.call(message, "metadata")) + $root.org.dash.platform.dapi.v0.ResponseMetadata.encode(message.metadata, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetShieldedNullifiersResponseV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.IGetShieldedNullifiersResponseV0} message GetShieldedNullifiersResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetShieldedNullifiersResponseV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetShieldedNullifiersResponseV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} GetShieldedNullifiersResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedNullifiersResponseV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.nullifierStatuses = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.decode(reader, reader.uint32()); + break; + case 2: + message.proof = $root.org.dash.platform.dapi.v0.Proof.decode(reader, reader.uint32()); + break; + case 3: + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetShieldedNullifiersResponseV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} GetShieldedNullifiersResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetShieldedNullifiersResponseV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetShieldedNullifiersResponseV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetShieldedNullifiersResponseV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.nullifierStatuses != null && message.hasOwnProperty("nullifierStatuses")) { + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.verify(message.nullifierStatuses); + if (error) + return "nullifierStatuses." + error; + } + } + if (message.proof != null && message.hasOwnProperty("proof")) { + if (properties.result === 1) + return "result: multiple values"; + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.Proof.verify(message.proof); + if (error) + return "proof." + error; + } + } + if (message.metadata != null && message.hasOwnProperty("metadata")) { + var error = $root.org.dash.platform.dapi.v0.ResponseMetadata.verify(message.metadata); + if (error) + return "metadata." + error; + } + return null; + }; + + /** + * Creates a GetShieldedNullifiersResponseV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} GetShieldedNullifiersResponseV0 + */ + GetShieldedNullifiersResponseV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0(); + if (object.nullifierStatuses != null) { + if (typeof object.nullifierStatuses !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.nullifierStatuses: object expected"); + message.nullifierStatuses = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.fromObject(object.nullifierStatuses); + } + if (object.proof != null) { + if (typeof object.proof !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.proof: object expected"); + message.proof = $root.org.dash.platform.dapi.v0.Proof.fromObject(object.proof); + } + if (object.metadata != null) { + if (typeof object.metadata !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.metadata: object expected"); + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.fromObject(object.metadata); + } + return message; + }; + + /** + * Creates a plain object from a GetShieldedNullifiersResponseV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} message GetShieldedNullifiersResponseV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetShieldedNullifiersResponseV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.metadata = null; + if (message.nullifierStatuses != null && message.hasOwnProperty("nullifierStatuses")) { + object.nullifierStatuses = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.toObject(message.nullifierStatuses, options); + if (options.oneofs) + object.result = "nullifierStatuses"; + } + if (message.proof != null && message.hasOwnProperty("proof")) { + object.proof = $root.org.dash.platform.dapi.v0.Proof.toObject(message.proof, options); + if (options.oneofs) + object.result = "proof"; + } + if (message.metadata != null && message.hasOwnProperty("metadata")) + object.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.toObject(message.metadata, options); + return object; + }; + + /** + * Converts this GetShieldedNullifiersResponseV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @instance + * @returns {Object.} JSON object + */ + GetShieldedNullifiersResponseV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetShieldedNullifiersResponseV0.NullifierStatus = (function() { + + /** + * Properties of a NullifierStatus. + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @interface INullifierStatus + * @property {Uint8Array|null} [nullifier] NullifierStatus nullifier + * @property {boolean|null} [isSpent] NullifierStatus isSpent + */ + + /** + * Constructs a new NullifierStatus. + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @classdesc Represents a NullifierStatus. + * @implements INullifierStatus + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatus=} [properties] Properties to set + */ + function NullifierStatus(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * NullifierStatus nullifier. + * @member {Uint8Array} nullifier + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @instance + */ + NullifierStatus.prototype.nullifier = $util.newBuffer([]); + + /** + * NullifierStatus isSpent. + * @member {boolean} isSpent + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @instance + */ + NullifierStatus.prototype.isSpent = false; + + /** + * Creates a new NullifierStatus instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatus=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} NullifierStatus instance + */ + NullifierStatus.create = function create(properties) { + return new NullifierStatus(properties); + }; + + /** + * Encodes the specified NullifierStatus message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatus} message NullifierStatus message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + NullifierStatus.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.nullifier != null && Object.hasOwnProperty.call(message, "nullifier")) + writer.uint32(/* id 1, wireType 2 =*/10).bytes(message.nullifier); + if (message.isSpent != null && Object.hasOwnProperty.call(message, "isSpent")) + writer.uint32(/* id 2, wireType 0 =*/16).bool(message.isSpent); + return writer; + }; + + /** + * Encodes the specified NullifierStatus message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatus} message NullifierStatus message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + NullifierStatus.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a NullifierStatus message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} NullifierStatus + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + NullifierStatus.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.nullifier = reader.bytes(); + break; + case 2: + message.isSpent = reader.bool(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a NullifierStatus message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} NullifierStatus + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + NullifierStatus.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a NullifierStatus message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + NullifierStatus.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.nullifier != null && message.hasOwnProperty("nullifier")) + if (!(message.nullifier && typeof message.nullifier.length === "number" || $util.isString(message.nullifier))) + return "nullifier: buffer expected"; + if (message.isSpent != null && message.hasOwnProperty("isSpent")) + if (typeof message.isSpent !== "boolean") + return "isSpent: boolean expected"; + return null; + }; + + /** + * Creates a NullifierStatus message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} NullifierStatus + */ + NullifierStatus.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus(); + if (object.nullifier != null) + if (typeof object.nullifier === "string") + $util.base64.decode(object.nullifier, message.nullifier = $util.newBuffer($util.base64.length(object.nullifier)), 0); + else if (object.nullifier.length >= 0) + message.nullifier = object.nullifier; + if (object.isSpent != null) + message.isSpent = Boolean(object.isSpent); + return message; + }; + + /** + * Creates a plain object from a NullifierStatus message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} message NullifierStatus + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + NullifierStatus.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + if (options.bytes === String) + object.nullifier = ""; + else { + object.nullifier = []; + if (options.bytes !== Array) + object.nullifier = $util.newBuffer(object.nullifier); + } + object.isSpent = false; + } + if (message.nullifier != null && message.hasOwnProperty("nullifier")) + object.nullifier = options.bytes === String ? $util.base64.encode(message.nullifier, 0, message.nullifier.length) : options.bytes === Array ? Array.prototype.slice.call(message.nullifier) : message.nullifier; + if (message.isSpent != null && message.hasOwnProperty("isSpent")) + object.isSpent = message.isSpent; + return object; + }; + + /** + * Converts this NullifierStatus to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus + * @instance + * @returns {Object.} JSON object + */ + NullifierStatus.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return NullifierStatus; + })(); + + GetShieldedNullifiersResponseV0.NullifierStatuses = (function() { + + /** + * Properties of a NullifierStatuses. + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @interface INullifierStatuses + * @property {Array.|null} [entries] NullifierStatuses entries + */ + + /** + * Constructs a new NullifierStatuses. + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 + * @classdesc Represents a NullifierStatuses. + * @implements INullifierStatuses + * @constructor + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatuses=} [properties] Properties to set + */ + function NullifierStatuses(properties) { + this.entries = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * NullifierStatuses entries. + * @member {Array.} entries + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @instance + */ + NullifierStatuses.prototype.entries = $util.emptyArray; + + /** + * Creates a new NullifierStatuses instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatuses=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} NullifierStatuses instance + */ + NullifierStatuses.create = function create(properties) { + return new NullifierStatuses(properties); + }; + + /** + * Encodes the specified NullifierStatuses message. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatuses} message NullifierStatuses message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + NullifierStatuses.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.entries != null && message.entries.length) + for (var i = 0; i < message.entries.length; ++i) + $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.encode(message.entries[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified NullifierStatuses message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.INullifierStatuses} message NullifierStatuses message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + NullifierStatuses.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a NullifierStatuses message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} NullifierStatuses + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + NullifierStatuses.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (!(message.entries && message.entries.length)) + message.entries = []; + message.entries.push($root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.decode(reader, reader.uint32())); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a NullifierStatuses message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} NullifierStatuses + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + NullifierStatuses.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a NullifierStatuses message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + NullifierStatuses.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.entries != null && message.hasOwnProperty("entries")) { + if (!Array.isArray(message.entries)) + return "entries: array expected"; + for (var i = 0; i < message.entries.length; ++i) { + var error = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.verify(message.entries[i]); + if (error) + return "entries." + error; + } + } + return null; + }; + + /** + * Creates a NullifierStatuses message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} NullifierStatuses + */ + NullifierStatuses.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses(); + if (object.entries) { + if (!Array.isArray(object.entries)) + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.entries: array expected"); + message.entries = []; + for (var i = 0; i < object.entries.length; ++i) { + if (typeof object.entries[i] !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.entries: object expected"); + message.entries[i] = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.fromObject(object.entries[i]); + } + } + return message; + }; + + /** + * Creates a plain object from a NullifierStatuses message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @static + * @param {org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} message NullifierStatuses + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + NullifierStatuses.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.entries = []; + if (message.entries && message.entries.length) { + object.entries = []; + for (var j = 0; j < message.entries.length; ++j) + object.entries[j] = $root.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.toObject(message.entries[j], options); + } + return object; + }; + + /** + * Converts this NullifierStatuses to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses + * @instance + * @returns {Object.} JSON object + */ + NullifierStatuses.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return NullifierStatuses; + })(); + + return GetShieldedNullifiersResponseV0; + })(); + + return GetShieldedNullifiersResponse; + })(); + return v0; })(); diff --git a/packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js b/packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js index 046bd95f81c..f38425b23af 100644 --- a/packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js +++ b/packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js @@ -418,6 +418,39 @@ goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBala goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0.ResultCase', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.ResultCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.ResultCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.ResultCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.ResultCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.VersionCase', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetStatusRequest', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetStatusRequest.GetStatusRequestV0', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetStatusRequest.VersionCase', null, { proto }); @@ -7604,6 +7637,447 @@ if (goog.DEBUG && !COMPILED) { */ proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0.displayName = 'proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.repeatedFields_, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.repeatedFields_, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.repeatedFields_, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.repeatedFields_, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses'; +} @@ -79673,6 +80147,4079 @@ proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse. }; + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest; + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.toObject = function(includeInstance, msg) { + var f, obj = { + startIndex: jspb.Message.getFieldWithDefault(msg, 1, 0), + count: jspb.Message.getFieldWithDefault(msg, 2, 0), + prove: jspb.Message.getBooleanFieldWithDefault(msg, 3, false) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0; + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readUint64()); + msg.setStartIndex(value); + break; + case 2: + var value = /** @type {number} */ (reader.readUint32()); + msg.setCount(value); + break; + case 3: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setProve(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getStartIndex(); + if (f !== 0) { + writer.writeUint64( + 1, + f + ); + } + f = message.getCount(); + if (f !== 0) { + writer.writeUint32( + 2, + f + ); + } + f = message.getProve(); + if (f) { + writer.writeBool( + 3, + f + ); + } +}; + + +/** + * optional uint64 start_index = 1; + * @return {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.prototype.getStartIndex = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.prototype.setStartIndex = function(value) { + return jspb.Message.setProto3IntField(this, 1, value); +}; + + +/** + * optional uint32 count = 2; + * @return {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.prototype.getCount = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.prototype.setCount = function(value) { + return jspb.Message.setProto3IntField(this, 2, value); +}; + + +/** + * optional bool prove = 3; + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.prototype.getProve = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 3, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.prototype.setProve = function(value) { + return jspb.Message.setProto3BooleanField(this, 3, value); +}; + + +/** + * optional GetShieldedEncryptedNotesRequestV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse; + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.serializeBinaryToWriter + ); + } +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.oneofGroups_ = [[1,2]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.ResultCase = { + RESULT_NOT_SET: 0, + ENCRYPTED_NOTES: 1, + PROOF: 2 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.ResultCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.getResultCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.ResultCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.toObject = function(includeInstance, msg) { + var f, obj = { + encryptedNotes: (f = msg.getEncryptedNotes()) && proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.toObject(includeInstance, f), + proof: (f = msg.getProof()) && proto.org.dash.platform.dapi.v0.Proof.toObject(includeInstance, f), + metadata: (f = msg.getMetadata()) && proto.org.dash.platform.dapi.v0.ResponseMetadata.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0; + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.deserializeBinaryFromReader); + msg.setEncryptedNotes(value); + break; + case 2: + var value = new proto.org.dash.platform.dapi.v0.Proof; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.Proof.deserializeBinaryFromReader); + msg.setProof(value); + break; + case 3: + var value = new proto.org.dash.platform.dapi.v0.ResponseMetadata; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.ResponseMetadata.deserializeBinaryFromReader); + msg.setMetadata(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getEncryptedNotes(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.serializeBinaryToWriter + ); + } + f = message.getProof(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.org.dash.platform.dapi.v0.Proof.serializeBinaryToWriter + ); + } + f = message.getMetadata(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.org.dash.platform.dapi.v0.ResponseMetadata.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.toObject = function(includeInstance, msg) { + var f, obj = { + cmx: msg.getCmx_asB64(), + encryptedNote: msg.getEncryptedNote_asB64() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote; + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setCmx(value); + break; + case 2: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setEncryptedNote(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getCmx_asU8(); + if (f.length > 0) { + writer.writeBytes( + 1, + f + ); + } + f = message.getEncryptedNote_asU8(); + if (f.length > 0) { + writer.writeBytes( + 2, + f + ); + } +}; + + +/** + * optional bytes cmx = 1; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getCmx = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * optional bytes cmx = 1; + * This is a type-conversion wrapper around `getCmx()` + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getCmx_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getCmx())); +}; + + +/** + * optional bytes cmx = 1; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getCmx()` + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getCmx_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getCmx())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.setCmx = function(value) { + return jspb.Message.setProto3BytesField(this, 1, value); +}; + + +/** + * optional bytes encrypted_note = 2; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getEncryptedNote = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * optional bytes encrypted_note = 2; + * This is a type-conversion wrapper around `getEncryptedNote()` + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getEncryptedNote_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getEncryptedNote())); +}; + + +/** + * optional bytes encrypted_note = 2; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getEncryptedNote()` + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getEncryptedNote_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getEncryptedNote())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.setEncryptedNote = function(value) { + return jspb.Message.setProto3BytesField(this, 2, value); +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.toObject = function(includeInstance, msg) { + var f, obj = { + entriesList: jspb.Message.toObjectList(msg.getEntriesList(), + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.toObject, includeInstance) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes; + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.deserializeBinaryFromReader); + msg.addEntries(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getEntriesList(); + if (f.length > 0) { + writer.writeRepeatedMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.serializeBinaryToWriter + ); + } +}; + + +/** + * repeated EncryptedNote entries = 1; + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.prototype.getEntriesList = function() { + return /** @type{!Array} */ ( + jspb.Message.getRepeatedWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote, 1)); +}; + + +/** + * @param {!Array} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.prototype.setEntriesList = function(value) { + return jspb.Message.setRepeatedWrapperField(this, 1, value); +}; + + +/** + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote=} opt_value + * @param {number=} opt_index + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.prototype.addEntries = function(opt_value, opt_index) { + return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.prototype.clearEntriesList = function() { + return this.setEntriesList([]); +}; + + +/** + * optional EncryptedNotes encrypted_notes = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.getEncryptedNotes = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.setEncryptedNotes = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.clearEncryptedNotes = function() { + return this.setEncryptedNotes(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.hasEncryptedNotes = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional Proof proof = 2; + * @return {?proto.org.dash.platform.dapi.v0.Proof} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.getProof = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.Proof} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.Proof, 2)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.Proof|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.setProof = function(value) { + return jspb.Message.setOneofWrapperField(this, 2, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.clearProof = function() { + return this.setProof(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.hasProof = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional ResponseMetadata metadata = 3; + * @return {?proto.org.dash.platform.dapi.v0.ResponseMetadata} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.getMetadata = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.ResponseMetadata} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.ResponseMetadata, 3)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.ResponseMetadata|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.setMetadata = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.clearMetadata = function() { + return this.setMetadata(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.hasMetadata = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional GetShieldedEncryptedNotesResponseV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest; + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.toObject = function(includeInstance, msg) { + var f, obj = { + prove: jspb.Message.getBooleanFieldWithDefault(msg, 1, false) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0; + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setProve(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getProve(); + if (f) { + writer.writeBool( + 1, + f + ); + } +}; + + +/** + * optional bool prove = 1; + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.prototype.getProve = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 1, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.prototype.setProve = function(value) { + return jspb.Message.setProto3BooleanField(this, 1, value); +}; + + +/** + * optional GetShieldedAnchorsRequestV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse; + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.serializeBinaryToWriter + ); + } +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.oneofGroups_ = [[1,2]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.ResultCase = { + RESULT_NOT_SET: 0, + ANCHORS: 1, + PROOF: 2 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.ResultCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.getResultCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.ResultCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.toObject = function(includeInstance, msg) { + var f, obj = { + anchors: (f = msg.getAnchors()) && proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.toObject(includeInstance, f), + proof: (f = msg.getProof()) && proto.org.dash.platform.dapi.v0.Proof.toObject(includeInstance, f), + metadata: (f = msg.getMetadata()) && proto.org.dash.platform.dapi.v0.ResponseMetadata.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0; + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.deserializeBinaryFromReader); + msg.setAnchors(value); + break; + case 2: + var value = new proto.org.dash.platform.dapi.v0.Proof; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.Proof.deserializeBinaryFromReader); + msg.setProof(value); + break; + case 3: + var value = new proto.org.dash.platform.dapi.v0.ResponseMetadata; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.ResponseMetadata.deserializeBinaryFromReader); + msg.setMetadata(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getAnchors(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.serializeBinaryToWriter + ); + } + f = message.getProof(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.org.dash.platform.dapi.v0.Proof.serializeBinaryToWriter + ); + } + f = message.getMetadata(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.org.dash.platform.dapi.v0.ResponseMetadata.serializeBinaryToWriter + ); + } +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.toObject = function(includeInstance, msg) { + var f, obj = { + anchorsList: msg.getAnchorsList_asB64() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors; + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.addAnchors(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getAnchorsList_asU8(); + if (f.length > 0) { + writer.writeRepeatedBytes( + 1, + f + ); + } +}; + + +/** + * repeated bytes anchors = 1; + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.prototype.getAnchorsList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 1)); +}; + + +/** + * repeated bytes anchors = 1; + * This is a type-conversion wrapper around `getAnchorsList()` + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.prototype.getAnchorsList_asB64 = function() { + return /** @type {!Array} */ (jspb.Message.bytesListAsB64( + this.getAnchorsList())); +}; + + +/** + * repeated bytes anchors = 1; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getAnchorsList()` + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.prototype.getAnchorsList_asU8 = function() { + return /** @type {!Array} */ (jspb.Message.bytesListAsU8( + this.getAnchorsList())); +}; + + +/** + * @param {!(Array|Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.prototype.setAnchorsList = function(value) { + return jspb.Message.setField(this, 1, value || []); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @param {number=} opt_index + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.prototype.addAnchors = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 1, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.prototype.clearAnchorsList = function() { + return this.setAnchorsList([]); +}; + + +/** + * optional Anchors anchors = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.getAnchors = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.setAnchors = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.clearAnchors = function() { + return this.setAnchors(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.hasAnchors = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional Proof proof = 2; + * @return {?proto.org.dash.platform.dapi.v0.Proof} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.getProof = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.Proof} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.Proof, 2)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.Proof|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.setProof = function(value) { + return jspb.Message.setOneofWrapperField(this, 2, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.clearProof = function() { + return this.setProof(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.hasProof = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional ResponseMetadata metadata = 3; + * @return {?proto.org.dash.platform.dapi.v0.ResponseMetadata} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.getMetadata = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.ResponseMetadata} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.ResponseMetadata, 3)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.ResponseMetadata|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.setMetadata = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.clearMetadata = function() { + return this.setMetadata(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.hasMetadata = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional GetShieldedAnchorsResponseV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest; + return proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.toObject = function(includeInstance, msg) { + var f, obj = { + prove: jspb.Message.getBooleanFieldWithDefault(msg, 1, false) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0; + return proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setProve(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getProve(); + if (f) { + writer.writeBool( + 1, + f + ); + } +}; + + +/** + * optional bool prove = 1; + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.prototype.getProve = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 1, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.prototype.setProve = function(value) { + return jspb.Message.setProto3BooleanField(this, 1, value); +}; + + +/** + * optional GetShieldedPoolStateRequestV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse; + return proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.serializeBinaryToWriter + ); + } +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.oneofGroups_ = [[1,2]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.ResultCase = { + RESULT_NOT_SET: 0, + TOTAL_BALANCE: 1, + PROOF: 2 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.ResultCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.getResultCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.ResultCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.toObject = function(includeInstance, msg) { + var f, obj = { + totalBalance: jspb.Message.getFieldWithDefault(msg, 1, "0"), + proof: (f = msg.getProof()) && proto.org.dash.platform.dapi.v0.Proof.toObject(includeInstance, f), + metadata: (f = msg.getMetadata()) && proto.org.dash.platform.dapi.v0.ResponseMetadata.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0; + return proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setTotalBalance(value); + break; + case 2: + var value = new proto.org.dash.platform.dapi.v0.Proof; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.Proof.deserializeBinaryFromReader); + msg.setProof(value); + break; + case 3: + var value = new proto.org.dash.platform.dapi.v0.ResponseMetadata; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.ResponseMetadata.deserializeBinaryFromReader); + msg.setMetadata(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = /** @type {string} */ (jspb.Message.getField(message, 1)); + if (f != null) { + writer.writeUint64String( + 1, + f + ); + } + f = message.getProof(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.org.dash.platform.dapi.v0.Proof.serializeBinaryToWriter + ); + } + f = message.getMetadata(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.org.dash.platform.dapi.v0.ResponseMetadata.serializeBinaryToWriter + ); + } +}; + + +/** + * optional uint64 total_balance = 1; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.getTotalBalance = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.setTotalBalance = function(value) { + return jspb.Message.setOneofField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.clearTotalBalance = function() { + return jspb.Message.setOneofField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.oneofGroups_[0], undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.hasTotalBalance = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional Proof proof = 2; + * @return {?proto.org.dash.platform.dapi.v0.Proof} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.getProof = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.Proof} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.Proof, 2)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.Proof|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.setProof = function(value) { + return jspb.Message.setOneofWrapperField(this, 2, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.clearProof = function() { + return this.setProof(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.hasProof = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional ResponseMetadata metadata = 3; + * @return {?proto.org.dash.platform.dapi.v0.ResponseMetadata} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.getMetadata = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.ResponseMetadata} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.ResponseMetadata, 3)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.ResponseMetadata|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.setMetadata = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.clearMetadata = function() { + return this.setMetadata(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.hasMetadata = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional GetShieldedPoolStateResponseV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest; + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.serializeBinaryToWriter + ); + } +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.toObject = function(includeInstance, msg) { + var f, obj = { + nullifiersList: msg.getNullifiersList_asB64(), + prove: jspb.Message.getBooleanFieldWithDefault(msg, 2, false) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0; + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.addNullifiers(value); + break; + case 2: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setProve(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getNullifiersList_asU8(); + if (f.length > 0) { + writer.writeRepeatedBytes( + 1, + f + ); + } + f = message.getProve(); + if (f) { + writer.writeBool( + 2, + f + ); + } +}; + + +/** + * repeated bytes nullifiers = 1; + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.getNullifiersList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 1)); +}; + + +/** + * repeated bytes nullifiers = 1; + * This is a type-conversion wrapper around `getNullifiersList()` + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.getNullifiersList_asB64 = function() { + return /** @type {!Array} */ (jspb.Message.bytesListAsB64( + this.getNullifiersList())); +}; + + +/** + * repeated bytes nullifiers = 1; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getNullifiersList()` + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.getNullifiersList_asU8 = function() { + return /** @type {!Array} */ (jspb.Message.bytesListAsU8( + this.getNullifiersList())); +}; + + +/** + * @param {!(Array|Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.setNullifiersList = function(value) { + return jspb.Message.setField(this, 1, value || []); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @param {number=} opt_index + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.addNullifiers = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 1, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.clearNullifiersList = function() { + return this.setNullifiersList([]); +}; + + +/** + * optional bool prove = 2; + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.getProve = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 2, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.setProve = function(value) { + return jspb.Message.setProto3BooleanField(this, 2, value); +}; + + +/** + * optional GetShieldedNullifiersRequestV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse; + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.serializeBinaryToWriter + ); + } +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.oneofGroups_ = [[1,2]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.ResultCase = { + RESULT_NOT_SET: 0, + NULLIFIER_STATUSES: 1, + PROOF: 2 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.ResultCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.getResultCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.ResultCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.toObject = function(includeInstance, msg) { + var f, obj = { + nullifierStatuses: (f = msg.getNullifierStatuses()) && proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.toObject(includeInstance, f), + proof: (f = msg.getProof()) && proto.org.dash.platform.dapi.v0.Proof.toObject(includeInstance, f), + metadata: (f = msg.getMetadata()) && proto.org.dash.platform.dapi.v0.ResponseMetadata.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0; + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.deserializeBinaryFromReader); + msg.setNullifierStatuses(value); + break; + case 2: + var value = new proto.org.dash.platform.dapi.v0.Proof; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.Proof.deserializeBinaryFromReader); + msg.setProof(value); + break; + case 3: + var value = new proto.org.dash.platform.dapi.v0.ResponseMetadata; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.ResponseMetadata.deserializeBinaryFromReader); + msg.setMetadata(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getNullifierStatuses(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.serializeBinaryToWriter + ); + } + f = message.getProof(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.org.dash.platform.dapi.v0.Proof.serializeBinaryToWriter + ); + } + f = message.getMetadata(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.org.dash.platform.dapi.v0.ResponseMetadata.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.toObject = function(includeInstance, msg) { + var f, obj = { + nullifier: msg.getNullifier_asB64(), + isSpent: jspb.Message.getBooleanFieldWithDefault(msg, 2, false) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus; + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setNullifier(value); + break; + case 2: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setIsSpent(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getNullifier_asU8(); + if (f.length > 0) { + writer.writeBytes( + 1, + f + ); + } + f = message.getIsSpent(); + if (f) { + writer.writeBool( + 2, + f + ); + } +}; + + +/** + * optional bytes nullifier = 1; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.prototype.getNullifier = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * optional bytes nullifier = 1; + * This is a type-conversion wrapper around `getNullifier()` + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.prototype.getNullifier_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getNullifier())); +}; + + +/** + * optional bytes nullifier = 1; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getNullifier()` + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.prototype.getNullifier_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getNullifier())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.prototype.setNullifier = function(value) { + return jspb.Message.setProto3BytesField(this, 1, value); +}; + + +/** + * optional bool is_spent = 2; + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.prototype.getIsSpent = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 2, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.prototype.setIsSpent = function(value) { + return jspb.Message.setProto3BooleanField(this, 2, value); +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.toObject = function(includeInstance, msg) { + var f, obj = { + entriesList: jspb.Message.toObjectList(msg.getEntriesList(), + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.toObject, includeInstance) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses; + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.deserializeBinaryFromReader); + msg.addEntries(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getEntriesList(); + if (f.length > 0) { + writer.writeRepeatedMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.serializeBinaryToWriter + ); + } +}; + + +/** + * repeated NullifierStatus entries = 1; + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.prototype.getEntriesList = function() { + return /** @type{!Array} */ ( + jspb.Message.getRepeatedWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus, 1)); +}; + + +/** + * @param {!Array} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.prototype.setEntriesList = function(value) { + return jspb.Message.setRepeatedWrapperField(this, 1, value); +}; + + +/** + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus=} opt_value + * @param {number=} opt_index + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.prototype.addEntries = function(opt_value, opt_index) { + return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.prototype.clearEntriesList = function() { + return this.setEntriesList([]); +}; + + +/** + * optional NullifierStatuses nullifier_statuses = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.getNullifierStatuses = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.setNullifierStatuses = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.clearNullifierStatuses = function() { + return this.setNullifierStatuses(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.hasNullifierStatuses = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional Proof proof = 2; + * @return {?proto.org.dash.platform.dapi.v0.Proof} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.getProof = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.Proof} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.Proof, 2)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.Proof|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.setProof = function(value) { + return jspb.Message.setOneofWrapperField(this, 2, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.clearProof = function() { + return this.setProof(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.hasProof = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional ResponseMetadata metadata = 3; + * @return {?proto.org.dash.platform.dapi.v0.ResponseMetadata} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.getMetadata = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.ResponseMetadata} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.ResponseMetadata, 3)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.ResponseMetadata|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.setMetadata = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.clearMetadata = function() { + return this.setMetadata(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.hasMetadata = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional GetShieldedNullifiersResponseV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + /** * @enum {number} */ diff --git a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h index 2a523e8267c..45b217f446f 100644 --- a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h +++ b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h @@ -204,6 +204,19 @@ CF_EXTERN_C_BEGIN @class GetRecentAddressBalanceChangesResponse_GetRecentAddressBalanceChangesResponseV0; @class GetRecentCompactedAddressBalanceChangesRequest_GetRecentCompactedAddressBalanceChangesRequestV0; @class GetRecentCompactedAddressBalanceChangesResponse_GetRecentCompactedAddressBalanceChangesResponseV0; +@class GetShieldedAnchorsRequest_GetShieldedAnchorsRequestV0; +@class GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0; +@class GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Anchors; +@class GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0; +@class GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0; +@class GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote; +@class GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNotes; +@class GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0; +@class GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0; +@class GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatus; +@class GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatuses; +@class GetShieldedPoolStateRequest_GetShieldedPoolStateRequestV0; +@class GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0; @class GetStatusRequest_GetStatusRequestV0; @class GetStatusResponse_GetStatusResponseV0; @class GetStatusResponse_GetStatusResponseV0_Chain; @@ -8548,6 +8561,461 @@ GPB_FINAL @interface GetRecentCompactedAddressBalanceChangesResponse_GetRecentCo **/ void GetRecentCompactedAddressBalanceChangesResponse_GetRecentCompactedAddressBalanceChangesResponseV0_ClearResultOneOfCase(GetRecentCompactedAddressBalanceChangesResponse_GetRecentCompactedAddressBalanceChangesResponseV0 *message); +#pragma mark - GetShieldedEncryptedNotesRequest + +typedef GPB_ENUM(GetShieldedEncryptedNotesRequest_FieldNumber) { + GetShieldedEncryptedNotesRequest_FieldNumber_V0 = 1, +}; + +typedef GPB_ENUM(GetShieldedEncryptedNotesRequest_Version_OneOfCase) { + GetShieldedEncryptedNotesRequest_Version_OneOfCase_GPBUnsetOneOfCase = 0, + GetShieldedEncryptedNotesRequest_Version_OneOfCase_V0 = 1, +}; + +GPB_FINAL @interface GetShieldedEncryptedNotesRequest : GPBMessage + +@property(nonatomic, readonly) GetShieldedEncryptedNotesRequest_Version_OneOfCase versionOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0 *v0; + +@end + +/** + * Clears whatever value was set for the oneof 'version'. + **/ +void GetShieldedEncryptedNotesRequest_ClearVersionOneOfCase(GetShieldedEncryptedNotesRequest *message); + +#pragma mark - GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0 + +typedef GPB_ENUM(GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0_FieldNumber) { + GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0_FieldNumber_StartIndex = 1, + GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0_FieldNumber_Count = 2, + GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0_FieldNumber_Prove = 3, +}; + +GPB_FINAL @interface GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0 : GPBMessage + +@property(nonatomic, readwrite) uint64_t startIndex; + +@property(nonatomic, readwrite) uint32_t count; + +@property(nonatomic, readwrite) BOOL prove; + +@end + +#pragma mark - GetShieldedEncryptedNotesResponse + +typedef GPB_ENUM(GetShieldedEncryptedNotesResponse_FieldNumber) { + GetShieldedEncryptedNotesResponse_FieldNumber_V0 = 1, +}; + +typedef GPB_ENUM(GetShieldedEncryptedNotesResponse_Version_OneOfCase) { + GetShieldedEncryptedNotesResponse_Version_OneOfCase_GPBUnsetOneOfCase = 0, + GetShieldedEncryptedNotesResponse_Version_OneOfCase_V0 = 1, +}; + +GPB_FINAL @interface GetShieldedEncryptedNotesResponse : GPBMessage + +@property(nonatomic, readonly) GetShieldedEncryptedNotesResponse_Version_OneOfCase versionOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0 *v0; + +@end + +/** + * Clears whatever value was set for the oneof 'version'. + **/ +void GetShieldedEncryptedNotesResponse_ClearVersionOneOfCase(GetShieldedEncryptedNotesResponse *message); + +#pragma mark - GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0 + +typedef GPB_ENUM(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_FieldNumber) { + GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_FieldNumber_EncryptedNotes = 1, + GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_FieldNumber_Proof = 2, + GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_FieldNumber_Metadata = 3, +}; + +typedef GPB_ENUM(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_Result_OneOfCase) { + GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_Result_OneOfCase_GPBUnsetOneOfCase = 0, + GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_Result_OneOfCase_EncryptedNotes = 1, + GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_Result_OneOfCase_Proof = 2, +}; + +GPB_FINAL @interface GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0 : GPBMessage + +@property(nonatomic, readonly) GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_Result_OneOfCase resultOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNotes *encryptedNotes; + +@property(nonatomic, readwrite, strong, null_resettable) Proof *proof; + +@property(nonatomic, readwrite, strong, null_resettable) ResponseMetadata *metadata; +/** Test to see if @c metadata has been set. */ +@property(nonatomic, readwrite) BOOL hasMetadata; + +@end + +/** + * Clears whatever value was set for the oneof 'result'. + **/ +void GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_ClearResultOneOfCase(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0 *message); + +#pragma mark - GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote + +typedef GPB_ENUM(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote_FieldNumber) { + GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote_FieldNumber_Cmx = 1, + GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote_FieldNumber_EncryptedNote = 2, +}; + +GPB_FINAL @interface GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote : GPBMessage + +@property(nonatomic, readwrite, copy, null_resettable) NSData *cmx; + +@property(nonatomic, readwrite, copy, null_resettable) NSData *encryptedNote; + +@end + +#pragma mark - GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNotes + +typedef GPB_ENUM(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNotes_FieldNumber) { + GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNotes_FieldNumber_EntriesArray = 1, +}; + +GPB_FINAL @interface GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNotes : GPBMessage + +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *entriesArray; +/** The number of items in @c entriesArray without causing the array to be created. */ +@property(nonatomic, readonly) NSUInteger entriesArray_Count; + +@end + +#pragma mark - GetShieldedAnchorsRequest + +typedef GPB_ENUM(GetShieldedAnchorsRequest_FieldNumber) { + GetShieldedAnchorsRequest_FieldNumber_V0 = 1, +}; + +typedef GPB_ENUM(GetShieldedAnchorsRequest_Version_OneOfCase) { + GetShieldedAnchorsRequest_Version_OneOfCase_GPBUnsetOneOfCase = 0, + GetShieldedAnchorsRequest_Version_OneOfCase_V0 = 1, +}; + +GPB_FINAL @interface GetShieldedAnchorsRequest : GPBMessage + +@property(nonatomic, readonly) GetShieldedAnchorsRequest_Version_OneOfCase versionOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetShieldedAnchorsRequest_GetShieldedAnchorsRequestV0 *v0; + +@end + +/** + * Clears whatever value was set for the oneof 'version'. + **/ +void GetShieldedAnchorsRequest_ClearVersionOneOfCase(GetShieldedAnchorsRequest *message); + +#pragma mark - GetShieldedAnchorsRequest_GetShieldedAnchorsRequestV0 + +typedef GPB_ENUM(GetShieldedAnchorsRequest_GetShieldedAnchorsRequestV0_FieldNumber) { + GetShieldedAnchorsRequest_GetShieldedAnchorsRequestV0_FieldNumber_Prove = 1, +}; + +GPB_FINAL @interface GetShieldedAnchorsRequest_GetShieldedAnchorsRequestV0 : GPBMessage + +@property(nonatomic, readwrite) BOOL prove; + +@end + +#pragma mark - GetShieldedAnchorsResponse + +typedef GPB_ENUM(GetShieldedAnchorsResponse_FieldNumber) { + GetShieldedAnchorsResponse_FieldNumber_V0 = 1, +}; + +typedef GPB_ENUM(GetShieldedAnchorsResponse_Version_OneOfCase) { + GetShieldedAnchorsResponse_Version_OneOfCase_GPBUnsetOneOfCase = 0, + GetShieldedAnchorsResponse_Version_OneOfCase_V0 = 1, +}; + +GPB_FINAL @interface GetShieldedAnchorsResponse : GPBMessage + +@property(nonatomic, readonly) GetShieldedAnchorsResponse_Version_OneOfCase versionOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0 *v0; + +@end + +/** + * Clears whatever value was set for the oneof 'version'. + **/ +void GetShieldedAnchorsResponse_ClearVersionOneOfCase(GetShieldedAnchorsResponse *message); + +#pragma mark - GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0 + +typedef GPB_ENUM(GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_FieldNumber) { + GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_FieldNumber_Anchors = 1, + GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_FieldNumber_Proof = 2, + GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_FieldNumber_Metadata = 3, +}; + +typedef GPB_ENUM(GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Result_OneOfCase) { + GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Result_OneOfCase_GPBUnsetOneOfCase = 0, + GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Result_OneOfCase_Anchors = 1, + GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Result_OneOfCase_Proof = 2, +}; + +GPB_FINAL @interface GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0 : GPBMessage + +@property(nonatomic, readonly) GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Result_OneOfCase resultOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Anchors *anchors; + +@property(nonatomic, readwrite, strong, null_resettable) Proof *proof; + +@property(nonatomic, readwrite, strong, null_resettable) ResponseMetadata *metadata; +/** Test to see if @c metadata has been set. */ +@property(nonatomic, readwrite) BOOL hasMetadata; + +@end + +/** + * Clears whatever value was set for the oneof 'result'. + **/ +void GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_ClearResultOneOfCase(GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0 *message); + +#pragma mark - GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Anchors + +typedef GPB_ENUM(GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Anchors_FieldNumber) { + GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Anchors_FieldNumber_AnchorsArray = 1, +}; + +GPB_FINAL @interface GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Anchors : GPBMessage + +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *anchorsArray; +/** The number of items in @c anchorsArray without causing the array to be created. */ +@property(nonatomic, readonly) NSUInteger anchorsArray_Count; + +@end + +#pragma mark - GetShieldedPoolStateRequest + +typedef GPB_ENUM(GetShieldedPoolStateRequest_FieldNumber) { + GetShieldedPoolStateRequest_FieldNumber_V0 = 1, +}; + +typedef GPB_ENUM(GetShieldedPoolStateRequest_Version_OneOfCase) { + GetShieldedPoolStateRequest_Version_OneOfCase_GPBUnsetOneOfCase = 0, + GetShieldedPoolStateRequest_Version_OneOfCase_V0 = 1, +}; + +GPB_FINAL @interface GetShieldedPoolStateRequest : GPBMessage + +@property(nonatomic, readonly) GetShieldedPoolStateRequest_Version_OneOfCase versionOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetShieldedPoolStateRequest_GetShieldedPoolStateRequestV0 *v0; + +@end + +/** + * Clears whatever value was set for the oneof 'version'. + **/ +void GetShieldedPoolStateRequest_ClearVersionOneOfCase(GetShieldedPoolStateRequest *message); + +#pragma mark - GetShieldedPoolStateRequest_GetShieldedPoolStateRequestV0 + +typedef GPB_ENUM(GetShieldedPoolStateRequest_GetShieldedPoolStateRequestV0_FieldNumber) { + GetShieldedPoolStateRequest_GetShieldedPoolStateRequestV0_FieldNumber_Prove = 1, +}; + +GPB_FINAL @interface GetShieldedPoolStateRequest_GetShieldedPoolStateRequestV0 : GPBMessage + +@property(nonatomic, readwrite) BOOL prove; + +@end + +#pragma mark - GetShieldedPoolStateResponse + +typedef GPB_ENUM(GetShieldedPoolStateResponse_FieldNumber) { + GetShieldedPoolStateResponse_FieldNumber_V0 = 1, +}; + +typedef GPB_ENUM(GetShieldedPoolStateResponse_Version_OneOfCase) { + GetShieldedPoolStateResponse_Version_OneOfCase_GPBUnsetOneOfCase = 0, + GetShieldedPoolStateResponse_Version_OneOfCase_V0 = 1, +}; + +GPB_FINAL @interface GetShieldedPoolStateResponse : GPBMessage + +@property(nonatomic, readonly) GetShieldedPoolStateResponse_Version_OneOfCase versionOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0 *v0; + +@end + +/** + * Clears whatever value was set for the oneof 'version'. + **/ +void GetShieldedPoolStateResponse_ClearVersionOneOfCase(GetShieldedPoolStateResponse *message); + +#pragma mark - GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0 + +typedef GPB_ENUM(GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0_FieldNumber) { + GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0_FieldNumber_TotalBalance = 1, + GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0_FieldNumber_Proof = 2, + GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0_FieldNumber_Metadata = 3, +}; + +typedef GPB_ENUM(GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0_Result_OneOfCase) { + GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0_Result_OneOfCase_GPBUnsetOneOfCase = 0, + GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0_Result_OneOfCase_TotalBalance = 1, + GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0_Result_OneOfCase_Proof = 2, +}; + +GPB_FINAL @interface GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0 : GPBMessage + +@property(nonatomic, readonly) GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0_Result_OneOfCase resultOneOfCase; + +@property(nonatomic, readwrite) uint64_t totalBalance; + +@property(nonatomic, readwrite, strong, null_resettable) Proof *proof; + +@property(nonatomic, readwrite, strong, null_resettable) ResponseMetadata *metadata; +/** Test to see if @c metadata has been set. */ +@property(nonatomic, readwrite) BOOL hasMetadata; + +@end + +/** + * Clears whatever value was set for the oneof 'result'. + **/ +void GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0_ClearResultOneOfCase(GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0 *message); + +#pragma mark - GetShieldedNullifiersRequest + +typedef GPB_ENUM(GetShieldedNullifiersRequest_FieldNumber) { + GetShieldedNullifiersRequest_FieldNumber_V0 = 1, +}; + +typedef GPB_ENUM(GetShieldedNullifiersRequest_Version_OneOfCase) { + GetShieldedNullifiersRequest_Version_OneOfCase_GPBUnsetOneOfCase = 0, + GetShieldedNullifiersRequest_Version_OneOfCase_V0 = 1, +}; + +GPB_FINAL @interface GetShieldedNullifiersRequest : GPBMessage + +@property(nonatomic, readonly) GetShieldedNullifiersRequest_Version_OneOfCase versionOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0 *v0; + +@end + +/** + * Clears whatever value was set for the oneof 'version'. + **/ +void GetShieldedNullifiersRequest_ClearVersionOneOfCase(GetShieldedNullifiersRequest *message); + +#pragma mark - GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0 + +typedef GPB_ENUM(GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0_FieldNumber) { + GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0_FieldNumber_NullifiersArray = 1, + GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0_FieldNumber_Prove = 2, +}; + +GPB_FINAL @interface GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0 : GPBMessage + +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *nullifiersArray; +/** The number of items in @c nullifiersArray without causing the array to be created. */ +@property(nonatomic, readonly) NSUInteger nullifiersArray_Count; + +@property(nonatomic, readwrite) BOOL prove; + +@end + +#pragma mark - GetShieldedNullifiersResponse + +typedef GPB_ENUM(GetShieldedNullifiersResponse_FieldNumber) { + GetShieldedNullifiersResponse_FieldNumber_V0 = 1, +}; + +typedef GPB_ENUM(GetShieldedNullifiersResponse_Version_OneOfCase) { + GetShieldedNullifiersResponse_Version_OneOfCase_GPBUnsetOneOfCase = 0, + GetShieldedNullifiersResponse_Version_OneOfCase_V0 = 1, +}; + +GPB_FINAL @interface GetShieldedNullifiersResponse : GPBMessage + +@property(nonatomic, readonly) GetShieldedNullifiersResponse_Version_OneOfCase versionOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0 *v0; + +@end + +/** + * Clears whatever value was set for the oneof 'version'. + **/ +void GetShieldedNullifiersResponse_ClearVersionOneOfCase(GetShieldedNullifiersResponse *message); + +#pragma mark - GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0 + +typedef GPB_ENUM(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_FieldNumber) { + GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_FieldNumber_NullifierStatuses = 1, + GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_FieldNumber_Proof = 2, + GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_FieldNumber_Metadata = 3, +}; + +typedef GPB_ENUM(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_Result_OneOfCase) { + GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_Result_OneOfCase_GPBUnsetOneOfCase = 0, + GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_Result_OneOfCase_NullifierStatuses = 1, + GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_Result_OneOfCase_Proof = 2, +}; + +GPB_FINAL @interface GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0 : GPBMessage + +@property(nonatomic, readonly) GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_Result_OneOfCase resultOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatuses *nullifierStatuses; + +@property(nonatomic, readwrite, strong, null_resettable) Proof *proof; + +@property(nonatomic, readwrite, strong, null_resettable) ResponseMetadata *metadata; +/** Test to see if @c metadata has been set. */ +@property(nonatomic, readwrite) BOOL hasMetadata; + +@end + +/** + * Clears whatever value was set for the oneof 'result'. + **/ +void GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_ClearResultOneOfCase(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0 *message); + +#pragma mark - GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatus + +typedef GPB_ENUM(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatus_FieldNumber) { + GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatus_FieldNumber_Nullifier = 1, + GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatus_FieldNumber_IsSpent = 2, +}; + +GPB_FINAL @interface GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatus : GPBMessage + +@property(nonatomic, readwrite, copy, null_resettable) NSData *nullifier; + +@property(nonatomic, readwrite) BOOL isSpent; + +@end + +#pragma mark - GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatuses + +typedef GPB_ENUM(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatuses_FieldNumber) { + GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatuses_FieldNumber_EntriesArray = 1, +}; + +GPB_FINAL @interface GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatuses : GPBMessage + +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *entriesArray; +/** The number of items in @c entriesArray without causing the array to be created. */ +@property(nonatomic, readonly) NSUInteger entriesArray_Count; + +@end + NS_ASSUME_NONNULL_END CF_EXTERN_C_END diff --git a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m index 0a011363beb..8ff1491b2a4 100644 --- a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m +++ b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m @@ -287,6 +287,27 @@ GPBObjCClassDeclaration(GetRecentCompactedAddressBalanceChangesRequest_GetRecentCompactedAddressBalanceChangesRequestV0); GPBObjCClassDeclaration(GetRecentCompactedAddressBalanceChangesResponse); GPBObjCClassDeclaration(GetRecentCompactedAddressBalanceChangesResponse_GetRecentCompactedAddressBalanceChangesResponseV0); +GPBObjCClassDeclaration(GetShieldedAnchorsRequest); +GPBObjCClassDeclaration(GetShieldedAnchorsRequest_GetShieldedAnchorsRequestV0); +GPBObjCClassDeclaration(GetShieldedAnchorsResponse); +GPBObjCClassDeclaration(GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0); +GPBObjCClassDeclaration(GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Anchors); +GPBObjCClassDeclaration(GetShieldedEncryptedNotesRequest); +GPBObjCClassDeclaration(GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0); +GPBObjCClassDeclaration(GetShieldedEncryptedNotesResponse); +GPBObjCClassDeclaration(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0); +GPBObjCClassDeclaration(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote); +GPBObjCClassDeclaration(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNotes); +GPBObjCClassDeclaration(GetShieldedNullifiersRequest); +GPBObjCClassDeclaration(GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0); +GPBObjCClassDeclaration(GetShieldedNullifiersResponse); +GPBObjCClassDeclaration(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0); +GPBObjCClassDeclaration(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatus); +GPBObjCClassDeclaration(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatuses); +GPBObjCClassDeclaration(GetShieldedPoolStateRequest); +GPBObjCClassDeclaration(GetShieldedPoolStateRequest_GetShieldedPoolStateRequestV0); +GPBObjCClassDeclaration(GetShieldedPoolStateResponse); +GPBObjCClassDeclaration(GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0); GPBObjCClassDeclaration(GetStatusRequest); GPBObjCClassDeclaration(GetStatusRequest_GetStatusRequestV0); GPBObjCClassDeclaration(GetStatusResponse); @@ -22264,6 +22285,1246 @@ void GetRecentCompactedAddressBalanceChangesResponse_GetRecentCompactedAddressBa GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; GPBClearOneof(message, oneof); } +#pragma mark - GetShieldedEncryptedNotesRequest + +@implementation GetShieldedEncryptedNotesRequest + +@dynamic versionOneOfCase; +@dynamic v0; + +typedef struct GetShieldedEncryptedNotesRequest__storage_ { + uint32_t _has_storage_[2]; + GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0 *v0; +} GetShieldedEncryptedNotesRequest__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "v0", + .dataTypeSpecific.clazz = GPBObjCClass(GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0), + .number = GetShieldedEncryptedNotesRequest_FieldNumber_V0, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetShieldedEncryptedNotesRequest__storage_, v0), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedEncryptedNotesRequest class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedEncryptedNotesRequest__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "version", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetShieldedEncryptedNotesRequest_ClearVersionOneOfCase(GetShieldedEncryptedNotesRequest *message) { + GPBDescriptor *descriptor = [GetShieldedEncryptedNotesRequest descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0 + +@implementation GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0 + +@dynamic startIndex; +@dynamic count; +@dynamic prove; + +typedef struct GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0__storage_ { + uint32_t _has_storage_[1]; + uint32_t count; + uint64_t startIndex; +} GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "startIndex", + .dataTypeSpecific.clazz = Nil, + .number = GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0_FieldNumber_StartIndex, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0__storage_, startIndex), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeUInt64, + }, + { + .name = "count", + .dataTypeSpecific.clazz = Nil, + .number = GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0_FieldNumber_Count, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0__storage_, count), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeUInt32, + }, + { + .name = "prove", + .dataTypeSpecific.clazz = Nil, + .number = GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0_FieldNumber_Prove, + .hasIndex = 2, + .offset = 3, // Stored in _has_storage_ to save space. + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeBool, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0 class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedEncryptedNotesRequest_GetShieldedEncryptedNotesRequestV0__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetShieldedEncryptedNotesRequest)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GetShieldedEncryptedNotesResponse + +@implementation GetShieldedEncryptedNotesResponse + +@dynamic versionOneOfCase; +@dynamic v0; + +typedef struct GetShieldedEncryptedNotesResponse__storage_ { + uint32_t _has_storage_[2]; + GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0 *v0; +} GetShieldedEncryptedNotesResponse__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "v0", + .dataTypeSpecific.clazz = GPBObjCClass(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0), + .number = GetShieldedEncryptedNotesResponse_FieldNumber_V0, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetShieldedEncryptedNotesResponse__storage_, v0), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedEncryptedNotesResponse class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedEncryptedNotesResponse__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "version", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetShieldedEncryptedNotesResponse_ClearVersionOneOfCase(GetShieldedEncryptedNotesResponse *message) { + GPBDescriptor *descriptor = [GetShieldedEncryptedNotesResponse descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0 + +@implementation GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0 + +@dynamic resultOneOfCase; +@dynamic encryptedNotes; +@dynamic proof; +@dynamic hasMetadata, metadata; + +typedef struct GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0__storage_ { + uint32_t _has_storage_[2]; + GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNotes *encryptedNotes; + Proof *proof; + ResponseMetadata *metadata; +} GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "encryptedNotes", + .dataTypeSpecific.clazz = GPBObjCClass(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNotes), + .number = GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_FieldNumber_EncryptedNotes, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0__storage_, encryptedNotes), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + { + .name = "proof", + .dataTypeSpecific.clazz = GPBObjCClass(Proof), + .number = GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_FieldNumber_Proof, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0__storage_, proof), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + { + .name = "metadata", + .dataTypeSpecific.clazz = GPBObjCClass(ResponseMetadata), + .number = GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_FieldNumber_Metadata, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0__storage_, metadata), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0 class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "result", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetShieldedEncryptedNotesResponse)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_ClearResultOneOfCase(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0 *message) { + GPBDescriptor *descriptor = [GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0 descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote + +@implementation GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote + +@dynamic cmx; +@dynamic encryptedNote; + +typedef struct GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote__storage_ { + uint32_t _has_storage_[1]; + NSData *cmx; + NSData *encryptedNote; +} GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "cmx", + .dataTypeSpecific.clazz = Nil, + .number = GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote_FieldNumber_Cmx, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote__storage_, cmx), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeBytes, + }, + { + .name = "encryptedNote", + .dataTypeSpecific.clazz = Nil, + .number = GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote_FieldNumber_EncryptedNote, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote__storage_, encryptedNote), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeBytes, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNotes + +@implementation GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNotes + +@dynamic entriesArray, entriesArray_Count; + +typedef struct GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNotes__storage_ { + uint32_t _has_storage_[1]; + NSMutableArray *entriesArray; +} GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNotes__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "entriesArray", + .dataTypeSpecific.clazz = GPBObjCClass(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote), + .number = GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNotes_FieldNumber_EntriesArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNotes__storage_, entriesArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNotes class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNotes__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GetShieldedAnchorsRequest + +@implementation GetShieldedAnchorsRequest + +@dynamic versionOneOfCase; +@dynamic v0; + +typedef struct GetShieldedAnchorsRequest__storage_ { + uint32_t _has_storage_[2]; + GetShieldedAnchorsRequest_GetShieldedAnchorsRequestV0 *v0; +} GetShieldedAnchorsRequest__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "v0", + .dataTypeSpecific.clazz = GPBObjCClass(GetShieldedAnchorsRequest_GetShieldedAnchorsRequestV0), + .number = GetShieldedAnchorsRequest_FieldNumber_V0, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetShieldedAnchorsRequest__storage_, v0), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedAnchorsRequest class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedAnchorsRequest__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "version", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetShieldedAnchorsRequest_ClearVersionOneOfCase(GetShieldedAnchorsRequest *message) { + GPBDescriptor *descriptor = [GetShieldedAnchorsRequest descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetShieldedAnchorsRequest_GetShieldedAnchorsRequestV0 + +@implementation GetShieldedAnchorsRequest_GetShieldedAnchorsRequestV0 + +@dynamic prove; + +typedef struct GetShieldedAnchorsRequest_GetShieldedAnchorsRequestV0__storage_ { + uint32_t _has_storage_[1]; +} GetShieldedAnchorsRequest_GetShieldedAnchorsRequestV0__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "prove", + .dataTypeSpecific.clazz = Nil, + .number = GetShieldedAnchorsRequest_GetShieldedAnchorsRequestV0_FieldNumber_Prove, + .hasIndex = 0, + .offset = 1, // Stored in _has_storage_ to save space. + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeBool, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedAnchorsRequest_GetShieldedAnchorsRequestV0 class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedAnchorsRequest_GetShieldedAnchorsRequestV0__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetShieldedAnchorsRequest)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GetShieldedAnchorsResponse + +@implementation GetShieldedAnchorsResponse + +@dynamic versionOneOfCase; +@dynamic v0; + +typedef struct GetShieldedAnchorsResponse__storage_ { + uint32_t _has_storage_[2]; + GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0 *v0; +} GetShieldedAnchorsResponse__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "v0", + .dataTypeSpecific.clazz = GPBObjCClass(GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0), + .number = GetShieldedAnchorsResponse_FieldNumber_V0, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetShieldedAnchorsResponse__storage_, v0), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedAnchorsResponse class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedAnchorsResponse__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "version", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetShieldedAnchorsResponse_ClearVersionOneOfCase(GetShieldedAnchorsResponse *message) { + GPBDescriptor *descriptor = [GetShieldedAnchorsResponse descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0 + +@implementation GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0 + +@dynamic resultOneOfCase; +@dynamic anchors; +@dynamic proof; +@dynamic hasMetadata, metadata; + +typedef struct GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0__storage_ { + uint32_t _has_storage_[2]; + GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Anchors *anchors; + Proof *proof; + ResponseMetadata *metadata; +} GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "anchors", + .dataTypeSpecific.clazz = GPBObjCClass(GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Anchors), + .number = GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_FieldNumber_Anchors, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0__storage_, anchors), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + { + .name = "proof", + .dataTypeSpecific.clazz = GPBObjCClass(Proof), + .number = GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_FieldNumber_Proof, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0__storage_, proof), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + { + .name = "metadata", + .dataTypeSpecific.clazz = GPBObjCClass(ResponseMetadata), + .number = GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_FieldNumber_Metadata, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0__storage_, metadata), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0 class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "result", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetShieldedAnchorsResponse)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_ClearResultOneOfCase(GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0 *message) { + GPBDescriptor *descriptor = [GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0 descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Anchors + +@implementation GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Anchors + +@dynamic anchorsArray, anchorsArray_Count; + +typedef struct GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Anchors__storage_ { + uint32_t _has_storage_[1]; + NSMutableArray *anchorsArray; +} GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Anchors__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "anchorsArray", + .dataTypeSpecific.clazz = Nil, + .number = GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Anchors_FieldNumber_AnchorsArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Anchors__storage_, anchorsArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeBytes, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Anchors class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Anchors__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GetShieldedPoolStateRequest + +@implementation GetShieldedPoolStateRequest + +@dynamic versionOneOfCase; +@dynamic v0; + +typedef struct GetShieldedPoolStateRequest__storage_ { + uint32_t _has_storage_[2]; + GetShieldedPoolStateRequest_GetShieldedPoolStateRequestV0 *v0; +} GetShieldedPoolStateRequest__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "v0", + .dataTypeSpecific.clazz = GPBObjCClass(GetShieldedPoolStateRequest_GetShieldedPoolStateRequestV0), + .number = GetShieldedPoolStateRequest_FieldNumber_V0, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetShieldedPoolStateRequest__storage_, v0), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedPoolStateRequest class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedPoolStateRequest__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "version", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetShieldedPoolStateRequest_ClearVersionOneOfCase(GetShieldedPoolStateRequest *message) { + GPBDescriptor *descriptor = [GetShieldedPoolStateRequest descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetShieldedPoolStateRequest_GetShieldedPoolStateRequestV0 + +@implementation GetShieldedPoolStateRequest_GetShieldedPoolStateRequestV0 + +@dynamic prove; + +typedef struct GetShieldedPoolStateRequest_GetShieldedPoolStateRequestV0__storage_ { + uint32_t _has_storage_[1]; +} GetShieldedPoolStateRequest_GetShieldedPoolStateRequestV0__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "prove", + .dataTypeSpecific.clazz = Nil, + .number = GetShieldedPoolStateRequest_GetShieldedPoolStateRequestV0_FieldNumber_Prove, + .hasIndex = 0, + .offset = 1, // Stored in _has_storage_ to save space. + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeBool, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedPoolStateRequest_GetShieldedPoolStateRequestV0 class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedPoolStateRequest_GetShieldedPoolStateRequestV0__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetShieldedPoolStateRequest)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GetShieldedPoolStateResponse + +@implementation GetShieldedPoolStateResponse + +@dynamic versionOneOfCase; +@dynamic v0; + +typedef struct GetShieldedPoolStateResponse__storage_ { + uint32_t _has_storage_[2]; + GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0 *v0; +} GetShieldedPoolStateResponse__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "v0", + .dataTypeSpecific.clazz = GPBObjCClass(GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0), + .number = GetShieldedPoolStateResponse_FieldNumber_V0, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetShieldedPoolStateResponse__storage_, v0), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedPoolStateResponse class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedPoolStateResponse__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "version", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetShieldedPoolStateResponse_ClearVersionOneOfCase(GetShieldedPoolStateResponse *message) { + GPBDescriptor *descriptor = [GetShieldedPoolStateResponse descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0 + +@implementation GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0 + +@dynamic resultOneOfCase; +@dynamic totalBalance; +@dynamic proof; +@dynamic hasMetadata, metadata; + +typedef struct GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0__storage_ { + uint32_t _has_storage_[2]; + Proof *proof; + ResponseMetadata *metadata; + uint64_t totalBalance; +} GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "totalBalance", + .dataTypeSpecific.clazz = Nil, + .number = GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0_FieldNumber_TotalBalance, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0__storage_, totalBalance), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeUInt64, + }, + { + .name = "proof", + .dataTypeSpecific.clazz = GPBObjCClass(Proof), + .number = GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0_FieldNumber_Proof, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0__storage_, proof), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + { + .name = "metadata", + .dataTypeSpecific.clazz = GPBObjCClass(ResponseMetadata), + .number = GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0_FieldNumber_Metadata, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0__storage_, metadata), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0 class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "result", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetShieldedPoolStateResponse)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0_ClearResultOneOfCase(GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0 *message) { + GPBDescriptor *descriptor = [GetShieldedPoolStateResponse_GetShieldedPoolStateResponseV0 descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetShieldedNullifiersRequest + +@implementation GetShieldedNullifiersRequest + +@dynamic versionOneOfCase; +@dynamic v0; + +typedef struct GetShieldedNullifiersRequest__storage_ { + uint32_t _has_storage_[2]; + GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0 *v0; +} GetShieldedNullifiersRequest__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "v0", + .dataTypeSpecific.clazz = GPBObjCClass(GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0), + .number = GetShieldedNullifiersRequest_FieldNumber_V0, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetShieldedNullifiersRequest__storage_, v0), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedNullifiersRequest class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedNullifiersRequest__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "version", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetShieldedNullifiersRequest_ClearVersionOneOfCase(GetShieldedNullifiersRequest *message) { + GPBDescriptor *descriptor = [GetShieldedNullifiersRequest descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0 + +@implementation GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0 + +@dynamic nullifiersArray, nullifiersArray_Count; +@dynamic prove; + +typedef struct GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0__storage_ { + uint32_t _has_storage_[1]; + NSMutableArray *nullifiersArray; +} GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "nullifiersArray", + .dataTypeSpecific.clazz = Nil, + .number = GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0_FieldNumber_NullifiersArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0__storage_, nullifiersArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeBytes, + }, + { + .name = "prove", + .dataTypeSpecific.clazz = Nil, + .number = GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0_FieldNumber_Prove, + .hasIndex = 0, + .offset = 1, // Stored in _has_storage_ to save space. + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeBool, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0 class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedNullifiersRequest_GetShieldedNullifiersRequestV0__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetShieldedNullifiersRequest)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GetShieldedNullifiersResponse + +@implementation GetShieldedNullifiersResponse + +@dynamic versionOneOfCase; +@dynamic v0; + +typedef struct GetShieldedNullifiersResponse__storage_ { + uint32_t _has_storage_[2]; + GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0 *v0; +} GetShieldedNullifiersResponse__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "v0", + .dataTypeSpecific.clazz = GPBObjCClass(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0), + .number = GetShieldedNullifiersResponse_FieldNumber_V0, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetShieldedNullifiersResponse__storage_, v0), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedNullifiersResponse class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedNullifiersResponse__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "version", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetShieldedNullifiersResponse_ClearVersionOneOfCase(GetShieldedNullifiersResponse *message) { + GPBDescriptor *descriptor = [GetShieldedNullifiersResponse descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0 + +@implementation GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0 + +@dynamic resultOneOfCase; +@dynamic nullifierStatuses; +@dynamic proof; +@dynamic hasMetadata, metadata; + +typedef struct GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0__storage_ { + uint32_t _has_storage_[2]; + GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatuses *nullifierStatuses; + Proof *proof; + ResponseMetadata *metadata; +} GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "nullifierStatuses", + .dataTypeSpecific.clazz = GPBObjCClass(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatuses), + .number = GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_FieldNumber_NullifierStatuses, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0__storage_, nullifierStatuses), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + { + .name = "proof", + .dataTypeSpecific.clazz = GPBObjCClass(Proof), + .number = GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_FieldNumber_Proof, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0__storage_, proof), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + { + .name = "metadata", + .dataTypeSpecific.clazz = GPBObjCClass(ResponseMetadata), + .number = GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_FieldNumber_Metadata, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0__storage_, metadata), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0 class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "result", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetShieldedNullifiersResponse)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_ClearResultOneOfCase(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0 *message) { + GPBDescriptor *descriptor = [GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0 descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatus + +@implementation GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatus + +@dynamic nullifier; +@dynamic isSpent; + +typedef struct GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatus__storage_ { + uint32_t _has_storage_[1]; + NSData *nullifier; +} GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatus__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "nullifier", + .dataTypeSpecific.clazz = Nil, + .number = GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatus_FieldNumber_Nullifier, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatus__storage_, nullifier), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeBytes, + }, + { + .name = "isSpent", + .dataTypeSpecific.clazz = Nil, + .number = GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatus_FieldNumber_IsSpent, + .hasIndex = 1, + .offset = 2, // Stored in _has_storage_ to save space. + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeBool, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatus class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatus__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatuses + +@implementation GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatuses + +@dynamic entriesArray, entriesArray_Count; + +typedef struct GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatuses__storage_ { + uint32_t _has_storage_[1]; + NSMutableArray *entriesArray; +} GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatuses__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "entriesArray", + .dataTypeSpecific.clazz = GPBObjCClass(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatus), + .number = GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatuses_FieldNumber_EntriesArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatuses__storage_, entriesArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatuses class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0_NullifierStatuses__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetShieldedNullifiersResponse_GetShieldedNullifiersResponseV0)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + #pragma clang diagnostic pop diff --git a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.h b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.h index 35182b472ec..ca3c040a8ae 100644 --- a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.h +++ b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.h @@ -99,6 +99,14 @@ @class GetRecentAddressBalanceChangesResponse; @class GetRecentCompactedAddressBalanceChangesRequest; @class GetRecentCompactedAddressBalanceChangesResponse; +@class GetShieldedAnchorsRequest; +@class GetShieldedAnchorsResponse; +@class GetShieldedEncryptedNotesRequest; +@class GetShieldedEncryptedNotesResponse; +@class GetShieldedNullifiersRequest; +@class GetShieldedNullifiersResponse; +@class GetShieldedPoolStateRequest; +@class GetShieldedPoolStateResponse; @class GetStatusRequest; @class GetStatusResponse; @class GetTokenContractInfoRequest; @@ -376,6 +384,22 @@ NS_ASSUME_NONNULL_BEGIN - (GRPCUnaryProtoCall *)getRecentCompactedAddressBalanceChangesWithMessage:(GetRecentCompactedAddressBalanceChangesRequest *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *_Nullable)callOptions; +#pragma mark getShieldedEncryptedNotes(GetShieldedEncryptedNotesRequest) returns (GetShieldedEncryptedNotesResponse) + +- (GRPCUnaryProtoCall *)getShieldedEncryptedNotesWithMessage:(GetShieldedEncryptedNotesRequest *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *_Nullable)callOptions; + +#pragma mark getShieldedAnchors(GetShieldedAnchorsRequest) returns (GetShieldedAnchorsResponse) + +- (GRPCUnaryProtoCall *)getShieldedAnchorsWithMessage:(GetShieldedAnchorsRequest *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *_Nullable)callOptions; + +#pragma mark getShieldedPoolState(GetShieldedPoolStateRequest) returns (GetShieldedPoolStateResponse) + +- (GRPCUnaryProtoCall *)getShieldedPoolStateWithMessage:(GetShieldedPoolStateRequest *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *_Nullable)callOptions; + +#pragma mark getShieldedNullifiers(GetShieldedNullifiersRequest) returns (GetShieldedNullifiersResponse) + +- (GRPCUnaryProtoCall *)getShieldedNullifiersWithMessage:(GetShieldedNullifiersRequest *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *_Nullable)callOptions; + @end /** @@ -805,6 +829,34 @@ NS_ASSUME_NONNULL_BEGIN - (GRPCProtoCall *)RPCTogetRecentCompactedAddressBalanceChangesWithRequest:(GetRecentCompactedAddressBalanceChangesRequest *)request handler:(void(^)(GetRecentCompactedAddressBalanceChangesResponse *_Nullable response, NSError *_Nullable error))handler; +#pragma mark getShieldedEncryptedNotes(GetShieldedEncryptedNotesRequest) returns (GetShieldedEncryptedNotesResponse) + +- (void)getShieldedEncryptedNotesWithRequest:(GetShieldedEncryptedNotesRequest *)request handler:(void(^)(GetShieldedEncryptedNotesResponse *_Nullable response, NSError *_Nullable error))handler; + +- (GRPCProtoCall *)RPCTogetShieldedEncryptedNotesWithRequest:(GetShieldedEncryptedNotesRequest *)request handler:(void(^)(GetShieldedEncryptedNotesResponse *_Nullable response, NSError *_Nullable error))handler; + + +#pragma mark getShieldedAnchors(GetShieldedAnchorsRequest) returns (GetShieldedAnchorsResponse) + +- (void)getShieldedAnchorsWithRequest:(GetShieldedAnchorsRequest *)request handler:(void(^)(GetShieldedAnchorsResponse *_Nullable response, NSError *_Nullable error))handler; + +- (GRPCProtoCall *)RPCTogetShieldedAnchorsWithRequest:(GetShieldedAnchorsRequest *)request handler:(void(^)(GetShieldedAnchorsResponse *_Nullable response, NSError *_Nullable error))handler; + + +#pragma mark getShieldedPoolState(GetShieldedPoolStateRequest) returns (GetShieldedPoolStateResponse) + +- (void)getShieldedPoolStateWithRequest:(GetShieldedPoolStateRequest *)request handler:(void(^)(GetShieldedPoolStateResponse *_Nullable response, NSError *_Nullable error))handler; + +- (GRPCProtoCall *)RPCTogetShieldedPoolStateWithRequest:(GetShieldedPoolStateRequest *)request handler:(void(^)(GetShieldedPoolStateResponse *_Nullable response, NSError *_Nullable error))handler; + + +#pragma mark getShieldedNullifiers(GetShieldedNullifiersRequest) returns (GetShieldedNullifiersResponse) + +- (void)getShieldedNullifiersWithRequest:(GetShieldedNullifiersRequest *)request handler:(void(^)(GetShieldedNullifiersResponse *_Nullable response, NSError *_Nullable error))handler; + +- (GRPCProtoCall *)RPCTogetShieldedNullifiersWithRequest:(GetShieldedNullifiersRequest *)request handler:(void(^)(GetShieldedNullifiersResponse *_Nullable response, NSError *_Nullable error))handler; + + @end diff --git a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.m b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.m index d75ccb77c60..80aec983df3 100644 --- a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.m +++ b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.m @@ -1195,5 +1195,85 @@ - (GRPCUnaryProtoCall *)getRecentCompactedAddressBalanceChangesWithMessage:(GetR responseClass:[GetRecentCompactedAddressBalanceChangesResponse class]]; } +#pragma mark getShieldedEncryptedNotes(GetShieldedEncryptedNotesRequest) returns (GetShieldedEncryptedNotesResponse) + +- (void)getShieldedEncryptedNotesWithRequest:(GetShieldedEncryptedNotesRequest *)request handler:(void(^)(GetShieldedEncryptedNotesResponse *_Nullable response, NSError *_Nullable error))handler{ + [[self RPCTogetShieldedEncryptedNotesWithRequest:request handler:handler] start]; +} +// Returns a not-yet-started RPC object. +- (GRPCProtoCall *)RPCTogetShieldedEncryptedNotesWithRequest:(GetShieldedEncryptedNotesRequest *)request handler:(void(^)(GetShieldedEncryptedNotesResponse *_Nullable response, NSError *_Nullable error))handler{ + return [self RPCToMethod:@"getShieldedEncryptedNotes" + requestsWriter:[GRXWriter writerWithValue:request] + responseClass:[GetShieldedEncryptedNotesResponse class] + responsesWriteable:[GRXWriteable writeableWithSingleHandler:handler]]; +} +- (GRPCUnaryProtoCall *)getShieldedEncryptedNotesWithMessage:(GetShieldedEncryptedNotesRequest *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *_Nullable)callOptions { + return [self RPCToMethod:@"getShieldedEncryptedNotes" + message:message + responseHandler:handler + callOptions:callOptions + responseClass:[GetShieldedEncryptedNotesResponse class]]; +} + +#pragma mark getShieldedAnchors(GetShieldedAnchorsRequest) returns (GetShieldedAnchorsResponse) + +- (void)getShieldedAnchorsWithRequest:(GetShieldedAnchorsRequest *)request handler:(void(^)(GetShieldedAnchorsResponse *_Nullable response, NSError *_Nullable error))handler{ + [[self RPCTogetShieldedAnchorsWithRequest:request handler:handler] start]; +} +// Returns a not-yet-started RPC object. +- (GRPCProtoCall *)RPCTogetShieldedAnchorsWithRequest:(GetShieldedAnchorsRequest *)request handler:(void(^)(GetShieldedAnchorsResponse *_Nullable response, NSError *_Nullable error))handler{ + return [self RPCToMethod:@"getShieldedAnchors" + requestsWriter:[GRXWriter writerWithValue:request] + responseClass:[GetShieldedAnchorsResponse class] + responsesWriteable:[GRXWriteable writeableWithSingleHandler:handler]]; +} +- (GRPCUnaryProtoCall *)getShieldedAnchorsWithMessage:(GetShieldedAnchorsRequest *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *_Nullable)callOptions { + return [self RPCToMethod:@"getShieldedAnchors" + message:message + responseHandler:handler + callOptions:callOptions + responseClass:[GetShieldedAnchorsResponse class]]; +} + +#pragma mark getShieldedPoolState(GetShieldedPoolStateRequest) returns (GetShieldedPoolStateResponse) + +- (void)getShieldedPoolStateWithRequest:(GetShieldedPoolStateRequest *)request handler:(void(^)(GetShieldedPoolStateResponse *_Nullable response, NSError *_Nullable error))handler{ + [[self RPCTogetShieldedPoolStateWithRequest:request handler:handler] start]; +} +// Returns a not-yet-started RPC object. +- (GRPCProtoCall *)RPCTogetShieldedPoolStateWithRequest:(GetShieldedPoolStateRequest *)request handler:(void(^)(GetShieldedPoolStateResponse *_Nullable response, NSError *_Nullable error))handler{ + return [self RPCToMethod:@"getShieldedPoolState" + requestsWriter:[GRXWriter writerWithValue:request] + responseClass:[GetShieldedPoolStateResponse class] + responsesWriteable:[GRXWriteable writeableWithSingleHandler:handler]]; +} +- (GRPCUnaryProtoCall *)getShieldedPoolStateWithMessage:(GetShieldedPoolStateRequest *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *_Nullable)callOptions { + return [self RPCToMethod:@"getShieldedPoolState" + message:message + responseHandler:handler + callOptions:callOptions + responseClass:[GetShieldedPoolStateResponse class]]; +} + +#pragma mark getShieldedNullifiers(GetShieldedNullifiersRequest) returns (GetShieldedNullifiersResponse) + +- (void)getShieldedNullifiersWithRequest:(GetShieldedNullifiersRequest *)request handler:(void(^)(GetShieldedNullifiersResponse *_Nullable response, NSError *_Nullable error))handler{ + [[self RPCTogetShieldedNullifiersWithRequest:request handler:handler] start]; +} +// Returns a not-yet-started RPC object. +- (GRPCProtoCall *)RPCTogetShieldedNullifiersWithRequest:(GetShieldedNullifiersRequest *)request handler:(void(^)(GetShieldedNullifiersResponse *_Nullable response, NSError *_Nullable error))handler{ + return [self RPCToMethod:@"getShieldedNullifiers" + requestsWriter:[GRXWriter writerWithValue:request] + responseClass:[GetShieldedNullifiersResponse class] + responsesWriteable:[GRXWriteable writeableWithSingleHandler:handler]]; +} +- (GRPCUnaryProtoCall *)getShieldedNullifiersWithMessage:(GetShieldedNullifiersRequest *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *_Nullable)callOptions { + return [self RPCToMethod:@"getShieldedNullifiers" + message:message + responseHandler:handler + callOptions:callOptions + responseClass:[GetShieldedNullifiersResponse class]]; +} + @end #endif diff --git a/packages/dapi-grpc/clients/platform/v0/python/platform_pb2.py b/packages/dapi-grpc/clients/platform/v0/python/platform_pb2.py index 82926fd8397..0b00b057655 100644 --- a/packages/dapi-grpc/clients/platform/v0/python/platform_pb2.py +++ b/packages/dapi-grpc/clients/platform/v0/python/platform_pb2.py @@ -23,7 +23,7 @@ syntax='proto3', serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x0eplatform.proto\x12\x19org.dash.platform.dapi.v0\x1a\x1egoogle/protobuf/wrappers.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x81\x01\n\x05Proof\x12\x15\n\rgrovedb_proof\x18\x01 \x01(\x0c\x12\x13\n\x0bquorum_hash\x18\x02 \x01(\x0c\x12\x11\n\tsignature\x18\x03 \x01(\x0c\x12\r\n\x05round\x18\x04 \x01(\r\x12\x15\n\rblock_id_hash\x18\x05 \x01(\x0c\x12\x13\n\x0bquorum_type\x18\x06 \x01(\r\"\x98\x01\n\x10ResponseMetadata\x12\x12\n\x06height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12 \n\x18\x63ore_chain_locked_height\x18\x02 \x01(\r\x12\r\n\x05\x65poch\x18\x03 \x01(\r\x12\x13\n\x07time_ms\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x18\n\x10protocol_version\x18\x05 \x01(\r\x12\x10\n\x08\x63hain_id\x18\x06 \x01(\t\"L\n\x1dStateTransitionBroadcastError\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\";\n\x1f\x42roadcastStateTransitionRequest\x12\x18\n\x10state_transition\x18\x01 \x01(\x0c\"\"\n BroadcastStateTransitionResponse\"\xa4\x01\n\x12GetIdentityRequest\x12P\n\x02v0\x18\x01 \x01(\x0b\x32\x42.org.dash.platform.dapi.v0.GetIdentityRequest.GetIdentityRequestV0H\x00\x1a\x31\n\x14GetIdentityRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xc1\x01\n\x17GetIdentityNonceRequest\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetIdentityNonceRequest.GetIdentityNonceRequestV0H\x00\x1a?\n\x19GetIdentityNonceRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xf6\x01\n\x1fGetIdentityContractNonceRequest\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetIdentityContractNonceRequest.GetIdentityContractNonceRequestV0H\x00\x1a\\\n!GetIdentityContractNonceRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x13\n\x0b\x63ontract_id\x18\x02 \x01(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xc0\x01\n\x19GetIdentityBalanceRequest\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetIdentityBalanceRequest.GetIdentityBalanceRequestV0H\x00\x1a\x38\n\x1bGetIdentityBalanceRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xec\x01\n$GetIdentityBalanceAndRevisionRequest\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionRequest.GetIdentityBalanceAndRevisionRequestV0H\x00\x1a\x43\n&GetIdentityBalanceAndRevisionRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x9e\x02\n\x13GetIdentityResponse\x12R\n\x02v0\x18\x01 \x01(\x0b\x32\x44.org.dash.platform.dapi.v0.GetIdentityResponse.GetIdentityResponseV0H\x00\x1a\xa7\x01\n\x15GetIdentityResponseV0\x12\x12\n\x08identity\x18\x01 \x01(\x0cH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xbc\x02\n\x18GetIdentityNonceResponse\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetIdentityNonceResponse.GetIdentityNonceResponseV0H\x00\x1a\xb6\x01\n\x1aGetIdentityNonceResponseV0\x12\x1c\n\x0eidentity_nonce\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xe5\x02\n GetIdentityContractNonceResponse\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetIdentityContractNonceResponse.GetIdentityContractNonceResponseV0H\x00\x1a\xc7\x01\n\"GetIdentityContractNonceResponseV0\x12%\n\x17identity_contract_nonce\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xbd\x02\n\x1aGetIdentityBalanceResponse\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetIdentityBalanceResponse.GetIdentityBalanceResponseV0H\x00\x1a\xb1\x01\n\x1cGetIdentityBalanceResponseV0\x12\x15\n\x07\x62\x61lance\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xb1\x04\n%GetIdentityBalanceAndRevisionResponse\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionResponse.GetIdentityBalanceAndRevisionResponseV0H\x00\x1a\x84\x03\n\'GetIdentityBalanceAndRevisionResponseV0\x12\x9b\x01\n\x14\x62\x61lance_and_revision\x18\x01 \x01(\x0b\x32{.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionResponse.GetIdentityBalanceAndRevisionResponseV0.BalanceAndRevisionH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a?\n\x12\x42\x61lanceAndRevision\x12\x13\n\x07\x62\x61lance\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x14\n\x08revision\x18\x02 \x01(\x04\x42\x02\x30\x01\x42\x08\n\x06resultB\t\n\x07version\"\xd1\x01\n\x0eKeyRequestType\x12\x36\n\x08\x61ll_keys\x18\x01 \x01(\x0b\x32\".org.dash.platform.dapi.v0.AllKeysH\x00\x12@\n\rspecific_keys\x18\x02 \x01(\x0b\x32\'.org.dash.platform.dapi.v0.SpecificKeysH\x00\x12:\n\nsearch_key\x18\x03 \x01(\x0b\x32$.org.dash.platform.dapi.v0.SearchKeyH\x00\x42\t\n\x07request\"\t\n\x07\x41llKeys\"\x1f\n\x0cSpecificKeys\x12\x0f\n\x07key_ids\x18\x01 \x03(\r\"\xb6\x01\n\tSearchKey\x12I\n\x0bpurpose_map\x18\x01 \x03(\x0b\x32\x34.org.dash.platform.dapi.v0.SearchKey.PurposeMapEntry\x1a^\n\x0fPurposeMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12:\n\x05value\x18\x02 \x01(\x0b\x32+.org.dash.platform.dapi.v0.SecurityLevelMap:\x02\x38\x01\"\xbf\x02\n\x10SecurityLevelMap\x12]\n\x12security_level_map\x18\x01 \x03(\x0b\x32\x41.org.dash.platform.dapi.v0.SecurityLevelMap.SecurityLevelMapEntry\x1aw\n\x15SecurityLevelMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12M\n\x05value\x18\x02 \x01(\x0e\x32>.org.dash.platform.dapi.v0.SecurityLevelMap.KeyKindRequestType:\x02\x38\x01\"S\n\x12KeyKindRequestType\x12\x1f\n\x1b\x43URRENT_KEY_OF_KIND_REQUEST\x10\x00\x12\x1c\n\x18\x41LL_KEYS_OF_KIND_REQUEST\x10\x01\"\xda\x02\n\x16GetIdentityKeysRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetIdentityKeysRequest.GetIdentityKeysRequestV0H\x00\x1a\xda\x01\n\x18GetIdentityKeysRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12?\n\x0crequest_type\x18\x02 \x01(\x0b\x32).org.dash.platform.dapi.v0.KeyRequestType\x12+\n\x05limit\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12,\n\x06offset\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\t\n\x07version\"\x99\x03\n\x17GetIdentityKeysResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetIdentityKeysResponse.GetIdentityKeysResponseV0H\x00\x1a\x96\x02\n\x19GetIdentityKeysResponseV0\x12\x61\n\x04keys\x18\x01 \x01(\x0b\x32Q.org.dash.platform.dapi.v0.GetIdentityKeysResponse.GetIdentityKeysResponseV0.KeysH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1a\n\x04Keys\x12\x12\n\nkeys_bytes\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xef\x02\n GetIdentitiesContractKeysRequest\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetIdentitiesContractKeysRequest.GetIdentitiesContractKeysRequestV0H\x00\x1a\xd1\x01\n\"GetIdentitiesContractKeysRequestV0\x12\x16\n\x0eidentities_ids\x18\x01 \x03(\x0c\x12\x13\n\x0b\x63ontract_id\x18\x02 \x01(\x0c\x12\x1f\n\x12\x64ocument_type_name\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x37\n\x08purposes\x18\x04 \x03(\x0e\x32%.org.dash.platform.dapi.v0.KeyPurpose\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\x15\n\x13_document_type_nameB\t\n\x07version\"\xdf\x06\n!GetIdentitiesContractKeysResponse\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0H\x00\x1a\xbe\x05\n#GetIdentitiesContractKeysResponseV0\x12\x8a\x01\n\x0fidentities_keys\x18\x01 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0.IdentitiesKeysH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aY\n\x0bPurposeKeys\x12\x36\n\x07purpose\x18\x01 \x01(\x0e\x32%.org.dash.platform.dapi.v0.KeyPurpose\x12\x12\n\nkeys_bytes\x18\x02 \x03(\x0c\x1a\x9f\x01\n\x0cIdentityKeys\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12z\n\x04keys\x18\x02 \x03(\x0b\x32l.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0.PurposeKeys\x1a\x90\x01\n\x0eIdentitiesKeys\x12~\n\x07\x65ntries\x18\x01 \x03(\x0b\x32m.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0.IdentityKeysB\x08\n\x06resultB\t\n\x07version\"\xa4\x02\n*GetEvonodesProposedEpochBlocksByIdsRequest\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByIdsRequest.GetEvonodesProposedEpochBlocksByIdsRequestV0H\x00\x1ah\n,GetEvonodesProposedEpochBlocksByIdsRequestV0\x12\x12\n\x05\x65poch\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x0b\n\x03ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\x08\n\x06_epochB\t\n\x07version\"\x92\x06\n&GetEvonodesProposedEpochBlocksResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse.GetEvonodesProposedEpochBlocksResponseV0H\x00\x1a\xe2\x04\n(GetEvonodesProposedEpochBlocksResponseV0\x12\xb1\x01\n#evonodes_proposed_block_counts_info\x18\x01 \x01(\x0b\x32\x81\x01.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse.GetEvonodesProposedEpochBlocksResponseV0.EvonodesProposedBlocksH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a?\n\x15\x45vonodeProposedBlocks\x12\x13\n\x0bpro_tx_hash\x18\x01 \x01(\x0c\x12\x11\n\x05\x63ount\x18\x02 \x01(\x04\x42\x02\x30\x01\x1a\xc4\x01\n\x16\x45vonodesProposedBlocks\x12\xa9\x01\n\x1e\x65vonodes_proposed_block_counts\x18\x01 \x03(\x0b\x32\x80\x01.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse.GetEvonodesProposedEpochBlocksResponseV0.EvonodeProposedBlocksB\x08\n\x06resultB\t\n\x07version\"\xf2\x02\n,GetEvonodesProposedEpochBlocksByRangeRequest\x12\x84\x01\n\x02v0\x18\x01 \x01(\x0b\x32v.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByRangeRequest.GetEvonodesProposedEpochBlocksByRangeRequestV0H\x00\x1a\xaf\x01\n.GetEvonodesProposedEpochBlocksByRangeRequestV0\x12\x12\n\x05\x65poch\x18\x01 \x01(\rH\x01\x88\x01\x01\x12\x12\n\x05limit\x18\x02 \x01(\rH\x02\x88\x01\x01\x12\x15\n\x0bstart_after\x18\x03 \x01(\x0cH\x00\x12\x12\n\x08start_at\x18\x04 \x01(\x0cH\x00\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\x07\n\x05startB\x08\n\x06_epochB\x08\n\x06_limitB\t\n\x07version\"\xcd\x01\n\x1cGetIdentitiesBalancesRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetIdentitiesBalancesRequest.GetIdentitiesBalancesRequestV0H\x00\x1a<\n\x1eGetIdentitiesBalancesRequestV0\x12\x0b\n\x03ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x9f\x05\n\x1dGetIdentitiesBalancesResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse.GetIdentitiesBalancesResponseV0H\x00\x1a\x8a\x04\n\x1fGetIdentitiesBalancesResponseV0\x12\x8a\x01\n\x13identities_balances\x18\x01 \x01(\x0b\x32k.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse.GetIdentitiesBalancesResponseV0.IdentitiesBalancesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aL\n\x0fIdentityBalance\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x18\n\x07\x62\x61lance\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x88\x01\x01\x42\n\n\x08_balance\x1a\x8f\x01\n\x12IdentitiesBalances\x12y\n\x07\x65ntries\x18\x01 \x03(\x0b\x32h.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse.GetIdentitiesBalancesResponseV0.IdentityBalanceB\x08\n\x06resultB\t\n\x07version\"\xb4\x01\n\x16GetDataContractRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetDataContractRequest.GetDataContractRequestV0H\x00\x1a\x35\n\x18GetDataContractRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xb3\x02\n\x17GetDataContractResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetDataContractResponse.GetDataContractResponseV0H\x00\x1a\xb0\x01\n\x19GetDataContractResponseV0\x12\x17\n\rdata_contract\x18\x01 \x01(\x0cH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xb9\x01\n\x17GetDataContractsRequest\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetDataContractsRequest.GetDataContractsRequestV0H\x00\x1a\x37\n\x19GetDataContractsRequestV0\x12\x0b\n\x03ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xcf\x04\n\x18GetDataContractsResponse\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetDataContractsResponse.GetDataContractsResponseV0H\x00\x1a[\n\x11\x44\x61taContractEntry\x12\x12\n\nidentifier\x18\x01 \x01(\x0c\x12\x32\n\rdata_contract\x18\x02 \x01(\x0b\x32\x1b.google.protobuf.BytesValue\x1au\n\rDataContracts\x12\x64\n\x15\x64\x61ta_contract_entries\x18\x01 \x03(\x0b\x32\x45.org.dash.platform.dapi.v0.GetDataContractsResponse.DataContractEntry\x1a\xf5\x01\n\x1aGetDataContractsResponseV0\x12[\n\x0e\x64\x61ta_contracts\x18\x01 \x01(\x0b\x32\x41.org.dash.platform.dapi.v0.GetDataContractsResponse.DataContractsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc5\x02\n\x1dGetDataContractHistoryRequest\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetDataContractHistoryRequest.GetDataContractHistoryRequestV0H\x00\x1a\xb0\x01\n\x1fGetDataContractHistoryRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12+\n\x05limit\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12,\n\x06offset\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\x17\n\x0bstart_at_ms\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\t\n\x07version\"\xb2\x05\n\x1eGetDataContractHistoryResponse\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetDataContractHistoryResponse.GetDataContractHistoryResponseV0H\x00\x1a\x9a\x04\n GetDataContractHistoryResponseV0\x12\x8f\x01\n\x15\x64\x61ta_contract_history\x18\x01 \x01(\x0b\x32n.org.dash.platform.dapi.v0.GetDataContractHistoryResponse.GetDataContractHistoryResponseV0.DataContractHistoryH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a;\n\x18\x44\x61taContractHistoryEntry\x12\x10\n\x04\x64\x61te\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05value\x18\x02 \x01(\x0c\x1a\xaa\x01\n\x13\x44\x61taContractHistory\x12\x92\x01\n\x15\x64\x61ta_contract_entries\x18\x01 \x03(\x0b\x32s.org.dash.platform.dapi.v0.GetDataContractHistoryResponse.GetDataContractHistoryResponseV0.DataContractHistoryEntryB\x08\n\x06resultB\t\n\x07version\"\xb2\x02\n\x13GetDocumentsRequest\x12R\n\x02v0\x18\x01 \x01(\x0b\x32\x44.org.dash.platform.dapi.v0.GetDocumentsRequest.GetDocumentsRequestV0H\x00\x1a\xbb\x01\n\x15GetDocumentsRequestV0\x12\x18\n\x10\x64\x61ta_contract_id\x18\x01 \x01(\x0c\x12\x15\n\rdocument_type\x18\x02 \x01(\t\x12\r\n\x05where\x18\x03 \x01(\x0c\x12\x10\n\x08order_by\x18\x04 \x01(\x0c\x12\r\n\x05limit\x18\x05 \x01(\r\x12\x15\n\x0bstart_after\x18\x06 \x01(\x0cH\x00\x12\x12\n\x08start_at\x18\x07 \x01(\x0cH\x00\x12\r\n\x05prove\x18\x08 \x01(\x08\x42\x07\n\x05startB\t\n\x07version\"\x95\x03\n\x14GetDocumentsResponse\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetDocumentsResponse.GetDocumentsResponseV0H\x00\x1a\x9b\x02\n\x16GetDocumentsResponseV0\x12\x65\n\tdocuments\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetDocumentsResponse.GetDocumentsResponseV0.DocumentsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1e\n\tDocuments\x12\x11\n\tdocuments\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xed\x01\n!GetIdentityByPublicKeyHashRequest\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashRequest.GetIdentityByPublicKeyHashRequestV0H\x00\x1aM\n#GetIdentityByPublicKeyHashRequestV0\x12\x17\n\x0fpublic_key_hash\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xda\x02\n\"GetIdentityByPublicKeyHashResponse\x12p\n\x02v0\x18\x01 \x01(\x0b\x32\x62.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashResponse.GetIdentityByPublicKeyHashResponseV0H\x00\x1a\xb6\x01\n$GetIdentityByPublicKeyHashResponseV0\x12\x12\n\x08identity\x18\x01 \x01(\x0cH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xbd\x02\n*GetIdentityByNonUniquePublicKeyHashRequest\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashRequest.GetIdentityByNonUniquePublicKeyHashRequestV0H\x00\x1a\x80\x01\n,GetIdentityByNonUniquePublicKeyHashRequestV0\x12\x17\n\x0fpublic_key_hash\x18\x01 \x01(\x0c\x12\x18\n\x0bstart_after\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\x0e\n\x0c_start_afterB\t\n\x07version\"\xd6\x06\n+GetIdentityByNonUniquePublicKeyHashResponse\x12\x82\x01\n\x02v0\x18\x01 \x01(\x0b\x32t.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse.GetIdentityByNonUniquePublicKeyHashResponseV0H\x00\x1a\x96\x05\n-GetIdentityByNonUniquePublicKeyHashResponseV0\x12\x9a\x01\n\x08identity\x18\x01 \x01(\x0b\x32\x85\x01.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse.GetIdentityByNonUniquePublicKeyHashResponseV0.IdentityResponseH\x00\x12\x9d\x01\n\x05proof\x18\x02 \x01(\x0b\x32\x8b\x01.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse.GetIdentityByNonUniquePublicKeyHashResponseV0.IdentityProvedResponseH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x36\n\x10IdentityResponse\x12\x15\n\x08identity\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\x0b\n\t_identity\x1a\xa6\x01\n\x16IdentityProvedResponse\x12P\n&grovedb_identity_public_key_hash_proof\x18\x01 \x01(\x0b\x32 .org.dash.platform.dapi.v0.Proof\x12!\n\x14identity_proof_bytes\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x42\x17\n\x15_identity_proof_bytesB\x08\n\x06resultB\t\n\x07version\"\xfb\x01\n#WaitForStateTransitionResultRequest\x12r\n\x02v0\x18\x01 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.WaitForStateTransitionResultRequest.WaitForStateTransitionResultRequestV0H\x00\x1aU\n%WaitForStateTransitionResultRequestV0\x12\x1d\n\x15state_transition_hash\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x99\x03\n$WaitForStateTransitionResultResponse\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.WaitForStateTransitionResultResponse.WaitForStateTransitionResultResponseV0H\x00\x1a\xef\x01\n&WaitForStateTransitionResultResponseV0\x12I\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x38.org.dash.platform.dapi.v0.StateTransitionBroadcastErrorH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc4\x01\n\x19GetConsensusParamsRequest\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetConsensusParamsRequest.GetConsensusParamsRequestV0H\x00\x1a<\n\x1bGetConsensusParamsRequestV0\x12\x0e\n\x06height\x18\x01 \x01(\x05\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x9c\x04\n\x1aGetConsensusParamsResponse\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetConsensusParamsResponse.GetConsensusParamsResponseV0H\x00\x1aP\n\x14\x43onsensusParamsBlock\x12\x11\n\tmax_bytes\x18\x01 \x01(\t\x12\x0f\n\x07max_gas\x18\x02 \x01(\t\x12\x14\n\x0ctime_iota_ms\x18\x03 \x01(\t\x1a\x62\n\x17\x43onsensusParamsEvidence\x12\x1a\n\x12max_age_num_blocks\x18\x01 \x01(\t\x12\x18\n\x10max_age_duration\x18\x02 \x01(\t\x12\x11\n\tmax_bytes\x18\x03 \x01(\t\x1a\xda\x01\n\x1cGetConsensusParamsResponseV0\x12Y\n\x05\x62lock\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetConsensusParamsResponse.ConsensusParamsBlock\x12_\n\x08\x65vidence\x18\x02 \x01(\x0b\x32M.org.dash.platform.dapi.v0.GetConsensusParamsResponse.ConsensusParamsEvidenceB\t\n\x07version\"\xe4\x01\n%GetProtocolVersionUpgradeStateRequest\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateRequest.GetProtocolVersionUpgradeStateRequestV0H\x00\x1a\x38\n\'GetProtocolVersionUpgradeStateRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xb5\x05\n&GetProtocolVersionUpgradeStateResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse.GetProtocolVersionUpgradeStateResponseV0H\x00\x1a\x85\x04\n(GetProtocolVersionUpgradeStateResponseV0\x12\x87\x01\n\x08versions\x18\x01 \x01(\x0b\x32s.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse.GetProtocolVersionUpgradeStateResponseV0.VersionsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x96\x01\n\x08Versions\x12\x89\x01\n\x08versions\x18\x01 \x03(\x0b\x32w.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse.GetProtocolVersionUpgradeStateResponseV0.VersionEntry\x1a:\n\x0cVersionEntry\x12\x16\n\x0eversion_number\x18\x01 \x01(\r\x12\x12\n\nvote_count\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xa3\x02\n*GetProtocolVersionUpgradeVoteStatusRequest\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusRequest.GetProtocolVersionUpgradeVoteStatusRequestV0H\x00\x1ag\n,GetProtocolVersionUpgradeVoteStatusRequestV0\x12\x19\n\x11start_pro_tx_hash\x18\x01 \x01(\x0c\x12\r\n\x05\x63ount\x18\x02 \x01(\r\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xef\x05\n+GetProtocolVersionUpgradeVoteStatusResponse\x12\x82\x01\n\x02v0\x18\x01 \x01(\x0b\x32t.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse.GetProtocolVersionUpgradeVoteStatusResponseV0H\x00\x1a\xaf\x04\n-GetProtocolVersionUpgradeVoteStatusResponseV0\x12\x98\x01\n\x08versions\x18\x01 \x01(\x0b\x32\x83\x01.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse.GetProtocolVersionUpgradeVoteStatusResponseV0.VersionSignalsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xaf\x01\n\x0eVersionSignals\x12\x9c\x01\n\x0fversion_signals\x18\x01 \x03(\x0b\x32\x82\x01.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse.GetProtocolVersionUpgradeVoteStatusResponseV0.VersionSignal\x1a\x35\n\rVersionSignal\x12\x13\n\x0bpro_tx_hash\x18\x01 \x01(\x0c\x12\x0f\n\x07version\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xf5\x01\n\x14GetEpochsInfoRequest\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetEpochsInfoRequest.GetEpochsInfoRequestV0H\x00\x1a|\n\x16GetEpochsInfoRequestV0\x12\x31\n\x0bstart_epoch\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\r\n\x05\x63ount\x18\x02 \x01(\r\x12\x11\n\tascending\x18\x03 \x01(\x08\x12\r\n\x05prove\x18\x04 \x01(\x08\x42\t\n\x07version\"\x99\x05\n\x15GetEpochsInfoResponse\x12V\n\x02v0\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetEpochsInfoResponse.GetEpochsInfoResponseV0H\x00\x1a\x9c\x04\n\x17GetEpochsInfoResponseV0\x12\x65\n\x06\x65pochs\x18\x01 \x01(\x0b\x32S.org.dash.platform.dapi.v0.GetEpochsInfoResponse.GetEpochsInfoResponseV0.EpochInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1au\n\nEpochInfos\x12g\n\x0b\x65poch_infos\x18\x01 \x03(\x0b\x32R.org.dash.platform.dapi.v0.GetEpochsInfoResponse.GetEpochsInfoResponseV0.EpochInfo\x1a\xa6\x01\n\tEpochInfo\x12\x0e\n\x06number\x18\x01 \x01(\r\x12\x1e\n\x12\x66irst_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x1f\n\x17\x66irst_core_block_height\x18\x03 \x01(\r\x12\x16\n\nstart_time\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x16\n\x0e\x66\x65\x65_multiplier\x18\x05 \x01(\x01\x12\x18\n\x10protocol_version\x18\x06 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xbf\x02\n\x1dGetFinalizedEpochInfosRequest\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetFinalizedEpochInfosRequest.GetFinalizedEpochInfosRequestV0H\x00\x1a\xaa\x01\n\x1fGetFinalizedEpochInfosRequestV0\x12\x19\n\x11start_epoch_index\x18\x01 \x01(\r\x12\"\n\x1astart_epoch_index_included\x18\x02 \x01(\x08\x12\x17\n\x0f\x65nd_epoch_index\x18\x03 \x01(\r\x12 \n\x18\x65nd_epoch_index_included\x18\x04 \x01(\x08\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\t\n\x07version\"\xbd\t\n\x1eGetFinalizedEpochInfosResponse\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0H\x00\x1a\xa5\x08\n GetFinalizedEpochInfosResponseV0\x12\x80\x01\n\x06\x65pochs\x18\x01 \x01(\x0b\x32n.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0.FinalizedEpochInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xa4\x01\n\x13\x46inalizedEpochInfos\x12\x8c\x01\n\x15\x66inalized_epoch_infos\x18\x01 \x03(\x0b\x32m.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0.FinalizedEpochInfo\x1a\x9f\x04\n\x12\x46inalizedEpochInfo\x12\x0e\n\x06number\x18\x01 \x01(\r\x12\x1e\n\x12\x66irst_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x1f\n\x17\x66irst_core_block_height\x18\x03 \x01(\r\x12\x1c\n\x10\x66irst_block_time\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x16\n\x0e\x66\x65\x65_multiplier\x18\x05 \x01(\x01\x12\x18\n\x10protocol_version\x18\x06 \x01(\r\x12!\n\x15total_blocks_in_epoch\x18\x07 \x01(\x04\x42\x02\x30\x01\x12*\n\"next_epoch_start_core_block_height\x18\x08 \x01(\r\x12!\n\x15total_processing_fees\x18\t \x01(\x04\x42\x02\x30\x01\x12*\n\x1etotal_distributed_storage_fees\x18\n \x01(\x04\x42\x02\x30\x01\x12&\n\x1atotal_created_storage_fees\x18\x0b \x01(\x04\x42\x02\x30\x01\x12\x1e\n\x12\x63ore_block_rewards\x18\x0c \x01(\x04\x42\x02\x30\x01\x12\x81\x01\n\x0f\x62lock_proposers\x18\r \x03(\x0b\x32h.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0.BlockProposer\x1a\x39\n\rBlockProposer\x12\x13\n\x0bproposer_id\x18\x01 \x01(\x0c\x12\x13\n\x0b\x62lock_count\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xde\x04\n\x1cGetContestedResourcesRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetContestedResourcesRequest.GetContestedResourcesRequestV0H\x00\x1a\xcc\x03\n\x1eGetContestedResourcesRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\x12\n\nindex_name\x18\x03 \x01(\t\x12\x1a\n\x12start_index_values\x18\x04 \x03(\x0c\x12\x18\n\x10\x65nd_index_values\x18\x05 \x03(\x0c\x12\x89\x01\n\x13start_at_value_info\x18\x06 \x01(\x0b\x32g.org.dash.platform.dapi.v0.GetContestedResourcesRequest.GetContestedResourcesRequestV0.StartAtValueInfoH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x07 \x01(\rH\x01\x88\x01\x01\x12\x17\n\x0forder_ascending\x18\x08 \x01(\x08\x12\r\n\x05prove\x18\t \x01(\x08\x1a\x45\n\x10StartAtValueInfo\x12\x13\n\x0bstart_value\x18\x01 \x01(\x0c\x12\x1c\n\x14start_value_included\x18\x02 \x01(\x08\x42\x16\n\x14_start_at_value_infoB\x08\n\x06_countB\t\n\x07version\"\x88\x04\n\x1dGetContestedResourcesResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetContestedResourcesResponse.GetContestedResourcesResponseV0H\x00\x1a\xf3\x02\n\x1fGetContestedResourcesResponseV0\x12\x95\x01\n\x19\x63ontested_resource_values\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetContestedResourcesResponse.GetContestedResourcesResponseV0.ContestedResourceValuesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a<\n\x17\x43ontestedResourceValues\x12!\n\x19\x63ontested_resource_values\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xd2\x05\n\x1cGetVotePollsByEndDateRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest.GetVotePollsByEndDateRequestV0H\x00\x1a\xc0\x04\n\x1eGetVotePollsByEndDateRequestV0\x12\x84\x01\n\x0fstart_time_info\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest.GetVotePollsByEndDateRequestV0.StartAtTimeInfoH\x00\x88\x01\x01\x12\x80\x01\n\rend_time_info\x18\x02 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest.GetVotePollsByEndDateRequestV0.EndAtTimeInfoH\x01\x88\x01\x01\x12\x12\n\x05limit\x18\x03 \x01(\rH\x02\x88\x01\x01\x12\x13\n\x06offset\x18\x04 \x01(\rH\x03\x88\x01\x01\x12\x11\n\tascending\x18\x05 \x01(\x08\x12\r\n\x05prove\x18\x06 \x01(\x08\x1aI\n\x0fStartAtTimeInfo\x12\x19\n\rstart_time_ms\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1b\n\x13start_time_included\x18\x02 \x01(\x08\x1a\x43\n\rEndAtTimeInfo\x12\x17\n\x0b\x65nd_time_ms\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x19\n\x11\x65nd_time_included\x18\x02 \x01(\x08\x42\x12\n\x10_start_time_infoB\x10\n\x0e_end_time_infoB\x08\n\x06_limitB\t\n\x07_offsetB\t\n\x07version\"\x83\x06\n\x1dGetVotePollsByEndDateResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse.GetVotePollsByEndDateResponseV0H\x00\x1a\xee\x04\n\x1fGetVotePollsByEndDateResponseV0\x12\x9c\x01\n\x18vote_polls_by_timestamps\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse.GetVotePollsByEndDateResponseV0.SerializedVotePollsByTimestampsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aV\n\x1eSerializedVotePollsByTimestamp\x12\x15\n\ttimestamp\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1d\n\x15serialized_vote_polls\x18\x02 \x03(\x0c\x1a\xd7\x01\n\x1fSerializedVotePollsByTimestamps\x12\x99\x01\n\x18vote_polls_by_timestamps\x18\x01 \x03(\x0b\x32w.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse.GetVotePollsByEndDateResponseV0.SerializedVotePollsByTimestamp\x12\x18\n\x10\x66inished_results\x18\x02 \x01(\x08\x42\x08\n\x06resultB\t\n\x07version\"\xff\x06\n$GetContestedResourceVoteStateRequest\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest.GetContestedResourceVoteStateRequestV0H\x00\x1a\xd5\x05\n&GetContestedResourceVoteStateRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\x12\n\nindex_name\x18\x03 \x01(\t\x12\x14\n\x0cindex_values\x18\x04 \x03(\x0c\x12\x86\x01\n\x0bresult_type\x18\x05 \x01(\x0e\x32q.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest.GetContestedResourceVoteStateRequestV0.ResultType\x12\x36\n.allow_include_locked_and_abstaining_vote_tally\x18\x06 \x01(\x08\x12\xa3\x01\n\x18start_at_identifier_info\x18\x07 \x01(\x0b\x32|.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest.GetContestedResourceVoteStateRequestV0.StartAtIdentifierInfoH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x08 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\t \x01(\x08\x1aT\n\x15StartAtIdentifierInfo\x12\x18\n\x10start_identifier\x18\x01 \x01(\x0c\x12!\n\x19start_identifier_included\x18\x02 \x01(\x08\"I\n\nResultType\x12\r\n\tDOCUMENTS\x10\x00\x12\x0e\n\nVOTE_TALLY\x10\x01\x12\x1c\n\x18\x44OCUMENTS_AND_VOTE_TALLY\x10\x02\x42\x1b\n\x19_start_at_identifier_infoB\x08\n\x06_countB\t\n\x07version\"\x94\x0c\n%GetContestedResourceVoteStateResponse\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0H\x00\x1a\xe7\n\n\'GetContestedResourceVoteStateResponseV0\x12\xae\x01\n\x1d\x63ontested_resource_contenders\x18\x01 \x01(\x0b\x32\x84\x01.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.ContestedResourceContendersH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xda\x03\n\x10\x46inishedVoteInfo\x12\xad\x01\n\x15\x66inished_vote_outcome\x18\x01 \x01(\x0e\x32\x8d\x01.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.FinishedVoteInfo.FinishedVoteOutcome\x12\x1f\n\x12won_by_identity_id\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12$\n\x18\x66inished_at_block_height\x18\x03 \x01(\x04\x42\x02\x30\x01\x12%\n\x1d\x66inished_at_core_block_height\x18\x04 \x01(\r\x12%\n\x19\x66inished_at_block_time_ms\x18\x05 \x01(\x04\x42\x02\x30\x01\x12\x19\n\x11\x66inished_at_epoch\x18\x06 \x01(\r\"O\n\x13\x46inishedVoteOutcome\x12\x14\n\x10TOWARDS_IDENTITY\x10\x00\x12\n\n\x06LOCKED\x10\x01\x12\x16\n\x12NO_PREVIOUS_WINNER\x10\x02\x42\x15\n\x13_won_by_identity_id\x1a\xc4\x03\n\x1b\x43ontestedResourceContenders\x12\x86\x01\n\ncontenders\x18\x01 \x03(\x0b\x32r.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.Contender\x12\x1f\n\x12\x61\x62stain_vote_tally\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x1c\n\x0flock_vote_tally\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x9a\x01\n\x12\x66inished_vote_info\x18\x04 \x01(\x0b\x32y.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.FinishedVoteInfoH\x02\x88\x01\x01\x42\x15\n\x13_abstain_vote_tallyB\x12\n\x10_lock_vote_tallyB\x15\n\x13_finished_vote_info\x1ak\n\tContender\x12\x12\n\nidentifier\x18\x01 \x01(\x0c\x12\x17\n\nvote_count\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x15\n\x08\x64ocument\x18\x03 \x01(\x0cH\x01\x88\x01\x01\x42\r\n\x0b_vote_countB\x0b\n\t_documentB\x08\n\x06resultB\t\n\x07version\"\xd5\x05\n,GetContestedResourceVotersForIdentityRequest\x12\x84\x01\n\x02v0\x18\x01 \x01(\x0b\x32v.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityRequest.GetContestedResourceVotersForIdentityRequestV0H\x00\x1a\x92\x04\n.GetContestedResourceVotersForIdentityRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\x12\n\nindex_name\x18\x03 \x01(\t\x12\x14\n\x0cindex_values\x18\x04 \x03(\x0c\x12\x15\n\rcontestant_id\x18\x05 \x01(\x0c\x12\xb4\x01\n\x18start_at_identifier_info\x18\x06 \x01(\x0b\x32\x8c\x01.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityRequest.GetContestedResourceVotersForIdentityRequestV0.StartAtIdentifierInfoH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x07 \x01(\rH\x01\x88\x01\x01\x12\x17\n\x0forder_ascending\x18\x08 \x01(\x08\x12\r\n\x05prove\x18\t \x01(\x08\x1aT\n\x15StartAtIdentifierInfo\x12\x18\n\x10start_identifier\x18\x01 \x01(\x0c\x12!\n\x19start_identifier_included\x18\x02 \x01(\x08\x42\x1b\n\x19_start_at_identifier_infoB\x08\n\x06_countB\t\n\x07version\"\xf1\x04\n-GetContestedResourceVotersForIdentityResponse\x12\x86\x01\n\x02v0\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityResponse.GetContestedResourceVotersForIdentityResponseV0H\x00\x1a\xab\x03\n/GetContestedResourceVotersForIdentityResponseV0\x12\xb6\x01\n\x19\x63ontested_resource_voters\x18\x01 \x01(\x0b\x32\x90\x01.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityResponse.GetContestedResourceVotersForIdentityResponseV0.ContestedResourceVotersH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x43\n\x17\x43ontestedResourceVoters\x12\x0e\n\x06voters\x18\x01 \x03(\x0c\x12\x18\n\x10\x66inished_results\x18\x02 \x01(\x08\x42\x08\n\x06resultB\t\n\x07version\"\xad\x05\n(GetContestedResourceIdentityVotesRequest\x12|\n\x02v0\x18\x01 \x01(\x0b\x32n.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesRequest.GetContestedResourceIdentityVotesRequestV0H\x00\x1a\xf7\x03\n*GetContestedResourceIdentityVotesRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12+\n\x05limit\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12,\n\x06offset\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\x17\n\x0forder_ascending\x18\x04 \x01(\x08\x12\xae\x01\n\x1astart_at_vote_poll_id_info\x18\x05 \x01(\x0b\x32\x84\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesRequest.GetContestedResourceIdentityVotesRequestV0.StartAtVotePollIdInfoH\x00\x88\x01\x01\x12\r\n\x05prove\x18\x06 \x01(\x08\x1a\x61\n\x15StartAtVotePollIdInfo\x12 \n\x18start_at_poll_identifier\x18\x01 \x01(\x0c\x12&\n\x1estart_poll_identifier_included\x18\x02 \x01(\x08\x42\x1d\n\x1b_start_at_vote_poll_id_infoB\t\n\x07version\"\xc8\n\n)GetContestedResourceIdentityVotesResponse\x12~\n\x02v0\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0H\x00\x1a\x8f\t\n+GetContestedResourceIdentityVotesResponseV0\x12\xa1\x01\n\x05votes\x18\x01 \x01(\x0b\x32\x8f\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ContestedResourceIdentityVotesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xf7\x01\n\x1e\x43ontestedResourceIdentityVotes\x12\xba\x01\n!contested_resource_identity_votes\x18\x01 \x03(\x0b\x32\x8e\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ContestedResourceIdentityVote\x12\x18\n\x10\x66inished_results\x18\x02 \x01(\x08\x1a\xad\x02\n\x12ResourceVoteChoice\x12\xad\x01\n\x10vote_choice_type\x18\x01 \x01(\x0e\x32\x92\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ResourceVoteChoice.VoteChoiceType\x12\x18\n\x0bidentity_id\x18\x02 \x01(\x0cH\x00\x88\x01\x01\"=\n\x0eVoteChoiceType\x12\x14\n\x10TOWARDS_IDENTITY\x10\x00\x12\x0b\n\x07\x41\x42STAIN\x10\x01\x12\x08\n\x04LOCK\x10\x02\x42\x0e\n\x0c_identity_id\x1a\x95\x02\n\x1d\x43ontestedResourceIdentityVote\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\'\n\x1fserialized_index_storage_values\x18\x03 \x03(\x0c\x12\x99\x01\n\x0bvote_choice\x18\x04 \x01(\x0b\x32\x83\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ResourceVoteChoiceB\x08\n\x06resultB\t\n\x07version\"\xf0\x01\n%GetPrefundedSpecializedBalanceRequest\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceRequest.GetPrefundedSpecializedBalanceRequestV0H\x00\x1a\x44\n\'GetPrefundedSpecializedBalanceRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xed\x02\n&GetPrefundedSpecializedBalanceResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceResponse.GetPrefundedSpecializedBalanceResponseV0H\x00\x1a\xbd\x01\n(GetPrefundedSpecializedBalanceResponseV0\x12\x15\n\x07\x62\x61lance\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xd0\x01\n GetTotalCreditsInPlatformRequest\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformRequest.GetTotalCreditsInPlatformRequestV0H\x00\x1a\x33\n\"GetTotalCreditsInPlatformRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xd9\x02\n!GetTotalCreditsInPlatformResponse\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformResponse.GetTotalCreditsInPlatformResponseV0H\x00\x1a\xb8\x01\n#GetTotalCreditsInPlatformResponseV0\x12\x15\n\x07\x63redits\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc4\x01\n\x16GetPathElementsRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetPathElementsRequest.GetPathElementsRequestV0H\x00\x1a\x45\n\x18GetPathElementsRequestV0\x12\x0c\n\x04path\x18\x01 \x03(\x0c\x12\x0c\n\x04keys\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xa3\x03\n\x17GetPathElementsResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetPathElementsResponse.GetPathElementsResponseV0H\x00\x1a\xa0\x02\n\x19GetPathElementsResponseV0\x12i\n\x08\x65lements\x18\x01 \x01(\x0b\x32U.org.dash.platform.dapi.v0.GetPathElementsResponse.GetPathElementsResponseV0.ElementsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1c\n\x08\x45lements\x12\x10\n\x08\x65lements\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\x81\x01\n\x10GetStatusRequest\x12L\n\x02v0\x18\x01 \x01(\x0b\x32>.org.dash.platform.dapi.v0.GetStatusRequest.GetStatusRequestV0H\x00\x1a\x14\n\x12GetStatusRequestV0B\t\n\x07version\"\xe4\x10\n\x11GetStatusResponse\x12N\n\x02v0\x18\x01 \x01(\x0b\x32@.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0H\x00\x1a\xf3\x0f\n\x13GetStatusResponseV0\x12Y\n\x07version\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version\x12S\n\x04node\x18\x02 \x01(\x0b\x32\x45.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Node\x12U\n\x05\x63hain\x18\x03 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Chain\x12Y\n\x07network\x18\x04 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Network\x12^\n\nstate_sync\x18\x05 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.StateSync\x12S\n\x04time\x18\x06 \x01(\x0b\x32\x45.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Time\x1a\x82\x05\n\x07Version\x12\x63\n\x08software\x18\x01 \x01(\x0b\x32Q.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Software\x12\x63\n\x08protocol\x18\x02 \x01(\x0b\x32Q.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Protocol\x1a^\n\x08Software\x12\x0c\n\x04\x64\x61pi\x18\x01 \x01(\t\x12\x12\n\x05\x64rive\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x17\n\ntenderdash\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_driveB\r\n\x0b_tenderdash\x1a\xcc\x02\n\x08Protocol\x12p\n\ntenderdash\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Protocol.Tenderdash\x12\x66\n\x05\x64rive\x18\x02 \x01(\x0b\x32W.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Protocol.Drive\x1a(\n\nTenderdash\x12\x0b\n\x03p2p\x18\x01 \x01(\r\x12\r\n\x05\x62lock\x18\x02 \x01(\r\x1a<\n\x05\x44rive\x12\x0e\n\x06latest\x18\x03 \x01(\r\x12\x0f\n\x07\x63urrent\x18\x04 \x01(\r\x12\x12\n\nnext_epoch\x18\x05 \x01(\r\x1a\x7f\n\x04Time\x12\x11\n\x05local\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x16\n\x05\x62lock\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x88\x01\x01\x12\x18\n\x07genesis\x18\x03 \x01(\x04\x42\x02\x30\x01H\x01\x88\x01\x01\x12\x12\n\x05\x65poch\x18\x04 \x01(\rH\x02\x88\x01\x01\x42\x08\n\x06_blockB\n\n\x08_genesisB\x08\n\x06_epoch\x1a<\n\x04Node\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x18\n\x0bpro_tx_hash\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x42\x0e\n\x0c_pro_tx_hash\x1a\xb3\x02\n\x05\x43hain\x12\x13\n\x0b\x63\x61tching_up\x18\x01 \x01(\x08\x12\x19\n\x11latest_block_hash\x18\x02 \x01(\x0c\x12\x17\n\x0flatest_app_hash\x18\x03 \x01(\x0c\x12\x1f\n\x13latest_block_height\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x1b\n\x13\x65\x61rliest_block_hash\x18\x05 \x01(\x0c\x12\x19\n\x11\x65\x61rliest_app_hash\x18\x06 \x01(\x0c\x12!\n\x15\x65\x61rliest_block_height\x18\x07 \x01(\x04\x42\x02\x30\x01\x12!\n\x15max_peer_block_height\x18\t \x01(\x04\x42\x02\x30\x01\x12%\n\x18\x63ore_chain_locked_height\x18\n \x01(\rH\x00\x88\x01\x01\x42\x1b\n\x19_core_chain_locked_height\x1a\x43\n\x07Network\x12\x10\n\x08\x63hain_id\x18\x01 \x01(\t\x12\x13\n\x0bpeers_count\x18\x02 \x01(\r\x12\x11\n\tlistening\x18\x03 \x01(\x08\x1a\x85\x02\n\tStateSync\x12\x1d\n\x11total_synced_time\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1a\n\x0eremaining_time\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x17\n\x0ftotal_snapshots\x18\x03 \x01(\r\x12\"\n\x16\x63hunk_process_avg_time\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x1b\n\x0fsnapshot_height\x18\x05 \x01(\x04\x42\x02\x30\x01\x12!\n\x15snapshot_chunks_count\x18\x06 \x01(\x04\x42\x02\x30\x01\x12\x1d\n\x11\x62\x61\x63kfilled_blocks\x18\x07 \x01(\x04\x42\x02\x30\x01\x12!\n\x15\x62\x61\x63kfill_blocks_total\x18\x08 \x01(\x04\x42\x02\x30\x01\x42\t\n\x07version\"\xb1\x01\n\x1cGetCurrentQuorumsInfoRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoRequest.GetCurrentQuorumsInfoRequestV0H\x00\x1a \n\x1eGetCurrentQuorumsInfoRequestV0B\t\n\x07version\"\xa1\x05\n\x1dGetCurrentQuorumsInfoResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse.GetCurrentQuorumsInfoResponseV0H\x00\x1a\x46\n\x0bValidatorV0\x12\x13\n\x0bpro_tx_hash\x18\x01 \x01(\x0c\x12\x0f\n\x07node_ip\x18\x02 \x01(\t\x12\x11\n\tis_banned\x18\x03 \x01(\x08\x1a\xaf\x01\n\x0eValidatorSetV0\x12\x13\n\x0bquorum_hash\x18\x01 \x01(\x0c\x12\x13\n\x0b\x63ore_height\x18\x02 \x01(\r\x12U\n\x07members\x18\x03 \x03(\x0b\x32\x44.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse.ValidatorV0\x12\x1c\n\x14threshold_public_key\x18\x04 \x01(\x0c\x1a\x92\x02\n\x1fGetCurrentQuorumsInfoResponseV0\x12\x15\n\rquorum_hashes\x18\x01 \x03(\x0c\x12\x1b\n\x13\x63urrent_quorum_hash\x18\x02 \x01(\x0c\x12_\n\x0evalidator_sets\x18\x03 \x03(\x0b\x32G.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse.ValidatorSetV0\x12\x1b\n\x13last_block_proposer\x18\x04 \x01(\x0c\x12=\n\x08metadata\x18\x05 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\t\n\x07version\"\xf4\x01\n\x1fGetIdentityTokenBalancesRequest\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetIdentityTokenBalancesRequest.GetIdentityTokenBalancesRequestV0H\x00\x1aZ\n!GetIdentityTokenBalancesRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x11\n\ttoken_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xad\x05\n GetIdentityTokenBalancesResponse\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse.GetIdentityTokenBalancesResponseV0H\x00\x1a\x8f\x04\n\"GetIdentityTokenBalancesResponseV0\x12\x86\x01\n\x0etoken_balances\x18\x01 \x01(\x0b\x32l.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse.GetIdentityTokenBalancesResponseV0.TokenBalancesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aG\n\x11TokenBalanceEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x14\n\x07\x62\x61lance\x18\x02 \x01(\x04H\x00\x88\x01\x01\x42\n\n\x08_balance\x1a\x9a\x01\n\rTokenBalances\x12\x88\x01\n\x0etoken_balances\x18\x01 \x03(\x0b\x32p.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse.GetIdentityTokenBalancesResponseV0.TokenBalanceEntryB\x08\n\x06resultB\t\n\x07version\"\xfc\x01\n!GetIdentitiesTokenBalancesRequest\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesRequest.GetIdentitiesTokenBalancesRequestV0H\x00\x1a\\\n#GetIdentitiesTokenBalancesRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x14\n\x0cidentity_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xf2\x05\n\"GetIdentitiesTokenBalancesResponse\x12p\n\x02v0\x18\x01 \x01(\x0b\x32\x62.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse.GetIdentitiesTokenBalancesResponseV0H\x00\x1a\xce\x04\n$GetIdentitiesTokenBalancesResponseV0\x12\x9b\x01\n\x17identity_token_balances\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse.GetIdentitiesTokenBalancesResponseV0.IdentityTokenBalancesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aR\n\x19IdentityTokenBalanceEntry\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x14\n\x07\x62\x61lance\x18\x02 \x01(\x04H\x00\x88\x01\x01\x42\n\n\x08_balance\x1a\xb7\x01\n\x15IdentityTokenBalances\x12\x9d\x01\n\x17identity_token_balances\x18\x01 \x03(\x0b\x32|.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse.GetIdentitiesTokenBalancesResponseV0.IdentityTokenBalanceEntryB\x08\n\x06resultB\t\n\x07version\"\xe8\x01\n\x1cGetIdentityTokenInfosRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetIdentityTokenInfosRequest.GetIdentityTokenInfosRequestV0H\x00\x1aW\n\x1eGetIdentityTokenInfosRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x11\n\ttoken_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\x98\x06\n\x1dGetIdentityTokenInfosResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0H\x00\x1a\x83\x05\n\x1fGetIdentityTokenInfosResponseV0\x12z\n\x0btoken_infos\x18\x01 \x01(\x0b\x32\x63.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a(\n\x16TokenIdentityInfoEntry\x12\x0e\n\x06\x66rozen\x18\x01 \x01(\x08\x1a\xb0\x01\n\x0eTokenInfoEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x82\x01\n\x04info\x18\x02 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenIdentityInfoEntryH\x00\x88\x01\x01\x42\x07\n\x05_info\x1a\x8a\x01\n\nTokenInfos\x12|\n\x0btoken_infos\x18\x01 \x03(\x0b\x32g.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenInfoEntryB\x08\n\x06resultB\t\n\x07version\"\xf0\x01\n\x1eGetIdentitiesTokenInfosRequest\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosRequest.GetIdentitiesTokenInfosRequestV0H\x00\x1aY\n GetIdentitiesTokenInfosRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x14\n\x0cidentity_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xca\x06\n\x1fGetIdentitiesTokenInfosResponse\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0H\x00\x1a\xaf\x05\n!GetIdentitiesTokenInfosResponseV0\x12\x8f\x01\n\x14identity_token_infos\x18\x01 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0.IdentityTokenInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a(\n\x16TokenIdentityInfoEntry\x12\x0e\n\x06\x66rozen\x18\x01 \x01(\x08\x1a\xb7\x01\n\x0eTokenInfoEntry\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x86\x01\n\x04info\x18\x02 \x01(\x0b\x32s.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0.TokenIdentityInfoEntryH\x00\x88\x01\x01\x42\x07\n\x05_info\x1a\x97\x01\n\x12IdentityTokenInfos\x12\x80\x01\n\x0btoken_infos\x18\x01 \x03(\x0b\x32k.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0.TokenInfoEntryB\x08\n\x06resultB\t\n\x07version\"\xbf\x01\n\x17GetTokenStatusesRequest\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetTokenStatusesRequest.GetTokenStatusesRequestV0H\x00\x1a=\n\x19GetTokenStatusesRequestV0\x12\x11\n\ttoken_ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xe7\x04\n\x18GetTokenStatusesResponse\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetTokenStatusesResponse.GetTokenStatusesResponseV0H\x00\x1a\xe1\x03\n\x1aGetTokenStatusesResponseV0\x12v\n\x0etoken_statuses\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetTokenStatusesResponse.GetTokenStatusesResponseV0.TokenStatusesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x44\n\x10TokenStatusEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x13\n\x06paused\x18\x02 \x01(\x08H\x00\x88\x01\x01\x42\t\n\x07_paused\x1a\x88\x01\n\rTokenStatuses\x12w\n\x0etoken_statuses\x18\x01 \x03(\x0b\x32_.org.dash.platform.dapi.v0.GetTokenStatusesResponse.GetTokenStatusesResponseV0.TokenStatusEntryB\x08\n\x06resultB\t\n\x07version\"\xef\x01\n#GetTokenDirectPurchasePricesRequest\x12r\n\x02v0\x18\x01 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesRequest.GetTokenDirectPurchasePricesRequestV0H\x00\x1aI\n%GetTokenDirectPurchasePricesRequestV0\x12\x11\n\ttoken_ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x8b\t\n$GetTokenDirectPurchasePricesResponse\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0H\x00\x1a\xe1\x07\n&GetTokenDirectPurchasePricesResponseV0\x12\xa9\x01\n\x1ctoken_direct_purchase_prices\x18\x01 \x01(\x0b\x32\x80\x01.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.TokenDirectPurchasePricesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x33\n\x10PriceForQuantity\x12\x10\n\x08quantity\x18\x01 \x01(\x04\x12\r\n\x05price\x18\x02 \x01(\x04\x1a\xa7\x01\n\x0fPricingSchedule\x12\x93\x01\n\x12price_for_quantity\x18\x01 \x03(\x0b\x32w.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.PriceForQuantity\x1a\xe4\x01\n\x1dTokenDirectPurchasePriceEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x15\n\x0b\x66ixed_price\x18\x02 \x01(\x04H\x00\x12\x90\x01\n\x0evariable_price\x18\x03 \x01(\x0b\x32v.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.PricingScheduleH\x00\x42\x07\n\x05price\x1a\xc8\x01\n\x19TokenDirectPurchasePrices\x12\xaa\x01\n\x1btoken_direct_purchase_price\x18\x01 \x03(\x0b\x32\x84\x01.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.TokenDirectPurchasePriceEntryB\x08\n\x06resultB\t\n\x07version\"\xce\x01\n\x1bGetTokenContractInfoRequest\x12\x62\n\x02v0\x18\x01 \x01(\x0b\x32T.org.dash.platform.dapi.v0.GetTokenContractInfoRequest.GetTokenContractInfoRequestV0H\x00\x1a@\n\x1dGetTokenContractInfoRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xfb\x03\n\x1cGetTokenContractInfoResponse\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetTokenContractInfoResponse.GetTokenContractInfoResponseV0H\x00\x1a\xe9\x02\n\x1eGetTokenContractInfoResponseV0\x12|\n\x04\x64\x61ta\x18\x01 \x01(\x0b\x32l.org.dash.platform.dapi.v0.GetTokenContractInfoResponse.GetTokenContractInfoResponseV0.TokenContractInfoDataH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aM\n\x15TokenContractInfoData\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17token_contract_position\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xef\x04\n)GetTokenPreProgrammedDistributionsRequest\x12~\n\x02v0\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsRequest.GetTokenPreProgrammedDistributionsRequestV0H\x00\x1a\xb6\x03\n+GetTokenPreProgrammedDistributionsRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x98\x01\n\rstart_at_info\x18\x02 \x01(\x0b\x32|.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsRequest.GetTokenPreProgrammedDistributionsRequestV0.StartAtInfoH\x00\x88\x01\x01\x12\x12\n\x05limit\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\x04 \x01(\x08\x1a\x9a\x01\n\x0bStartAtInfo\x12\x15\n\rstart_time_ms\x18\x01 \x01(\x04\x12\x1c\n\x0fstart_recipient\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12%\n\x18start_recipient_included\x18\x03 \x01(\x08H\x01\x88\x01\x01\x42\x12\n\x10_start_recipientB\x1b\n\x19_start_recipient_includedB\x10\n\x0e_start_at_infoB\x08\n\x06_limitB\t\n\x07version\"\xec\x07\n*GetTokenPreProgrammedDistributionsResponse\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0H\x00\x1a\xaf\x06\n,GetTokenPreProgrammedDistributionsResponseV0\x12\xa5\x01\n\x13token_distributions\x18\x01 \x01(\x0b\x32\x85\x01.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0.TokenDistributionsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a>\n\x16TokenDistributionEntry\x12\x14\n\x0crecipient_id\x18\x01 \x01(\x0c\x12\x0e\n\x06\x61mount\x18\x02 \x01(\x04\x1a\xd4\x01\n\x1bTokenTimedDistributionEntry\x12\x11\n\ttimestamp\x18\x01 \x01(\x04\x12\xa1\x01\n\rdistributions\x18\x02 \x03(\x0b\x32\x89\x01.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0.TokenDistributionEntry\x1a\xc3\x01\n\x12TokenDistributions\x12\xac\x01\n\x13token_distributions\x18\x01 \x03(\x0b\x32\x8e\x01.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0.TokenTimedDistributionEntryB\x08\n\x06resultB\t\n\x07version\"\x82\x04\n-GetTokenPerpetualDistributionLastClaimRequest\x12\x86\x01\n\x02v0\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimRequest.GetTokenPerpetualDistributionLastClaimRequestV0H\x00\x1aI\n\x11\x43ontractTokenInfo\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17token_contract_position\x18\x02 \x01(\r\x1a\xf1\x01\n/GetTokenPerpetualDistributionLastClaimRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12v\n\rcontract_info\x18\x02 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimRequest.ContractTokenInfoH\x00\x88\x01\x01\x12\x13\n\x0bidentity_id\x18\x04 \x01(\x0c\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\x10\n\x0e_contract_infoB\t\n\x07version\"\x93\x05\n.GetTokenPerpetualDistributionLastClaimResponse\x12\x88\x01\n\x02v0\x18\x01 \x01(\x0b\x32z.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimResponse.GetTokenPerpetualDistributionLastClaimResponseV0H\x00\x1a\xca\x03\n0GetTokenPerpetualDistributionLastClaimResponseV0\x12\x9f\x01\n\nlast_claim\x18\x01 \x01(\x0b\x32\x88\x01.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimResponse.GetTokenPerpetualDistributionLastClaimResponseV0.LastClaimInfoH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1ax\n\rLastClaimInfo\x12\x1a\n\x0ctimestamp_ms\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x1a\n\x0c\x62lock_height\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x12\x0f\n\x05\x65poch\x18\x03 \x01(\rH\x00\x12\x13\n\traw_bytes\x18\x04 \x01(\x0cH\x00\x42\t\n\x07paid_atB\x08\n\x06resultB\t\n\x07version\"\xca\x01\n\x1aGetTokenTotalSupplyRequest\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetTokenTotalSupplyRequest.GetTokenTotalSupplyRequestV0H\x00\x1a?\n\x1cGetTokenTotalSupplyRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xaf\x04\n\x1bGetTokenTotalSupplyResponse\x12\x62\n\x02v0\x18\x01 \x01(\x0b\x32T.org.dash.platform.dapi.v0.GetTokenTotalSupplyResponse.GetTokenTotalSupplyResponseV0H\x00\x1a\xa0\x03\n\x1dGetTokenTotalSupplyResponseV0\x12\x88\x01\n\x12token_total_supply\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetTokenTotalSupplyResponse.GetTokenTotalSupplyResponseV0.TokenTotalSupplyEntryH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1ax\n\x15TokenTotalSupplyEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x30\n(total_aggregated_amount_in_user_accounts\x18\x02 \x01(\x04\x12\x1b\n\x13total_system_amount\x18\x03 \x01(\x04\x42\x08\n\x06resultB\t\n\x07version\"\xd2\x01\n\x13GetGroupInfoRequest\x12R\n\x02v0\x18\x01 \x01(\x0b\x32\x44.org.dash.platform.dapi.v0.GetGroupInfoRequest.GetGroupInfoRequestV0H\x00\x1a\\\n\x15GetGroupInfoRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17group_contract_position\x18\x02 \x01(\r\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xd4\x05\n\x14GetGroupInfoResponse\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0H\x00\x1a\xda\x04\n\x16GetGroupInfoResponseV0\x12\x66\n\ngroup_info\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0.GroupInfoH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x04 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x34\n\x10GroupMemberEntry\x12\x11\n\tmember_id\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x02 \x01(\r\x1a\x98\x01\n\x0eGroupInfoEntry\x12h\n\x07members\x18\x01 \x03(\x0b\x32W.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0.GroupMemberEntry\x12\x1c\n\x14group_required_power\x18\x02 \x01(\r\x1a\x8a\x01\n\tGroupInfo\x12n\n\ngroup_info\x18\x01 \x01(\x0b\x32U.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0.GroupInfoEntryH\x00\x88\x01\x01\x42\r\n\x0b_group_infoB\x08\n\x06resultB\t\n\x07version\"\xed\x03\n\x14GetGroupInfosRequest\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetGroupInfosRequest.GetGroupInfosRequestV0H\x00\x1au\n\x1cStartAtGroupContractPosition\x12%\n\x1dstart_group_contract_position\x18\x01 \x01(\r\x12.\n&start_group_contract_position_included\x18\x02 \x01(\x08\x1a\xfc\x01\n\x16GetGroupInfosRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12{\n start_at_group_contract_position\x18\x02 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetGroupInfosRequest.StartAtGroupContractPositionH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\x04 \x01(\x08\x42#\n!_start_at_group_contract_positionB\x08\n\x06_countB\t\n\x07version\"\xff\x05\n\x15GetGroupInfosResponse\x12V\n\x02v0\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0H\x00\x1a\x82\x05\n\x17GetGroupInfosResponseV0\x12j\n\x0bgroup_infos\x18\x01 \x01(\x0b\x32S.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0.GroupInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x04 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x34\n\x10GroupMemberEntry\x12\x11\n\tmember_id\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x02 \x01(\r\x1a\xc3\x01\n\x16GroupPositionInfoEntry\x12\x1f\n\x17group_contract_position\x18\x01 \x01(\r\x12j\n\x07members\x18\x02 \x03(\x0b\x32Y.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0.GroupMemberEntry\x12\x1c\n\x14group_required_power\x18\x03 \x01(\r\x1a\x82\x01\n\nGroupInfos\x12t\n\x0bgroup_infos\x18\x01 \x03(\x0b\x32_.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0.GroupPositionInfoEntryB\x08\n\x06resultB\t\n\x07version\"\xbe\x04\n\x16GetGroupActionsRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetGroupActionsRequest.GetGroupActionsRequestV0H\x00\x1aL\n\x0fStartAtActionId\x12\x17\n\x0fstart_action_id\x18\x01 \x01(\x0c\x12 \n\x18start_action_id_included\x18\x02 \x01(\x08\x1a\xc8\x02\n\x18GetGroupActionsRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17group_contract_position\x18\x02 \x01(\r\x12N\n\x06status\x18\x03 \x01(\x0e\x32>.org.dash.platform.dapi.v0.GetGroupActionsRequest.ActionStatus\x12\x62\n\x12start_at_action_id\x18\x04 \x01(\x0b\x32\x41.org.dash.platform.dapi.v0.GetGroupActionsRequest.StartAtActionIdH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x05 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\x06 \x01(\x08\x42\x15\n\x13_start_at_action_idB\x08\n\x06_count\"&\n\x0c\x41\x63tionStatus\x12\n\n\x06\x41\x43TIVE\x10\x00\x12\n\n\x06\x43LOSED\x10\x01\x42\t\n\x07version\"\xd6\x1e\n\x17GetGroupActionsResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0H\x00\x1a\xd3\x1d\n\x19GetGroupActionsResponseV0\x12r\n\rgroup_actions\x18\x01 \x01(\x0b\x32Y.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.GroupActionsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a[\n\tMintEvent\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x04\x12\x14\n\x0crecipient_id\x18\x02 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a[\n\tBurnEvent\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x04\x12\x14\n\x0c\x62urn_from_id\x18\x02 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1aJ\n\x0b\x46reezeEvent\x12\x11\n\tfrozen_id\x18\x01 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1aL\n\rUnfreezeEvent\x12\x11\n\tfrozen_id\x18\x01 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a\x66\n\x17\x44\x65stroyFrozenFundsEvent\x12\x11\n\tfrozen_id\x18\x01 \x01(\x0c\x12\x0e\n\x06\x61mount\x18\x02 \x01(\x04\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a\x64\n\x13SharedEncryptedNote\x12\x18\n\x10sender_key_index\x18\x01 \x01(\r\x12\x1b\n\x13recipient_key_index\x18\x02 \x01(\r\x12\x16\n\x0e\x65ncrypted_data\x18\x03 \x01(\x0c\x1a{\n\x15PersonalEncryptedNote\x12!\n\x19root_encryption_key_index\x18\x01 \x01(\r\x12\'\n\x1f\x64\x65rivation_encryption_key_index\x18\x02 \x01(\r\x12\x16\n\x0e\x65ncrypted_data\x18\x03 \x01(\x0c\x1a\xe9\x01\n\x14\x45mergencyActionEvent\x12\x81\x01\n\x0b\x61\x63tion_type\x18\x01 \x01(\x0e\x32l.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.EmergencyActionEvent.ActionType\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\"#\n\nActionType\x12\t\n\x05PAUSE\x10\x00\x12\n\n\x06RESUME\x10\x01\x42\x0e\n\x0c_public_note\x1a\x64\n\x16TokenConfigUpdateEvent\x12 \n\x18token_config_update_item\x18\x01 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a\xe6\x03\n\x1eUpdateDirectPurchasePriceEvent\x12\x15\n\x0b\x66ixed_price\x18\x01 \x01(\x04H\x00\x12\x95\x01\n\x0evariable_price\x18\x02 \x01(\x0b\x32{.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UpdateDirectPurchasePriceEvent.PricingScheduleH\x00\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x01\x88\x01\x01\x1a\x33\n\x10PriceForQuantity\x12\x10\n\x08quantity\x18\x01 \x01(\x04\x12\r\n\x05price\x18\x02 \x01(\x04\x1a\xac\x01\n\x0fPricingSchedule\x12\x98\x01\n\x12price_for_quantity\x18\x01 \x03(\x0b\x32|.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UpdateDirectPurchasePriceEvent.PriceForQuantityB\x07\n\x05priceB\x0e\n\x0c_public_note\x1a\xfc\x02\n\x10GroupActionEvent\x12n\n\x0btoken_event\x18\x01 \x01(\x0b\x32W.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.TokenEventH\x00\x12t\n\x0e\x64ocument_event\x18\x02 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.DocumentEventH\x00\x12t\n\x0e\x63ontract_event\x18\x03 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.ContractEventH\x00\x42\x0c\n\nevent_type\x1a\x8b\x01\n\rDocumentEvent\x12r\n\x06\x63reate\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.DocumentCreateEventH\x00\x42\x06\n\x04type\x1a/\n\x13\x44ocumentCreateEvent\x12\x18\n\x10\x63reated_document\x18\x01 \x01(\x0c\x1a/\n\x13\x43ontractUpdateEvent\x12\x18\n\x10updated_contract\x18\x01 \x01(\x0c\x1a\x8b\x01\n\rContractEvent\x12r\n\x06update\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.ContractUpdateEventH\x00\x42\x06\n\x04type\x1a\xd1\x07\n\nTokenEvent\x12\x66\n\x04mint\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.MintEventH\x00\x12\x66\n\x04\x62urn\x18\x02 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.BurnEventH\x00\x12j\n\x06\x66reeze\x18\x03 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.FreezeEventH\x00\x12n\n\x08unfreeze\x18\x04 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UnfreezeEventH\x00\x12\x84\x01\n\x14\x64\x65stroy_frozen_funds\x18\x05 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.DestroyFrozenFundsEventH\x00\x12}\n\x10\x65mergency_action\x18\x06 \x01(\x0b\x32\x61.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.EmergencyActionEventH\x00\x12\x82\x01\n\x13token_config_update\x18\x07 \x01(\x0b\x32\x63.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.TokenConfigUpdateEventH\x00\x12\x83\x01\n\x0cupdate_price\x18\x08 \x01(\x0b\x32k.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UpdateDirectPurchasePriceEventH\x00\x42\x06\n\x04type\x1a\x93\x01\n\x10GroupActionEntry\x12\x11\n\taction_id\x18\x01 \x01(\x0c\x12l\n\x05\x65vent\x18\x02 \x01(\x0b\x32].org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.GroupActionEvent\x1a\x84\x01\n\x0cGroupActions\x12t\n\rgroup_actions\x18\x01 \x03(\x0b\x32].org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.GroupActionEntryB\x08\n\x06resultB\t\n\x07version\"\x88\x03\n\x1cGetGroupActionSignersRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetGroupActionSignersRequest.GetGroupActionSignersRequestV0H\x00\x1a\xce\x01\n\x1eGetGroupActionSignersRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17group_contract_position\x18\x02 \x01(\r\x12T\n\x06status\x18\x03 \x01(\x0e\x32\x44.org.dash.platform.dapi.v0.GetGroupActionSignersRequest.ActionStatus\x12\x11\n\taction_id\x18\x04 \x01(\x0c\x12\r\n\x05prove\x18\x05 \x01(\x08\"&\n\x0c\x41\x63tionStatus\x12\n\n\x06\x41\x43TIVE\x10\x00\x12\n\n\x06\x43LOSED\x10\x01\x42\t\n\x07version\"\x8b\x05\n\x1dGetGroupActionSignersResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetGroupActionSignersResponse.GetGroupActionSignersResponseV0H\x00\x1a\xf6\x03\n\x1fGetGroupActionSignersResponseV0\x12\x8b\x01\n\x14group_action_signers\x18\x01 \x01(\x0b\x32k.org.dash.platform.dapi.v0.GetGroupActionSignersResponse.GetGroupActionSignersResponseV0.GroupActionSignersH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x35\n\x11GroupActionSigner\x12\x11\n\tsigner_id\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x02 \x01(\r\x1a\x91\x01\n\x12GroupActionSigners\x12{\n\x07signers\x18\x01 \x03(\x0b\x32j.org.dash.platform.dapi.v0.GetGroupActionSignersResponse.GetGroupActionSignersResponseV0.GroupActionSignerB\x08\n\x06resultB\t\n\x07version\"\xb5\x01\n\x15GetAddressInfoRequest\x12V\n\x02v0\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetAddressInfoRequest.GetAddressInfoRequestV0H\x00\x1a\x39\n\x17GetAddressInfoRequestV0\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x85\x01\n\x10\x41\x64\x64ressInfoEntry\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12J\n\x11\x62\x61lance_and_nonce\x18\x02 \x01(\x0b\x32*.org.dash.platform.dapi.v0.BalanceAndNonceH\x00\x88\x01\x01\x42\x14\n\x12_balance_and_nonce\"1\n\x0f\x42\x61lanceAndNonce\x12\x0f\n\x07\x62\x61lance\x18\x01 \x01(\x04\x12\r\n\x05nonce\x18\x02 \x01(\r\"_\n\x12\x41\x64\x64ressInfoEntries\x12I\n\x14\x61\x64\x64ress_info_entries\x18\x01 \x03(\x0b\x32+.org.dash.platform.dapi.v0.AddressInfoEntry\"m\n\x14\x41\x64\x64ressBalanceChange\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x19\n\x0bset_balance\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x12\x1c\n\x0e\x61\x64\x64_to_balance\x18\x03 \x01(\x04\x42\x02\x30\x01H\x00\x42\x0b\n\toperation\"x\n\x1a\x42lockAddressBalanceChanges\x12\x18\n\x0c\x62lock_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12@\n\x07\x63hanges\x18\x02 \x03(\x0b\x32/.org.dash.platform.dapi.v0.AddressBalanceChange\"k\n\x1b\x41\x64\x64ressBalanceUpdateEntries\x12L\n\rblock_changes\x18\x01 \x03(\x0b\x32\x35.org.dash.platform.dapi.v0.BlockAddressBalanceChanges\"\xe1\x02\n\x16GetAddressInfoResponse\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetAddressInfoResponse.GetAddressInfoResponseV0H\x00\x1a\xe1\x01\n\x18GetAddressInfoResponseV0\x12I\n\x12\x61\x64\x64ress_info_entry\x18\x01 \x01(\x0b\x32+.org.dash.platform.dapi.v0.AddressInfoEntryH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc3\x01\n\x18GetAddressesInfosRequest\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetAddressesInfosRequest.GetAddressesInfosRequestV0H\x00\x1a>\n\x1aGetAddressesInfosRequestV0\x12\x11\n\taddresses\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xf1\x02\n\x19GetAddressesInfosResponse\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetAddressesInfosResponse.GetAddressesInfosResponseV0H\x00\x1a\xe8\x01\n\x1bGetAddressesInfosResponseV0\x12M\n\x14\x61\x64\x64ress_info_entries\x18\x01 \x01(\x0b\x32-.org.dash.platform.dapi.v0.AddressInfoEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xb5\x01\n\x1dGetAddressesTrunkStateRequest\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetAddressesTrunkStateRequest.GetAddressesTrunkStateRequestV0H\x00\x1a!\n\x1fGetAddressesTrunkStateRequestV0B\t\n\x07version\"\xaa\x02\n\x1eGetAddressesTrunkStateResponse\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetAddressesTrunkStateResponse.GetAddressesTrunkStateResponseV0H\x00\x1a\x92\x01\n GetAddressesTrunkStateResponseV0\x12/\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.Proof\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\t\n\x07version\"\xf0\x01\n\x1eGetAddressesBranchStateRequest\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetAddressesBranchStateRequest.GetAddressesBranchStateRequestV0H\x00\x1aY\n GetAddressesBranchStateRequestV0\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\r\n\x05\x64\x65pth\x18\x02 \x01(\r\x12\x19\n\x11\x63heckpoint_height\x18\x03 \x01(\x04\x42\t\n\x07version\"\xd1\x01\n\x1fGetAddressesBranchStateResponse\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetAddressesBranchStateResponse.GetAddressesBranchStateResponseV0H\x00\x1a\x37\n!GetAddressesBranchStateResponseV0\x12\x12\n\nmerk_proof\x18\x02 \x01(\x0c\x42\t\n\x07version\"\xfe\x01\n%GetRecentAddressBalanceChangesRequest\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesRequest.GetRecentAddressBalanceChangesRequestV0H\x00\x1aR\n\'GetRecentAddressBalanceChangesRequestV0\x12\x18\n\x0cstart_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xb8\x03\n&GetRecentAddressBalanceChangesResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesResponse.GetRecentAddressBalanceChangesResponseV0H\x00\x1a\x88\x02\n(GetRecentAddressBalanceChangesResponseV0\x12`\n\x1e\x61\x64\x64ress_balance_update_entries\x18\x01 \x01(\x0b\x32\x36.org.dash.platform.dapi.v0.AddressBalanceUpdateEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"G\n\x16\x42lockHeightCreditEntry\x12\x18\n\x0c\x62lock_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x13\n\x07\x63redits\x18\x02 \x01(\x04\x42\x02\x30\x01\"\xb0\x01\n\x1d\x43ompactedAddressBalanceChange\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x19\n\x0bset_credits\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x12V\n\x19\x61\x64\x64_to_credits_operations\x18\x03 \x01(\x0b\x32\x31.org.dash.platform.dapi.v0.AddToCreditsOperationsH\x00\x42\x0b\n\toperation\"\\\n\x16\x41\x64\x64ToCreditsOperations\x12\x42\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x31.org.dash.platform.dapi.v0.BlockHeightCreditEntry\"\xae\x01\n#CompactedBlockAddressBalanceChanges\x12\x1e\n\x12start_block_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1c\n\x10\x65nd_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12I\n\x07\x63hanges\x18\x03 \x03(\x0b\x32\x38.org.dash.platform.dapi.v0.CompactedAddressBalanceChange\"\x87\x01\n$CompactedAddressBalanceUpdateEntries\x12_\n\x17\x63ompacted_block_changes\x18\x01 \x03(\x0b\x32>.org.dash.platform.dapi.v0.CompactedBlockAddressBalanceChanges\"\xa9\x02\n.GetRecentCompactedAddressBalanceChangesRequest\x12\x88\x01\n\x02v0\x18\x01 \x01(\x0b\x32z.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesRequest.GetRecentCompactedAddressBalanceChangesRequestV0H\x00\x1a\x61\n0GetRecentCompactedAddressBalanceChangesRequestV0\x12\x1e\n\x12start_block_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xf0\x03\n/GetRecentCompactedAddressBalanceChangesResponse\x12\x8a\x01\n\x02v0\x18\x01 \x01(\x0b\x32|.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0H\x00\x1a\xa4\x02\n1GetRecentCompactedAddressBalanceChangesResponseV0\x12s\n(compacted_address_balance_update_entries\x18\x01 \x01(\x0b\x32?.org.dash.platform.dapi.v0.CompactedAddressBalanceUpdateEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version*Z\n\nKeyPurpose\x12\x12\n\x0e\x41UTHENTICATION\x10\x00\x12\x0e\n\nENCRYPTION\x10\x01\x12\x0e\n\nDECRYPTION\x10\x02\x12\x0c\n\x08TRANSFER\x10\x03\x12\n\n\x06VOTING\x10\x05\x32\xea<\n\x08Platform\x12\x93\x01\n\x18\x62roadcastStateTransition\x12:.org.dash.platform.dapi.v0.BroadcastStateTransitionRequest\x1a;.org.dash.platform.dapi.v0.BroadcastStateTransitionResponse\x12l\n\x0bgetIdentity\x12-.org.dash.platform.dapi.v0.GetIdentityRequest\x1a..org.dash.platform.dapi.v0.GetIdentityResponse\x12x\n\x0fgetIdentityKeys\x12\x31.org.dash.platform.dapi.v0.GetIdentityKeysRequest\x1a\x32.org.dash.platform.dapi.v0.GetIdentityKeysResponse\x12\x96\x01\n\x19getIdentitiesContractKeys\x12;.org.dash.platform.dapi.v0.GetIdentitiesContractKeysRequest\x1a<.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse\x12{\n\x10getIdentityNonce\x12\x32.org.dash.platform.dapi.v0.GetIdentityNonceRequest\x1a\x33.org.dash.platform.dapi.v0.GetIdentityNonceResponse\x12\x93\x01\n\x18getIdentityContractNonce\x12:.org.dash.platform.dapi.v0.GetIdentityContractNonceRequest\x1a;.org.dash.platform.dapi.v0.GetIdentityContractNonceResponse\x12\x81\x01\n\x12getIdentityBalance\x12\x34.org.dash.platform.dapi.v0.GetIdentityBalanceRequest\x1a\x35.org.dash.platform.dapi.v0.GetIdentityBalanceResponse\x12\x8a\x01\n\x15getIdentitiesBalances\x12\x37.org.dash.platform.dapi.v0.GetIdentitiesBalancesRequest\x1a\x38.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse\x12\xa2\x01\n\x1dgetIdentityBalanceAndRevision\x12?.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionRequest\x1a@.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionResponse\x12\xaf\x01\n#getEvonodesProposedEpochBlocksByIds\x12\x45.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByIdsRequest\x1a\x41.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse\x12\xb3\x01\n%getEvonodesProposedEpochBlocksByRange\x12G.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByRangeRequest\x1a\x41.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse\x12x\n\x0fgetDataContract\x12\x31.org.dash.platform.dapi.v0.GetDataContractRequest\x1a\x32.org.dash.platform.dapi.v0.GetDataContractResponse\x12\x8d\x01\n\x16getDataContractHistory\x12\x38.org.dash.platform.dapi.v0.GetDataContractHistoryRequest\x1a\x39.org.dash.platform.dapi.v0.GetDataContractHistoryResponse\x12{\n\x10getDataContracts\x12\x32.org.dash.platform.dapi.v0.GetDataContractsRequest\x1a\x33.org.dash.platform.dapi.v0.GetDataContractsResponse\x12o\n\x0cgetDocuments\x12..org.dash.platform.dapi.v0.GetDocumentsRequest\x1a/.org.dash.platform.dapi.v0.GetDocumentsResponse\x12\x99\x01\n\x1agetIdentityByPublicKeyHash\x12<.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashRequest\x1a=.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashResponse\x12\xb4\x01\n#getIdentityByNonUniquePublicKeyHash\x12\x45.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashRequest\x1a\x46.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse\x12\x9f\x01\n\x1cwaitForStateTransitionResult\x12>.org.dash.platform.dapi.v0.WaitForStateTransitionResultRequest\x1a?.org.dash.platform.dapi.v0.WaitForStateTransitionResultResponse\x12\x81\x01\n\x12getConsensusParams\x12\x34.org.dash.platform.dapi.v0.GetConsensusParamsRequest\x1a\x35.org.dash.platform.dapi.v0.GetConsensusParamsResponse\x12\xa5\x01\n\x1egetProtocolVersionUpgradeState\x12@.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateRequest\x1a\x41.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse\x12\xb4\x01\n#getProtocolVersionUpgradeVoteStatus\x12\x45.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusRequest\x1a\x46.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse\x12r\n\rgetEpochsInfo\x12/.org.dash.platform.dapi.v0.GetEpochsInfoRequest\x1a\x30.org.dash.platform.dapi.v0.GetEpochsInfoResponse\x12\x8d\x01\n\x16getFinalizedEpochInfos\x12\x38.org.dash.platform.dapi.v0.GetFinalizedEpochInfosRequest\x1a\x39.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse\x12\x8a\x01\n\x15getContestedResources\x12\x37.org.dash.platform.dapi.v0.GetContestedResourcesRequest\x1a\x38.org.dash.platform.dapi.v0.GetContestedResourcesResponse\x12\xa2\x01\n\x1dgetContestedResourceVoteState\x12?.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest\x1a@.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse\x12\xba\x01\n%getContestedResourceVotersForIdentity\x12G.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityRequest\x1aH.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityResponse\x12\xae\x01\n!getContestedResourceIdentityVotes\x12\x43.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesRequest\x1a\x44.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse\x12\x8a\x01\n\x15getVotePollsByEndDate\x12\x37.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest\x1a\x38.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse\x12\xa5\x01\n\x1egetPrefundedSpecializedBalance\x12@.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceRequest\x1a\x41.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceResponse\x12\x96\x01\n\x19getTotalCreditsInPlatform\x12;.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformRequest\x1a<.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformResponse\x12x\n\x0fgetPathElements\x12\x31.org.dash.platform.dapi.v0.GetPathElementsRequest\x1a\x32.org.dash.platform.dapi.v0.GetPathElementsResponse\x12\x66\n\tgetStatus\x12+.org.dash.platform.dapi.v0.GetStatusRequest\x1a,.org.dash.platform.dapi.v0.GetStatusResponse\x12\x8a\x01\n\x15getCurrentQuorumsInfo\x12\x37.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoRequest\x1a\x38.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse\x12\x93\x01\n\x18getIdentityTokenBalances\x12:.org.dash.platform.dapi.v0.GetIdentityTokenBalancesRequest\x1a;.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse\x12\x99\x01\n\x1agetIdentitiesTokenBalances\x12<.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesRequest\x1a=.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse\x12\x8a\x01\n\x15getIdentityTokenInfos\x12\x37.org.dash.platform.dapi.v0.GetIdentityTokenInfosRequest\x1a\x38.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse\x12\x90\x01\n\x17getIdentitiesTokenInfos\x12\x39.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosRequest\x1a:.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse\x12{\n\x10getTokenStatuses\x12\x32.org.dash.platform.dapi.v0.GetTokenStatusesRequest\x1a\x33.org.dash.platform.dapi.v0.GetTokenStatusesResponse\x12\x9f\x01\n\x1cgetTokenDirectPurchasePrices\x12>.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesRequest\x1a?.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse\x12\x87\x01\n\x14getTokenContractInfo\x12\x36.org.dash.platform.dapi.v0.GetTokenContractInfoRequest\x1a\x37.org.dash.platform.dapi.v0.GetTokenContractInfoResponse\x12\xb1\x01\n\"getTokenPreProgrammedDistributions\x12\x44.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsRequest\x1a\x45.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse\x12\xbd\x01\n&getTokenPerpetualDistributionLastClaim\x12H.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimRequest\x1aI.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimResponse\x12\x84\x01\n\x13getTokenTotalSupply\x12\x35.org.dash.platform.dapi.v0.GetTokenTotalSupplyRequest\x1a\x36.org.dash.platform.dapi.v0.GetTokenTotalSupplyResponse\x12o\n\x0cgetGroupInfo\x12..org.dash.platform.dapi.v0.GetGroupInfoRequest\x1a/.org.dash.platform.dapi.v0.GetGroupInfoResponse\x12r\n\rgetGroupInfos\x12/.org.dash.platform.dapi.v0.GetGroupInfosRequest\x1a\x30.org.dash.platform.dapi.v0.GetGroupInfosResponse\x12x\n\x0fgetGroupActions\x12\x31.org.dash.platform.dapi.v0.GetGroupActionsRequest\x1a\x32.org.dash.platform.dapi.v0.GetGroupActionsResponse\x12\x8a\x01\n\x15getGroupActionSigners\x12\x37.org.dash.platform.dapi.v0.GetGroupActionSignersRequest\x1a\x38.org.dash.platform.dapi.v0.GetGroupActionSignersResponse\x12u\n\x0egetAddressInfo\x12\x30.org.dash.platform.dapi.v0.GetAddressInfoRequest\x1a\x31.org.dash.platform.dapi.v0.GetAddressInfoResponse\x12~\n\x11getAddressesInfos\x12\x33.org.dash.platform.dapi.v0.GetAddressesInfosRequest\x1a\x34.org.dash.platform.dapi.v0.GetAddressesInfosResponse\x12\x8d\x01\n\x16getAddressesTrunkState\x12\x38.org.dash.platform.dapi.v0.GetAddressesTrunkStateRequest\x1a\x39.org.dash.platform.dapi.v0.GetAddressesTrunkStateResponse\x12\x90\x01\n\x17getAddressesBranchState\x12\x39.org.dash.platform.dapi.v0.GetAddressesBranchStateRequest\x1a:.org.dash.platform.dapi.v0.GetAddressesBranchStateResponse\x12\xa5\x01\n\x1egetRecentAddressBalanceChanges\x12@.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesRequest\x1a\x41.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesResponse\x12\xc0\x01\n\'getRecentCompactedAddressBalanceChanges\x12I.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesRequest\x1aJ.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponseb\x06proto3' + serialized_pb=b'\n\x0eplatform.proto\x12\x19org.dash.platform.dapi.v0\x1a\x1egoogle/protobuf/wrappers.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x81\x01\n\x05Proof\x12\x15\n\rgrovedb_proof\x18\x01 \x01(\x0c\x12\x13\n\x0bquorum_hash\x18\x02 \x01(\x0c\x12\x11\n\tsignature\x18\x03 \x01(\x0c\x12\r\n\x05round\x18\x04 \x01(\r\x12\x15\n\rblock_id_hash\x18\x05 \x01(\x0c\x12\x13\n\x0bquorum_type\x18\x06 \x01(\r\"\x98\x01\n\x10ResponseMetadata\x12\x12\n\x06height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12 \n\x18\x63ore_chain_locked_height\x18\x02 \x01(\r\x12\r\n\x05\x65poch\x18\x03 \x01(\r\x12\x13\n\x07time_ms\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x18\n\x10protocol_version\x18\x05 \x01(\r\x12\x10\n\x08\x63hain_id\x18\x06 \x01(\t\"L\n\x1dStateTransitionBroadcastError\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\";\n\x1f\x42roadcastStateTransitionRequest\x12\x18\n\x10state_transition\x18\x01 \x01(\x0c\"\"\n BroadcastStateTransitionResponse\"\xa4\x01\n\x12GetIdentityRequest\x12P\n\x02v0\x18\x01 \x01(\x0b\x32\x42.org.dash.platform.dapi.v0.GetIdentityRequest.GetIdentityRequestV0H\x00\x1a\x31\n\x14GetIdentityRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xc1\x01\n\x17GetIdentityNonceRequest\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetIdentityNonceRequest.GetIdentityNonceRequestV0H\x00\x1a?\n\x19GetIdentityNonceRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xf6\x01\n\x1fGetIdentityContractNonceRequest\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetIdentityContractNonceRequest.GetIdentityContractNonceRequestV0H\x00\x1a\\\n!GetIdentityContractNonceRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x13\n\x0b\x63ontract_id\x18\x02 \x01(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xc0\x01\n\x19GetIdentityBalanceRequest\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetIdentityBalanceRequest.GetIdentityBalanceRequestV0H\x00\x1a\x38\n\x1bGetIdentityBalanceRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xec\x01\n$GetIdentityBalanceAndRevisionRequest\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionRequest.GetIdentityBalanceAndRevisionRequestV0H\x00\x1a\x43\n&GetIdentityBalanceAndRevisionRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x9e\x02\n\x13GetIdentityResponse\x12R\n\x02v0\x18\x01 \x01(\x0b\x32\x44.org.dash.platform.dapi.v0.GetIdentityResponse.GetIdentityResponseV0H\x00\x1a\xa7\x01\n\x15GetIdentityResponseV0\x12\x12\n\x08identity\x18\x01 \x01(\x0cH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xbc\x02\n\x18GetIdentityNonceResponse\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetIdentityNonceResponse.GetIdentityNonceResponseV0H\x00\x1a\xb6\x01\n\x1aGetIdentityNonceResponseV0\x12\x1c\n\x0eidentity_nonce\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xe5\x02\n GetIdentityContractNonceResponse\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetIdentityContractNonceResponse.GetIdentityContractNonceResponseV0H\x00\x1a\xc7\x01\n\"GetIdentityContractNonceResponseV0\x12%\n\x17identity_contract_nonce\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xbd\x02\n\x1aGetIdentityBalanceResponse\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetIdentityBalanceResponse.GetIdentityBalanceResponseV0H\x00\x1a\xb1\x01\n\x1cGetIdentityBalanceResponseV0\x12\x15\n\x07\x62\x61lance\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xb1\x04\n%GetIdentityBalanceAndRevisionResponse\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionResponse.GetIdentityBalanceAndRevisionResponseV0H\x00\x1a\x84\x03\n\'GetIdentityBalanceAndRevisionResponseV0\x12\x9b\x01\n\x14\x62\x61lance_and_revision\x18\x01 \x01(\x0b\x32{.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionResponse.GetIdentityBalanceAndRevisionResponseV0.BalanceAndRevisionH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a?\n\x12\x42\x61lanceAndRevision\x12\x13\n\x07\x62\x61lance\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x14\n\x08revision\x18\x02 \x01(\x04\x42\x02\x30\x01\x42\x08\n\x06resultB\t\n\x07version\"\xd1\x01\n\x0eKeyRequestType\x12\x36\n\x08\x61ll_keys\x18\x01 \x01(\x0b\x32\".org.dash.platform.dapi.v0.AllKeysH\x00\x12@\n\rspecific_keys\x18\x02 \x01(\x0b\x32\'.org.dash.platform.dapi.v0.SpecificKeysH\x00\x12:\n\nsearch_key\x18\x03 \x01(\x0b\x32$.org.dash.platform.dapi.v0.SearchKeyH\x00\x42\t\n\x07request\"\t\n\x07\x41llKeys\"\x1f\n\x0cSpecificKeys\x12\x0f\n\x07key_ids\x18\x01 \x03(\r\"\xb6\x01\n\tSearchKey\x12I\n\x0bpurpose_map\x18\x01 \x03(\x0b\x32\x34.org.dash.platform.dapi.v0.SearchKey.PurposeMapEntry\x1a^\n\x0fPurposeMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12:\n\x05value\x18\x02 \x01(\x0b\x32+.org.dash.platform.dapi.v0.SecurityLevelMap:\x02\x38\x01\"\xbf\x02\n\x10SecurityLevelMap\x12]\n\x12security_level_map\x18\x01 \x03(\x0b\x32\x41.org.dash.platform.dapi.v0.SecurityLevelMap.SecurityLevelMapEntry\x1aw\n\x15SecurityLevelMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12M\n\x05value\x18\x02 \x01(\x0e\x32>.org.dash.platform.dapi.v0.SecurityLevelMap.KeyKindRequestType:\x02\x38\x01\"S\n\x12KeyKindRequestType\x12\x1f\n\x1b\x43URRENT_KEY_OF_KIND_REQUEST\x10\x00\x12\x1c\n\x18\x41LL_KEYS_OF_KIND_REQUEST\x10\x01\"\xda\x02\n\x16GetIdentityKeysRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetIdentityKeysRequest.GetIdentityKeysRequestV0H\x00\x1a\xda\x01\n\x18GetIdentityKeysRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12?\n\x0crequest_type\x18\x02 \x01(\x0b\x32).org.dash.platform.dapi.v0.KeyRequestType\x12+\n\x05limit\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12,\n\x06offset\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\t\n\x07version\"\x99\x03\n\x17GetIdentityKeysResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetIdentityKeysResponse.GetIdentityKeysResponseV0H\x00\x1a\x96\x02\n\x19GetIdentityKeysResponseV0\x12\x61\n\x04keys\x18\x01 \x01(\x0b\x32Q.org.dash.platform.dapi.v0.GetIdentityKeysResponse.GetIdentityKeysResponseV0.KeysH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1a\n\x04Keys\x12\x12\n\nkeys_bytes\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xef\x02\n GetIdentitiesContractKeysRequest\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetIdentitiesContractKeysRequest.GetIdentitiesContractKeysRequestV0H\x00\x1a\xd1\x01\n\"GetIdentitiesContractKeysRequestV0\x12\x16\n\x0eidentities_ids\x18\x01 \x03(\x0c\x12\x13\n\x0b\x63ontract_id\x18\x02 \x01(\x0c\x12\x1f\n\x12\x64ocument_type_name\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x37\n\x08purposes\x18\x04 \x03(\x0e\x32%.org.dash.platform.dapi.v0.KeyPurpose\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\x15\n\x13_document_type_nameB\t\n\x07version\"\xdf\x06\n!GetIdentitiesContractKeysResponse\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0H\x00\x1a\xbe\x05\n#GetIdentitiesContractKeysResponseV0\x12\x8a\x01\n\x0fidentities_keys\x18\x01 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0.IdentitiesKeysH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aY\n\x0bPurposeKeys\x12\x36\n\x07purpose\x18\x01 \x01(\x0e\x32%.org.dash.platform.dapi.v0.KeyPurpose\x12\x12\n\nkeys_bytes\x18\x02 \x03(\x0c\x1a\x9f\x01\n\x0cIdentityKeys\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12z\n\x04keys\x18\x02 \x03(\x0b\x32l.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0.PurposeKeys\x1a\x90\x01\n\x0eIdentitiesKeys\x12~\n\x07\x65ntries\x18\x01 \x03(\x0b\x32m.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0.IdentityKeysB\x08\n\x06resultB\t\n\x07version\"\xa4\x02\n*GetEvonodesProposedEpochBlocksByIdsRequest\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByIdsRequest.GetEvonodesProposedEpochBlocksByIdsRequestV0H\x00\x1ah\n,GetEvonodesProposedEpochBlocksByIdsRequestV0\x12\x12\n\x05\x65poch\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x0b\n\x03ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\x08\n\x06_epochB\t\n\x07version\"\x92\x06\n&GetEvonodesProposedEpochBlocksResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse.GetEvonodesProposedEpochBlocksResponseV0H\x00\x1a\xe2\x04\n(GetEvonodesProposedEpochBlocksResponseV0\x12\xb1\x01\n#evonodes_proposed_block_counts_info\x18\x01 \x01(\x0b\x32\x81\x01.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse.GetEvonodesProposedEpochBlocksResponseV0.EvonodesProposedBlocksH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a?\n\x15\x45vonodeProposedBlocks\x12\x13\n\x0bpro_tx_hash\x18\x01 \x01(\x0c\x12\x11\n\x05\x63ount\x18\x02 \x01(\x04\x42\x02\x30\x01\x1a\xc4\x01\n\x16\x45vonodesProposedBlocks\x12\xa9\x01\n\x1e\x65vonodes_proposed_block_counts\x18\x01 \x03(\x0b\x32\x80\x01.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse.GetEvonodesProposedEpochBlocksResponseV0.EvonodeProposedBlocksB\x08\n\x06resultB\t\n\x07version\"\xf2\x02\n,GetEvonodesProposedEpochBlocksByRangeRequest\x12\x84\x01\n\x02v0\x18\x01 \x01(\x0b\x32v.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByRangeRequest.GetEvonodesProposedEpochBlocksByRangeRequestV0H\x00\x1a\xaf\x01\n.GetEvonodesProposedEpochBlocksByRangeRequestV0\x12\x12\n\x05\x65poch\x18\x01 \x01(\rH\x01\x88\x01\x01\x12\x12\n\x05limit\x18\x02 \x01(\rH\x02\x88\x01\x01\x12\x15\n\x0bstart_after\x18\x03 \x01(\x0cH\x00\x12\x12\n\x08start_at\x18\x04 \x01(\x0cH\x00\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\x07\n\x05startB\x08\n\x06_epochB\x08\n\x06_limitB\t\n\x07version\"\xcd\x01\n\x1cGetIdentitiesBalancesRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetIdentitiesBalancesRequest.GetIdentitiesBalancesRequestV0H\x00\x1a<\n\x1eGetIdentitiesBalancesRequestV0\x12\x0b\n\x03ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x9f\x05\n\x1dGetIdentitiesBalancesResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse.GetIdentitiesBalancesResponseV0H\x00\x1a\x8a\x04\n\x1fGetIdentitiesBalancesResponseV0\x12\x8a\x01\n\x13identities_balances\x18\x01 \x01(\x0b\x32k.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse.GetIdentitiesBalancesResponseV0.IdentitiesBalancesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aL\n\x0fIdentityBalance\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x18\n\x07\x62\x61lance\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x88\x01\x01\x42\n\n\x08_balance\x1a\x8f\x01\n\x12IdentitiesBalances\x12y\n\x07\x65ntries\x18\x01 \x03(\x0b\x32h.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse.GetIdentitiesBalancesResponseV0.IdentityBalanceB\x08\n\x06resultB\t\n\x07version\"\xb4\x01\n\x16GetDataContractRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetDataContractRequest.GetDataContractRequestV0H\x00\x1a\x35\n\x18GetDataContractRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xb3\x02\n\x17GetDataContractResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetDataContractResponse.GetDataContractResponseV0H\x00\x1a\xb0\x01\n\x19GetDataContractResponseV0\x12\x17\n\rdata_contract\x18\x01 \x01(\x0cH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xb9\x01\n\x17GetDataContractsRequest\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetDataContractsRequest.GetDataContractsRequestV0H\x00\x1a\x37\n\x19GetDataContractsRequestV0\x12\x0b\n\x03ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xcf\x04\n\x18GetDataContractsResponse\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetDataContractsResponse.GetDataContractsResponseV0H\x00\x1a[\n\x11\x44\x61taContractEntry\x12\x12\n\nidentifier\x18\x01 \x01(\x0c\x12\x32\n\rdata_contract\x18\x02 \x01(\x0b\x32\x1b.google.protobuf.BytesValue\x1au\n\rDataContracts\x12\x64\n\x15\x64\x61ta_contract_entries\x18\x01 \x03(\x0b\x32\x45.org.dash.platform.dapi.v0.GetDataContractsResponse.DataContractEntry\x1a\xf5\x01\n\x1aGetDataContractsResponseV0\x12[\n\x0e\x64\x61ta_contracts\x18\x01 \x01(\x0b\x32\x41.org.dash.platform.dapi.v0.GetDataContractsResponse.DataContractsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc5\x02\n\x1dGetDataContractHistoryRequest\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetDataContractHistoryRequest.GetDataContractHistoryRequestV0H\x00\x1a\xb0\x01\n\x1fGetDataContractHistoryRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12+\n\x05limit\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12,\n\x06offset\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\x17\n\x0bstart_at_ms\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\t\n\x07version\"\xb2\x05\n\x1eGetDataContractHistoryResponse\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetDataContractHistoryResponse.GetDataContractHistoryResponseV0H\x00\x1a\x9a\x04\n GetDataContractHistoryResponseV0\x12\x8f\x01\n\x15\x64\x61ta_contract_history\x18\x01 \x01(\x0b\x32n.org.dash.platform.dapi.v0.GetDataContractHistoryResponse.GetDataContractHistoryResponseV0.DataContractHistoryH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a;\n\x18\x44\x61taContractHistoryEntry\x12\x10\n\x04\x64\x61te\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05value\x18\x02 \x01(\x0c\x1a\xaa\x01\n\x13\x44\x61taContractHistory\x12\x92\x01\n\x15\x64\x61ta_contract_entries\x18\x01 \x03(\x0b\x32s.org.dash.platform.dapi.v0.GetDataContractHistoryResponse.GetDataContractHistoryResponseV0.DataContractHistoryEntryB\x08\n\x06resultB\t\n\x07version\"\xb2\x02\n\x13GetDocumentsRequest\x12R\n\x02v0\x18\x01 \x01(\x0b\x32\x44.org.dash.platform.dapi.v0.GetDocumentsRequest.GetDocumentsRequestV0H\x00\x1a\xbb\x01\n\x15GetDocumentsRequestV0\x12\x18\n\x10\x64\x61ta_contract_id\x18\x01 \x01(\x0c\x12\x15\n\rdocument_type\x18\x02 \x01(\t\x12\r\n\x05where\x18\x03 \x01(\x0c\x12\x10\n\x08order_by\x18\x04 \x01(\x0c\x12\r\n\x05limit\x18\x05 \x01(\r\x12\x15\n\x0bstart_after\x18\x06 \x01(\x0cH\x00\x12\x12\n\x08start_at\x18\x07 \x01(\x0cH\x00\x12\r\n\x05prove\x18\x08 \x01(\x08\x42\x07\n\x05startB\t\n\x07version\"\x95\x03\n\x14GetDocumentsResponse\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetDocumentsResponse.GetDocumentsResponseV0H\x00\x1a\x9b\x02\n\x16GetDocumentsResponseV0\x12\x65\n\tdocuments\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetDocumentsResponse.GetDocumentsResponseV0.DocumentsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1e\n\tDocuments\x12\x11\n\tdocuments\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xed\x01\n!GetIdentityByPublicKeyHashRequest\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashRequest.GetIdentityByPublicKeyHashRequestV0H\x00\x1aM\n#GetIdentityByPublicKeyHashRequestV0\x12\x17\n\x0fpublic_key_hash\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xda\x02\n\"GetIdentityByPublicKeyHashResponse\x12p\n\x02v0\x18\x01 \x01(\x0b\x32\x62.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashResponse.GetIdentityByPublicKeyHashResponseV0H\x00\x1a\xb6\x01\n$GetIdentityByPublicKeyHashResponseV0\x12\x12\n\x08identity\x18\x01 \x01(\x0cH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xbd\x02\n*GetIdentityByNonUniquePublicKeyHashRequest\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashRequest.GetIdentityByNonUniquePublicKeyHashRequestV0H\x00\x1a\x80\x01\n,GetIdentityByNonUniquePublicKeyHashRequestV0\x12\x17\n\x0fpublic_key_hash\x18\x01 \x01(\x0c\x12\x18\n\x0bstart_after\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\x0e\n\x0c_start_afterB\t\n\x07version\"\xd6\x06\n+GetIdentityByNonUniquePublicKeyHashResponse\x12\x82\x01\n\x02v0\x18\x01 \x01(\x0b\x32t.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse.GetIdentityByNonUniquePublicKeyHashResponseV0H\x00\x1a\x96\x05\n-GetIdentityByNonUniquePublicKeyHashResponseV0\x12\x9a\x01\n\x08identity\x18\x01 \x01(\x0b\x32\x85\x01.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse.GetIdentityByNonUniquePublicKeyHashResponseV0.IdentityResponseH\x00\x12\x9d\x01\n\x05proof\x18\x02 \x01(\x0b\x32\x8b\x01.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse.GetIdentityByNonUniquePublicKeyHashResponseV0.IdentityProvedResponseH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x36\n\x10IdentityResponse\x12\x15\n\x08identity\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\x0b\n\t_identity\x1a\xa6\x01\n\x16IdentityProvedResponse\x12P\n&grovedb_identity_public_key_hash_proof\x18\x01 \x01(\x0b\x32 .org.dash.platform.dapi.v0.Proof\x12!\n\x14identity_proof_bytes\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x42\x17\n\x15_identity_proof_bytesB\x08\n\x06resultB\t\n\x07version\"\xfb\x01\n#WaitForStateTransitionResultRequest\x12r\n\x02v0\x18\x01 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.WaitForStateTransitionResultRequest.WaitForStateTransitionResultRequestV0H\x00\x1aU\n%WaitForStateTransitionResultRequestV0\x12\x1d\n\x15state_transition_hash\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x99\x03\n$WaitForStateTransitionResultResponse\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.WaitForStateTransitionResultResponse.WaitForStateTransitionResultResponseV0H\x00\x1a\xef\x01\n&WaitForStateTransitionResultResponseV0\x12I\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x38.org.dash.platform.dapi.v0.StateTransitionBroadcastErrorH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc4\x01\n\x19GetConsensusParamsRequest\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetConsensusParamsRequest.GetConsensusParamsRequestV0H\x00\x1a<\n\x1bGetConsensusParamsRequestV0\x12\x0e\n\x06height\x18\x01 \x01(\x05\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x9c\x04\n\x1aGetConsensusParamsResponse\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetConsensusParamsResponse.GetConsensusParamsResponseV0H\x00\x1aP\n\x14\x43onsensusParamsBlock\x12\x11\n\tmax_bytes\x18\x01 \x01(\t\x12\x0f\n\x07max_gas\x18\x02 \x01(\t\x12\x14\n\x0ctime_iota_ms\x18\x03 \x01(\t\x1a\x62\n\x17\x43onsensusParamsEvidence\x12\x1a\n\x12max_age_num_blocks\x18\x01 \x01(\t\x12\x18\n\x10max_age_duration\x18\x02 \x01(\t\x12\x11\n\tmax_bytes\x18\x03 \x01(\t\x1a\xda\x01\n\x1cGetConsensusParamsResponseV0\x12Y\n\x05\x62lock\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetConsensusParamsResponse.ConsensusParamsBlock\x12_\n\x08\x65vidence\x18\x02 \x01(\x0b\x32M.org.dash.platform.dapi.v0.GetConsensusParamsResponse.ConsensusParamsEvidenceB\t\n\x07version\"\xe4\x01\n%GetProtocolVersionUpgradeStateRequest\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateRequest.GetProtocolVersionUpgradeStateRequestV0H\x00\x1a\x38\n\'GetProtocolVersionUpgradeStateRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xb5\x05\n&GetProtocolVersionUpgradeStateResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse.GetProtocolVersionUpgradeStateResponseV0H\x00\x1a\x85\x04\n(GetProtocolVersionUpgradeStateResponseV0\x12\x87\x01\n\x08versions\x18\x01 \x01(\x0b\x32s.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse.GetProtocolVersionUpgradeStateResponseV0.VersionsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x96\x01\n\x08Versions\x12\x89\x01\n\x08versions\x18\x01 \x03(\x0b\x32w.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse.GetProtocolVersionUpgradeStateResponseV0.VersionEntry\x1a:\n\x0cVersionEntry\x12\x16\n\x0eversion_number\x18\x01 \x01(\r\x12\x12\n\nvote_count\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xa3\x02\n*GetProtocolVersionUpgradeVoteStatusRequest\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusRequest.GetProtocolVersionUpgradeVoteStatusRequestV0H\x00\x1ag\n,GetProtocolVersionUpgradeVoteStatusRequestV0\x12\x19\n\x11start_pro_tx_hash\x18\x01 \x01(\x0c\x12\r\n\x05\x63ount\x18\x02 \x01(\r\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xef\x05\n+GetProtocolVersionUpgradeVoteStatusResponse\x12\x82\x01\n\x02v0\x18\x01 \x01(\x0b\x32t.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse.GetProtocolVersionUpgradeVoteStatusResponseV0H\x00\x1a\xaf\x04\n-GetProtocolVersionUpgradeVoteStatusResponseV0\x12\x98\x01\n\x08versions\x18\x01 \x01(\x0b\x32\x83\x01.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse.GetProtocolVersionUpgradeVoteStatusResponseV0.VersionSignalsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xaf\x01\n\x0eVersionSignals\x12\x9c\x01\n\x0fversion_signals\x18\x01 \x03(\x0b\x32\x82\x01.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse.GetProtocolVersionUpgradeVoteStatusResponseV0.VersionSignal\x1a\x35\n\rVersionSignal\x12\x13\n\x0bpro_tx_hash\x18\x01 \x01(\x0c\x12\x0f\n\x07version\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xf5\x01\n\x14GetEpochsInfoRequest\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetEpochsInfoRequest.GetEpochsInfoRequestV0H\x00\x1a|\n\x16GetEpochsInfoRequestV0\x12\x31\n\x0bstart_epoch\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\r\n\x05\x63ount\x18\x02 \x01(\r\x12\x11\n\tascending\x18\x03 \x01(\x08\x12\r\n\x05prove\x18\x04 \x01(\x08\x42\t\n\x07version\"\x99\x05\n\x15GetEpochsInfoResponse\x12V\n\x02v0\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetEpochsInfoResponse.GetEpochsInfoResponseV0H\x00\x1a\x9c\x04\n\x17GetEpochsInfoResponseV0\x12\x65\n\x06\x65pochs\x18\x01 \x01(\x0b\x32S.org.dash.platform.dapi.v0.GetEpochsInfoResponse.GetEpochsInfoResponseV0.EpochInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1au\n\nEpochInfos\x12g\n\x0b\x65poch_infos\x18\x01 \x03(\x0b\x32R.org.dash.platform.dapi.v0.GetEpochsInfoResponse.GetEpochsInfoResponseV0.EpochInfo\x1a\xa6\x01\n\tEpochInfo\x12\x0e\n\x06number\x18\x01 \x01(\r\x12\x1e\n\x12\x66irst_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x1f\n\x17\x66irst_core_block_height\x18\x03 \x01(\r\x12\x16\n\nstart_time\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x16\n\x0e\x66\x65\x65_multiplier\x18\x05 \x01(\x01\x12\x18\n\x10protocol_version\x18\x06 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xbf\x02\n\x1dGetFinalizedEpochInfosRequest\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetFinalizedEpochInfosRequest.GetFinalizedEpochInfosRequestV0H\x00\x1a\xaa\x01\n\x1fGetFinalizedEpochInfosRequestV0\x12\x19\n\x11start_epoch_index\x18\x01 \x01(\r\x12\"\n\x1astart_epoch_index_included\x18\x02 \x01(\x08\x12\x17\n\x0f\x65nd_epoch_index\x18\x03 \x01(\r\x12 \n\x18\x65nd_epoch_index_included\x18\x04 \x01(\x08\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\t\n\x07version\"\xbd\t\n\x1eGetFinalizedEpochInfosResponse\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0H\x00\x1a\xa5\x08\n GetFinalizedEpochInfosResponseV0\x12\x80\x01\n\x06\x65pochs\x18\x01 \x01(\x0b\x32n.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0.FinalizedEpochInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xa4\x01\n\x13\x46inalizedEpochInfos\x12\x8c\x01\n\x15\x66inalized_epoch_infos\x18\x01 \x03(\x0b\x32m.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0.FinalizedEpochInfo\x1a\x9f\x04\n\x12\x46inalizedEpochInfo\x12\x0e\n\x06number\x18\x01 \x01(\r\x12\x1e\n\x12\x66irst_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x1f\n\x17\x66irst_core_block_height\x18\x03 \x01(\r\x12\x1c\n\x10\x66irst_block_time\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x16\n\x0e\x66\x65\x65_multiplier\x18\x05 \x01(\x01\x12\x18\n\x10protocol_version\x18\x06 \x01(\r\x12!\n\x15total_blocks_in_epoch\x18\x07 \x01(\x04\x42\x02\x30\x01\x12*\n\"next_epoch_start_core_block_height\x18\x08 \x01(\r\x12!\n\x15total_processing_fees\x18\t \x01(\x04\x42\x02\x30\x01\x12*\n\x1etotal_distributed_storage_fees\x18\n \x01(\x04\x42\x02\x30\x01\x12&\n\x1atotal_created_storage_fees\x18\x0b \x01(\x04\x42\x02\x30\x01\x12\x1e\n\x12\x63ore_block_rewards\x18\x0c \x01(\x04\x42\x02\x30\x01\x12\x81\x01\n\x0f\x62lock_proposers\x18\r \x03(\x0b\x32h.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0.BlockProposer\x1a\x39\n\rBlockProposer\x12\x13\n\x0bproposer_id\x18\x01 \x01(\x0c\x12\x13\n\x0b\x62lock_count\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xde\x04\n\x1cGetContestedResourcesRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetContestedResourcesRequest.GetContestedResourcesRequestV0H\x00\x1a\xcc\x03\n\x1eGetContestedResourcesRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\x12\n\nindex_name\x18\x03 \x01(\t\x12\x1a\n\x12start_index_values\x18\x04 \x03(\x0c\x12\x18\n\x10\x65nd_index_values\x18\x05 \x03(\x0c\x12\x89\x01\n\x13start_at_value_info\x18\x06 \x01(\x0b\x32g.org.dash.platform.dapi.v0.GetContestedResourcesRequest.GetContestedResourcesRequestV0.StartAtValueInfoH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x07 \x01(\rH\x01\x88\x01\x01\x12\x17\n\x0forder_ascending\x18\x08 \x01(\x08\x12\r\n\x05prove\x18\t \x01(\x08\x1a\x45\n\x10StartAtValueInfo\x12\x13\n\x0bstart_value\x18\x01 \x01(\x0c\x12\x1c\n\x14start_value_included\x18\x02 \x01(\x08\x42\x16\n\x14_start_at_value_infoB\x08\n\x06_countB\t\n\x07version\"\x88\x04\n\x1dGetContestedResourcesResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetContestedResourcesResponse.GetContestedResourcesResponseV0H\x00\x1a\xf3\x02\n\x1fGetContestedResourcesResponseV0\x12\x95\x01\n\x19\x63ontested_resource_values\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetContestedResourcesResponse.GetContestedResourcesResponseV0.ContestedResourceValuesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a<\n\x17\x43ontestedResourceValues\x12!\n\x19\x63ontested_resource_values\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xd2\x05\n\x1cGetVotePollsByEndDateRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest.GetVotePollsByEndDateRequestV0H\x00\x1a\xc0\x04\n\x1eGetVotePollsByEndDateRequestV0\x12\x84\x01\n\x0fstart_time_info\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest.GetVotePollsByEndDateRequestV0.StartAtTimeInfoH\x00\x88\x01\x01\x12\x80\x01\n\rend_time_info\x18\x02 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest.GetVotePollsByEndDateRequestV0.EndAtTimeInfoH\x01\x88\x01\x01\x12\x12\n\x05limit\x18\x03 \x01(\rH\x02\x88\x01\x01\x12\x13\n\x06offset\x18\x04 \x01(\rH\x03\x88\x01\x01\x12\x11\n\tascending\x18\x05 \x01(\x08\x12\r\n\x05prove\x18\x06 \x01(\x08\x1aI\n\x0fStartAtTimeInfo\x12\x19\n\rstart_time_ms\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1b\n\x13start_time_included\x18\x02 \x01(\x08\x1a\x43\n\rEndAtTimeInfo\x12\x17\n\x0b\x65nd_time_ms\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x19\n\x11\x65nd_time_included\x18\x02 \x01(\x08\x42\x12\n\x10_start_time_infoB\x10\n\x0e_end_time_infoB\x08\n\x06_limitB\t\n\x07_offsetB\t\n\x07version\"\x83\x06\n\x1dGetVotePollsByEndDateResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse.GetVotePollsByEndDateResponseV0H\x00\x1a\xee\x04\n\x1fGetVotePollsByEndDateResponseV0\x12\x9c\x01\n\x18vote_polls_by_timestamps\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse.GetVotePollsByEndDateResponseV0.SerializedVotePollsByTimestampsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aV\n\x1eSerializedVotePollsByTimestamp\x12\x15\n\ttimestamp\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1d\n\x15serialized_vote_polls\x18\x02 \x03(\x0c\x1a\xd7\x01\n\x1fSerializedVotePollsByTimestamps\x12\x99\x01\n\x18vote_polls_by_timestamps\x18\x01 \x03(\x0b\x32w.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse.GetVotePollsByEndDateResponseV0.SerializedVotePollsByTimestamp\x12\x18\n\x10\x66inished_results\x18\x02 \x01(\x08\x42\x08\n\x06resultB\t\n\x07version\"\xff\x06\n$GetContestedResourceVoteStateRequest\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest.GetContestedResourceVoteStateRequestV0H\x00\x1a\xd5\x05\n&GetContestedResourceVoteStateRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\x12\n\nindex_name\x18\x03 \x01(\t\x12\x14\n\x0cindex_values\x18\x04 \x03(\x0c\x12\x86\x01\n\x0bresult_type\x18\x05 \x01(\x0e\x32q.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest.GetContestedResourceVoteStateRequestV0.ResultType\x12\x36\n.allow_include_locked_and_abstaining_vote_tally\x18\x06 \x01(\x08\x12\xa3\x01\n\x18start_at_identifier_info\x18\x07 \x01(\x0b\x32|.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest.GetContestedResourceVoteStateRequestV0.StartAtIdentifierInfoH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x08 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\t \x01(\x08\x1aT\n\x15StartAtIdentifierInfo\x12\x18\n\x10start_identifier\x18\x01 \x01(\x0c\x12!\n\x19start_identifier_included\x18\x02 \x01(\x08\"I\n\nResultType\x12\r\n\tDOCUMENTS\x10\x00\x12\x0e\n\nVOTE_TALLY\x10\x01\x12\x1c\n\x18\x44OCUMENTS_AND_VOTE_TALLY\x10\x02\x42\x1b\n\x19_start_at_identifier_infoB\x08\n\x06_countB\t\n\x07version\"\x94\x0c\n%GetContestedResourceVoteStateResponse\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0H\x00\x1a\xe7\n\n\'GetContestedResourceVoteStateResponseV0\x12\xae\x01\n\x1d\x63ontested_resource_contenders\x18\x01 \x01(\x0b\x32\x84\x01.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.ContestedResourceContendersH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xda\x03\n\x10\x46inishedVoteInfo\x12\xad\x01\n\x15\x66inished_vote_outcome\x18\x01 \x01(\x0e\x32\x8d\x01.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.FinishedVoteInfo.FinishedVoteOutcome\x12\x1f\n\x12won_by_identity_id\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12$\n\x18\x66inished_at_block_height\x18\x03 \x01(\x04\x42\x02\x30\x01\x12%\n\x1d\x66inished_at_core_block_height\x18\x04 \x01(\r\x12%\n\x19\x66inished_at_block_time_ms\x18\x05 \x01(\x04\x42\x02\x30\x01\x12\x19\n\x11\x66inished_at_epoch\x18\x06 \x01(\r\"O\n\x13\x46inishedVoteOutcome\x12\x14\n\x10TOWARDS_IDENTITY\x10\x00\x12\n\n\x06LOCKED\x10\x01\x12\x16\n\x12NO_PREVIOUS_WINNER\x10\x02\x42\x15\n\x13_won_by_identity_id\x1a\xc4\x03\n\x1b\x43ontestedResourceContenders\x12\x86\x01\n\ncontenders\x18\x01 \x03(\x0b\x32r.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.Contender\x12\x1f\n\x12\x61\x62stain_vote_tally\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x1c\n\x0flock_vote_tally\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x9a\x01\n\x12\x66inished_vote_info\x18\x04 \x01(\x0b\x32y.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.FinishedVoteInfoH\x02\x88\x01\x01\x42\x15\n\x13_abstain_vote_tallyB\x12\n\x10_lock_vote_tallyB\x15\n\x13_finished_vote_info\x1ak\n\tContender\x12\x12\n\nidentifier\x18\x01 \x01(\x0c\x12\x17\n\nvote_count\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x15\n\x08\x64ocument\x18\x03 \x01(\x0cH\x01\x88\x01\x01\x42\r\n\x0b_vote_countB\x0b\n\t_documentB\x08\n\x06resultB\t\n\x07version\"\xd5\x05\n,GetContestedResourceVotersForIdentityRequest\x12\x84\x01\n\x02v0\x18\x01 \x01(\x0b\x32v.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityRequest.GetContestedResourceVotersForIdentityRequestV0H\x00\x1a\x92\x04\n.GetContestedResourceVotersForIdentityRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\x12\n\nindex_name\x18\x03 \x01(\t\x12\x14\n\x0cindex_values\x18\x04 \x03(\x0c\x12\x15\n\rcontestant_id\x18\x05 \x01(\x0c\x12\xb4\x01\n\x18start_at_identifier_info\x18\x06 \x01(\x0b\x32\x8c\x01.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityRequest.GetContestedResourceVotersForIdentityRequestV0.StartAtIdentifierInfoH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x07 \x01(\rH\x01\x88\x01\x01\x12\x17\n\x0forder_ascending\x18\x08 \x01(\x08\x12\r\n\x05prove\x18\t \x01(\x08\x1aT\n\x15StartAtIdentifierInfo\x12\x18\n\x10start_identifier\x18\x01 \x01(\x0c\x12!\n\x19start_identifier_included\x18\x02 \x01(\x08\x42\x1b\n\x19_start_at_identifier_infoB\x08\n\x06_countB\t\n\x07version\"\xf1\x04\n-GetContestedResourceVotersForIdentityResponse\x12\x86\x01\n\x02v0\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityResponse.GetContestedResourceVotersForIdentityResponseV0H\x00\x1a\xab\x03\n/GetContestedResourceVotersForIdentityResponseV0\x12\xb6\x01\n\x19\x63ontested_resource_voters\x18\x01 \x01(\x0b\x32\x90\x01.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityResponse.GetContestedResourceVotersForIdentityResponseV0.ContestedResourceVotersH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x43\n\x17\x43ontestedResourceVoters\x12\x0e\n\x06voters\x18\x01 \x03(\x0c\x12\x18\n\x10\x66inished_results\x18\x02 \x01(\x08\x42\x08\n\x06resultB\t\n\x07version\"\xad\x05\n(GetContestedResourceIdentityVotesRequest\x12|\n\x02v0\x18\x01 \x01(\x0b\x32n.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesRequest.GetContestedResourceIdentityVotesRequestV0H\x00\x1a\xf7\x03\n*GetContestedResourceIdentityVotesRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12+\n\x05limit\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12,\n\x06offset\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\x17\n\x0forder_ascending\x18\x04 \x01(\x08\x12\xae\x01\n\x1astart_at_vote_poll_id_info\x18\x05 \x01(\x0b\x32\x84\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesRequest.GetContestedResourceIdentityVotesRequestV0.StartAtVotePollIdInfoH\x00\x88\x01\x01\x12\r\n\x05prove\x18\x06 \x01(\x08\x1a\x61\n\x15StartAtVotePollIdInfo\x12 \n\x18start_at_poll_identifier\x18\x01 \x01(\x0c\x12&\n\x1estart_poll_identifier_included\x18\x02 \x01(\x08\x42\x1d\n\x1b_start_at_vote_poll_id_infoB\t\n\x07version\"\xc8\n\n)GetContestedResourceIdentityVotesResponse\x12~\n\x02v0\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0H\x00\x1a\x8f\t\n+GetContestedResourceIdentityVotesResponseV0\x12\xa1\x01\n\x05votes\x18\x01 \x01(\x0b\x32\x8f\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ContestedResourceIdentityVotesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xf7\x01\n\x1e\x43ontestedResourceIdentityVotes\x12\xba\x01\n!contested_resource_identity_votes\x18\x01 \x03(\x0b\x32\x8e\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ContestedResourceIdentityVote\x12\x18\n\x10\x66inished_results\x18\x02 \x01(\x08\x1a\xad\x02\n\x12ResourceVoteChoice\x12\xad\x01\n\x10vote_choice_type\x18\x01 \x01(\x0e\x32\x92\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ResourceVoteChoice.VoteChoiceType\x12\x18\n\x0bidentity_id\x18\x02 \x01(\x0cH\x00\x88\x01\x01\"=\n\x0eVoteChoiceType\x12\x14\n\x10TOWARDS_IDENTITY\x10\x00\x12\x0b\n\x07\x41\x42STAIN\x10\x01\x12\x08\n\x04LOCK\x10\x02\x42\x0e\n\x0c_identity_id\x1a\x95\x02\n\x1d\x43ontestedResourceIdentityVote\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\'\n\x1fserialized_index_storage_values\x18\x03 \x03(\x0c\x12\x99\x01\n\x0bvote_choice\x18\x04 \x01(\x0b\x32\x83\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ResourceVoteChoiceB\x08\n\x06resultB\t\n\x07version\"\xf0\x01\n%GetPrefundedSpecializedBalanceRequest\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceRequest.GetPrefundedSpecializedBalanceRequestV0H\x00\x1a\x44\n\'GetPrefundedSpecializedBalanceRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xed\x02\n&GetPrefundedSpecializedBalanceResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceResponse.GetPrefundedSpecializedBalanceResponseV0H\x00\x1a\xbd\x01\n(GetPrefundedSpecializedBalanceResponseV0\x12\x15\n\x07\x62\x61lance\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xd0\x01\n GetTotalCreditsInPlatformRequest\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformRequest.GetTotalCreditsInPlatformRequestV0H\x00\x1a\x33\n\"GetTotalCreditsInPlatformRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xd9\x02\n!GetTotalCreditsInPlatformResponse\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformResponse.GetTotalCreditsInPlatformResponseV0H\x00\x1a\xb8\x01\n#GetTotalCreditsInPlatformResponseV0\x12\x15\n\x07\x63redits\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc4\x01\n\x16GetPathElementsRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetPathElementsRequest.GetPathElementsRequestV0H\x00\x1a\x45\n\x18GetPathElementsRequestV0\x12\x0c\n\x04path\x18\x01 \x03(\x0c\x12\x0c\n\x04keys\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xa3\x03\n\x17GetPathElementsResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetPathElementsResponse.GetPathElementsResponseV0H\x00\x1a\xa0\x02\n\x19GetPathElementsResponseV0\x12i\n\x08\x65lements\x18\x01 \x01(\x0b\x32U.org.dash.platform.dapi.v0.GetPathElementsResponse.GetPathElementsResponseV0.ElementsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1c\n\x08\x45lements\x12\x10\n\x08\x65lements\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\x81\x01\n\x10GetStatusRequest\x12L\n\x02v0\x18\x01 \x01(\x0b\x32>.org.dash.platform.dapi.v0.GetStatusRequest.GetStatusRequestV0H\x00\x1a\x14\n\x12GetStatusRequestV0B\t\n\x07version\"\xe4\x10\n\x11GetStatusResponse\x12N\n\x02v0\x18\x01 \x01(\x0b\x32@.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0H\x00\x1a\xf3\x0f\n\x13GetStatusResponseV0\x12Y\n\x07version\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version\x12S\n\x04node\x18\x02 \x01(\x0b\x32\x45.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Node\x12U\n\x05\x63hain\x18\x03 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Chain\x12Y\n\x07network\x18\x04 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Network\x12^\n\nstate_sync\x18\x05 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.StateSync\x12S\n\x04time\x18\x06 \x01(\x0b\x32\x45.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Time\x1a\x82\x05\n\x07Version\x12\x63\n\x08software\x18\x01 \x01(\x0b\x32Q.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Software\x12\x63\n\x08protocol\x18\x02 \x01(\x0b\x32Q.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Protocol\x1a^\n\x08Software\x12\x0c\n\x04\x64\x61pi\x18\x01 \x01(\t\x12\x12\n\x05\x64rive\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x17\n\ntenderdash\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_driveB\r\n\x0b_tenderdash\x1a\xcc\x02\n\x08Protocol\x12p\n\ntenderdash\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Protocol.Tenderdash\x12\x66\n\x05\x64rive\x18\x02 \x01(\x0b\x32W.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Protocol.Drive\x1a(\n\nTenderdash\x12\x0b\n\x03p2p\x18\x01 \x01(\r\x12\r\n\x05\x62lock\x18\x02 \x01(\r\x1a<\n\x05\x44rive\x12\x0e\n\x06latest\x18\x03 \x01(\r\x12\x0f\n\x07\x63urrent\x18\x04 \x01(\r\x12\x12\n\nnext_epoch\x18\x05 \x01(\r\x1a\x7f\n\x04Time\x12\x11\n\x05local\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x16\n\x05\x62lock\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x88\x01\x01\x12\x18\n\x07genesis\x18\x03 \x01(\x04\x42\x02\x30\x01H\x01\x88\x01\x01\x12\x12\n\x05\x65poch\x18\x04 \x01(\rH\x02\x88\x01\x01\x42\x08\n\x06_blockB\n\n\x08_genesisB\x08\n\x06_epoch\x1a<\n\x04Node\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x18\n\x0bpro_tx_hash\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x42\x0e\n\x0c_pro_tx_hash\x1a\xb3\x02\n\x05\x43hain\x12\x13\n\x0b\x63\x61tching_up\x18\x01 \x01(\x08\x12\x19\n\x11latest_block_hash\x18\x02 \x01(\x0c\x12\x17\n\x0flatest_app_hash\x18\x03 \x01(\x0c\x12\x1f\n\x13latest_block_height\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x1b\n\x13\x65\x61rliest_block_hash\x18\x05 \x01(\x0c\x12\x19\n\x11\x65\x61rliest_app_hash\x18\x06 \x01(\x0c\x12!\n\x15\x65\x61rliest_block_height\x18\x07 \x01(\x04\x42\x02\x30\x01\x12!\n\x15max_peer_block_height\x18\t \x01(\x04\x42\x02\x30\x01\x12%\n\x18\x63ore_chain_locked_height\x18\n \x01(\rH\x00\x88\x01\x01\x42\x1b\n\x19_core_chain_locked_height\x1a\x43\n\x07Network\x12\x10\n\x08\x63hain_id\x18\x01 \x01(\t\x12\x13\n\x0bpeers_count\x18\x02 \x01(\r\x12\x11\n\tlistening\x18\x03 \x01(\x08\x1a\x85\x02\n\tStateSync\x12\x1d\n\x11total_synced_time\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1a\n\x0eremaining_time\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x17\n\x0ftotal_snapshots\x18\x03 \x01(\r\x12\"\n\x16\x63hunk_process_avg_time\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x1b\n\x0fsnapshot_height\x18\x05 \x01(\x04\x42\x02\x30\x01\x12!\n\x15snapshot_chunks_count\x18\x06 \x01(\x04\x42\x02\x30\x01\x12\x1d\n\x11\x62\x61\x63kfilled_blocks\x18\x07 \x01(\x04\x42\x02\x30\x01\x12!\n\x15\x62\x61\x63kfill_blocks_total\x18\x08 \x01(\x04\x42\x02\x30\x01\x42\t\n\x07version\"\xb1\x01\n\x1cGetCurrentQuorumsInfoRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoRequest.GetCurrentQuorumsInfoRequestV0H\x00\x1a \n\x1eGetCurrentQuorumsInfoRequestV0B\t\n\x07version\"\xa1\x05\n\x1dGetCurrentQuorumsInfoResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse.GetCurrentQuorumsInfoResponseV0H\x00\x1a\x46\n\x0bValidatorV0\x12\x13\n\x0bpro_tx_hash\x18\x01 \x01(\x0c\x12\x0f\n\x07node_ip\x18\x02 \x01(\t\x12\x11\n\tis_banned\x18\x03 \x01(\x08\x1a\xaf\x01\n\x0eValidatorSetV0\x12\x13\n\x0bquorum_hash\x18\x01 \x01(\x0c\x12\x13\n\x0b\x63ore_height\x18\x02 \x01(\r\x12U\n\x07members\x18\x03 \x03(\x0b\x32\x44.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse.ValidatorV0\x12\x1c\n\x14threshold_public_key\x18\x04 \x01(\x0c\x1a\x92\x02\n\x1fGetCurrentQuorumsInfoResponseV0\x12\x15\n\rquorum_hashes\x18\x01 \x03(\x0c\x12\x1b\n\x13\x63urrent_quorum_hash\x18\x02 \x01(\x0c\x12_\n\x0evalidator_sets\x18\x03 \x03(\x0b\x32G.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse.ValidatorSetV0\x12\x1b\n\x13last_block_proposer\x18\x04 \x01(\x0c\x12=\n\x08metadata\x18\x05 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\t\n\x07version\"\xf4\x01\n\x1fGetIdentityTokenBalancesRequest\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetIdentityTokenBalancesRequest.GetIdentityTokenBalancesRequestV0H\x00\x1aZ\n!GetIdentityTokenBalancesRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x11\n\ttoken_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xad\x05\n GetIdentityTokenBalancesResponse\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse.GetIdentityTokenBalancesResponseV0H\x00\x1a\x8f\x04\n\"GetIdentityTokenBalancesResponseV0\x12\x86\x01\n\x0etoken_balances\x18\x01 \x01(\x0b\x32l.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse.GetIdentityTokenBalancesResponseV0.TokenBalancesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aG\n\x11TokenBalanceEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x14\n\x07\x62\x61lance\x18\x02 \x01(\x04H\x00\x88\x01\x01\x42\n\n\x08_balance\x1a\x9a\x01\n\rTokenBalances\x12\x88\x01\n\x0etoken_balances\x18\x01 \x03(\x0b\x32p.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse.GetIdentityTokenBalancesResponseV0.TokenBalanceEntryB\x08\n\x06resultB\t\n\x07version\"\xfc\x01\n!GetIdentitiesTokenBalancesRequest\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesRequest.GetIdentitiesTokenBalancesRequestV0H\x00\x1a\\\n#GetIdentitiesTokenBalancesRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x14\n\x0cidentity_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xf2\x05\n\"GetIdentitiesTokenBalancesResponse\x12p\n\x02v0\x18\x01 \x01(\x0b\x32\x62.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse.GetIdentitiesTokenBalancesResponseV0H\x00\x1a\xce\x04\n$GetIdentitiesTokenBalancesResponseV0\x12\x9b\x01\n\x17identity_token_balances\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse.GetIdentitiesTokenBalancesResponseV0.IdentityTokenBalancesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aR\n\x19IdentityTokenBalanceEntry\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x14\n\x07\x62\x61lance\x18\x02 \x01(\x04H\x00\x88\x01\x01\x42\n\n\x08_balance\x1a\xb7\x01\n\x15IdentityTokenBalances\x12\x9d\x01\n\x17identity_token_balances\x18\x01 \x03(\x0b\x32|.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse.GetIdentitiesTokenBalancesResponseV0.IdentityTokenBalanceEntryB\x08\n\x06resultB\t\n\x07version\"\xe8\x01\n\x1cGetIdentityTokenInfosRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetIdentityTokenInfosRequest.GetIdentityTokenInfosRequestV0H\x00\x1aW\n\x1eGetIdentityTokenInfosRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x11\n\ttoken_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\x98\x06\n\x1dGetIdentityTokenInfosResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0H\x00\x1a\x83\x05\n\x1fGetIdentityTokenInfosResponseV0\x12z\n\x0btoken_infos\x18\x01 \x01(\x0b\x32\x63.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a(\n\x16TokenIdentityInfoEntry\x12\x0e\n\x06\x66rozen\x18\x01 \x01(\x08\x1a\xb0\x01\n\x0eTokenInfoEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x82\x01\n\x04info\x18\x02 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenIdentityInfoEntryH\x00\x88\x01\x01\x42\x07\n\x05_info\x1a\x8a\x01\n\nTokenInfos\x12|\n\x0btoken_infos\x18\x01 \x03(\x0b\x32g.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenInfoEntryB\x08\n\x06resultB\t\n\x07version\"\xf0\x01\n\x1eGetIdentitiesTokenInfosRequest\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosRequest.GetIdentitiesTokenInfosRequestV0H\x00\x1aY\n GetIdentitiesTokenInfosRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x14\n\x0cidentity_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xca\x06\n\x1fGetIdentitiesTokenInfosResponse\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0H\x00\x1a\xaf\x05\n!GetIdentitiesTokenInfosResponseV0\x12\x8f\x01\n\x14identity_token_infos\x18\x01 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0.IdentityTokenInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a(\n\x16TokenIdentityInfoEntry\x12\x0e\n\x06\x66rozen\x18\x01 \x01(\x08\x1a\xb7\x01\n\x0eTokenInfoEntry\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x86\x01\n\x04info\x18\x02 \x01(\x0b\x32s.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0.TokenIdentityInfoEntryH\x00\x88\x01\x01\x42\x07\n\x05_info\x1a\x97\x01\n\x12IdentityTokenInfos\x12\x80\x01\n\x0btoken_infos\x18\x01 \x03(\x0b\x32k.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0.TokenInfoEntryB\x08\n\x06resultB\t\n\x07version\"\xbf\x01\n\x17GetTokenStatusesRequest\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetTokenStatusesRequest.GetTokenStatusesRequestV0H\x00\x1a=\n\x19GetTokenStatusesRequestV0\x12\x11\n\ttoken_ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xe7\x04\n\x18GetTokenStatusesResponse\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetTokenStatusesResponse.GetTokenStatusesResponseV0H\x00\x1a\xe1\x03\n\x1aGetTokenStatusesResponseV0\x12v\n\x0etoken_statuses\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetTokenStatusesResponse.GetTokenStatusesResponseV0.TokenStatusesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x44\n\x10TokenStatusEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x13\n\x06paused\x18\x02 \x01(\x08H\x00\x88\x01\x01\x42\t\n\x07_paused\x1a\x88\x01\n\rTokenStatuses\x12w\n\x0etoken_statuses\x18\x01 \x03(\x0b\x32_.org.dash.platform.dapi.v0.GetTokenStatusesResponse.GetTokenStatusesResponseV0.TokenStatusEntryB\x08\n\x06resultB\t\n\x07version\"\xef\x01\n#GetTokenDirectPurchasePricesRequest\x12r\n\x02v0\x18\x01 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesRequest.GetTokenDirectPurchasePricesRequestV0H\x00\x1aI\n%GetTokenDirectPurchasePricesRequestV0\x12\x11\n\ttoken_ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x8b\t\n$GetTokenDirectPurchasePricesResponse\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0H\x00\x1a\xe1\x07\n&GetTokenDirectPurchasePricesResponseV0\x12\xa9\x01\n\x1ctoken_direct_purchase_prices\x18\x01 \x01(\x0b\x32\x80\x01.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.TokenDirectPurchasePricesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x33\n\x10PriceForQuantity\x12\x10\n\x08quantity\x18\x01 \x01(\x04\x12\r\n\x05price\x18\x02 \x01(\x04\x1a\xa7\x01\n\x0fPricingSchedule\x12\x93\x01\n\x12price_for_quantity\x18\x01 \x03(\x0b\x32w.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.PriceForQuantity\x1a\xe4\x01\n\x1dTokenDirectPurchasePriceEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x15\n\x0b\x66ixed_price\x18\x02 \x01(\x04H\x00\x12\x90\x01\n\x0evariable_price\x18\x03 \x01(\x0b\x32v.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.PricingScheduleH\x00\x42\x07\n\x05price\x1a\xc8\x01\n\x19TokenDirectPurchasePrices\x12\xaa\x01\n\x1btoken_direct_purchase_price\x18\x01 \x03(\x0b\x32\x84\x01.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.TokenDirectPurchasePriceEntryB\x08\n\x06resultB\t\n\x07version\"\xce\x01\n\x1bGetTokenContractInfoRequest\x12\x62\n\x02v0\x18\x01 \x01(\x0b\x32T.org.dash.platform.dapi.v0.GetTokenContractInfoRequest.GetTokenContractInfoRequestV0H\x00\x1a@\n\x1dGetTokenContractInfoRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xfb\x03\n\x1cGetTokenContractInfoResponse\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetTokenContractInfoResponse.GetTokenContractInfoResponseV0H\x00\x1a\xe9\x02\n\x1eGetTokenContractInfoResponseV0\x12|\n\x04\x64\x61ta\x18\x01 \x01(\x0b\x32l.org.dash.platform.dapi.v0.GetTokenContractInfoResponse.GetTokenContractInfoResponseV0.TokenContractInfoDataH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aM\n\x15TokenContractInfoData\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17token_contract_position\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xef\x04\n)GetTokenPreProgrammedDistributionsRequest\x12~\n\x02v0\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsRequest.GetTokenPreProgrammedDistributionsRequestV0H\x00\x1a\xb6\x03\n+GetTokenPreProgrammedDistributionsRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x98\x01\n\rstart_at_info\x18\x02 \x01(\x0b\x32|.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsRequest.GetTokenPreProgrammedDistributionsRequestV0.StartAtInfoH\x00\x88\x01\x01\x12\x12\n\x05limit\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\x04 \x01(\x08\x1a\x9a\x01\n\x0bStartAtInfo\x12\x15\n\rstart_time_ms\x18\x01 \x01(\x04\x12\x1c\n\x0fstart_recipient\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12%\n\x18start_recipient_included\x18\x03 \x01(\x08H\x01\x88\x01\x01\x42\x12\n\x10_start_recipientB\x1b\n\x19_start_recipient_includedB\x10\n\x0e_start_at_infoB\x08\n\x06_limitB\t\n\x07version\"\xec\x07\n*GetTokenPreProgrammedDistributionsResponse\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0H\x00\x1a\xaf\x06\n,GetTokenPreProgrammedDistributionsResponseV0\x12\xa5\x01\n\x13token_distributions\x18\x01 \x01(\x0b\x32\x85\x01.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0.TokenDistributionsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a>\n\x16TokenDistributionEntry\x12\x14\n\x0crecipient_id\x18\x01 \x01(\x0c\x12\x0e\n\x06\x61mount\x18\x02 \x01(\x04\x1a\xd4\x01\n\x1bTokenTimedDistributionEntry\x12\x11\n\ttimestamp\x18\x01 \x01(\x04\x12\xa1\x01\n\rdistributions\x18\x02 \x03(\x0b\x32\x89\x01.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0.TokenDistributionEntry\x1a\xc3\x01\n\x12TokenDistributions\x12\xac\x01\n\x13token_distributions\x18\x01 \x03(\x0b\x32\x8e\x01.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0.TokenTimedDistributionEntryB\x08\n\x06resultB\t\n\x07version\"\x82\x04\n-GetTokenPerpetualDistributionLastClaimRequest\x12\x86\x01\n\x02v0\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimRequest.GetTokenPerpetualDistributionLastClaimRequestV0H\x00\x1aI\n\x11\x43ontractTokenInfo\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17token_contract_position\x18\x02 \x01(\r\x1a\xf1\x01\n/GetTokenPerpetualDistributionLastClaimRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12v\n\rcontract_info\x18\x02 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimRequest.ContractTokenInfoH\x00\x88\x01\x01\x12\x13\n\x0bidentity_id\x18\x04 \x01(\x0c\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\x10\n\x0e_contract_infoB\t\n\x07version\"\x93\x05\n.GetTokenPerpetualDistributionLastClaimResponse\x12\x88\x01\n\x02v0\x18\x01 \x01(\x0b\x32z.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimResponse.GetTokenPerpetualDistributionLastClaimResponseV0H\x00\x1a\xca\x03\n0GetTokenPerpetualDistributionLastClaimResponseV0\x12\x9f\x01\n\nlast_claim\x18\x01 \x01(\x0b\x32\x88\x01.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimResponse.GetTokenPerpetualDistributionLastClaimResponseV0.LastClaimInfoH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1ax\n\rLastClaimInfo\x12\x1a\n\x0ctimestamp_ms\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x1a\n\x0c\x62lock_height\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x12\x0f\n\x05\x65poch\x18\x03 \x01(\rH\x00\x12\x13\n\traw_bytes\x18\x04 \x01(\x0cH\x00\x42\t\n\x07paid_atB\x08\n\x06resultB\t\n\x07version\"\xca\x01\n\x1aGetTokenTotalSupplyRequest\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetTokenTotalSupplyRequest.GetTokenTotalSupplyRequestV0H\x00\x1a?\n\x1cGetTokenTotalSupplyRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xaf\x04\n\x1bGetTokenTotalSupplyResponse\x12\x62\n\x02v0\x18\x01 \x01(\x0b\x32T.org.dash.platform.dapi.v0.GetTokenTotalSupplyResponse.GetTokenTotalSupplyResponseV0H\x00\x1a\xa0\x03\n\x1dGetTokenTotalSupplyResponseV0\x12\x88\x01\n\x12token_total_supply\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetTokenTotalSupplyResponse.GetTokenTotalSupplyResponseV0.TokenTotalSupplyEntryH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1ax\n\x15TokenTotalSupplyEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x30\n(total_aggregated_amount_in_user_accounts\x18\x02 \x01(\x04\x12\x1b\n\x13total_system_amount\x18\x03 \x01(\x04\x42\x08\n\x06resultB\t\n\x07version\"\xd2\x01\n\x13GetGroupInfoRequest\x12R\n\x02v0\x18\x01 \x01(\x0b\x32\x44.org.dash.platform.dapi.v0.GetGroupInfoRequest.GetGroupInfoRequestV0H\x00\x1a\\\n\x15GetGroupInfoRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17group_contract_position\x18\x02 \x01(\r\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xd4\x05\n\x14GetGroupInfoResponse\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0H\x00\x1a\xda\x04\n\x16GetGroupInfoResponseV0\x12\x66\n\ngroup_info\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0.GroupInfoH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x04 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x34\n\x10GroupMemberEntry\x12\x11\n\tmember_id\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x02 \x01(\r\x1a\x98\x01\n\x0eGroupInfoEntry\x12h\n\x07members\x18\x01 \x03(\x0b\x32W.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0.GroupMemberEntry\x12\x1c\n\x14group_required_power\x18\x02 \x01(\r\x1a\x8a\x01\n\tGroupInfo\x12n\n\ngroup_info\x18\x01 \x01(\x0b\x32U.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0.GroupInfoEntryH\x00\x88\x01\x01\x42\r\n\x0b_group_infoB\x08\n\x06resultB\t\n\x07version\"\xed\x03\n\x14GetGroupInfosRequest\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetGroupInfosRequest.GetGroupInfosRequestV0H\x00\x1au\n\x1cStartAtGroupContractPosition\x12%\n\x1dstart_group_contract_position\x18\x01 \x01(\r\x12.\n&start_group_contract_position_included\x18\x02 \x01(\x08\x1a\xfc\x01\n\x16GetGroupInfosRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12{\n start_at_group_contract_position\x18\x02 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetGroupInfosRequest.StartAtGroupContractPositionH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\x04 \x01(\x08\x42#\n!_start_at_group_contract_positionB\x08\n\x06_countB\t\n\x07version\"\xff\x05\n\x15GetGroupInfosResponse\x12V\n\x02v0\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0H\x00\x1a\x82\x05\n\x17GetGroupInfosResponseV0\x12j\n\x0bgroup_infos\x18\x01 \x01(\x0b\x32S.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0.GroupInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x04 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x34\n\x10GroupMemberEntry\x12\x11\n\tmember_id\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x02 \x01(\r\x1a\xc3\x01\n\x16GroupPositionInfoEntry\x12\x1f\n\x17group_contract_position\x18\x01 \x01(\r\x12j\n\x07members\x18\x02 \x03(\x0b\x32Y.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0.GroupMemberEntry\x12\x1c\n\x14group_required_power\x18\x03 \x01(\r\x1a\x82\x01\n\nGroupInfos\x12t\n\x0bgroup_infos\x18\x01 \x03(\x0b\x32_.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0.GroupPositionInfoEntryB\x08\n\x06resultB\t\n\x07version\"\xbe\x04\n\x16GetGroupActionsRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetGroupActionsRequest.GetGroupActionsRequestV0H\x00\x1aL\n\x0fStartAtActionId\x12\x17\n\x0fstart_action_id\x18\x01 \x01(\x0c\x12 \n\x18start_action_id_included\x18\x02 \x01(\x08\x1a\xc8\x02\n\x18GetGroupActionsRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17group_contract_position\x18\x02 \x01(\r\x12N\n\x06status\x18\x03 \x01(\x0e\x32>.org.dash.platform.dapi.v0.GetGroupActionsRequest.ActionStatus\x12\x62\n\x12start_at_action_id\x18\x04 \x01(\x0b\x32\x41.org.dash.platform.dapi.v0.GetGroupActionsRequest.StartAtActionIdH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x05 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\x06 \x01(\x08\x42\x15\n\x13_start_at_action_idB\x08\n\x06_count\"&\n\x0c\x41\x63tionStatus\x12\n\n\x06\x41\x43TIVE\x10\x00\x12\n\n\x06\x43LOSED\x10\x01\x42\t\n\x07version\"\xd6\x1e\n\x17GetGroupActionsResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0H\x00\x1a\xd3\x1d\n\x19GetGroupActionsResponseV0\x12r\n\rgroup_actions\x18\x01 \x01(\x0b\x32Y.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.GroupActionsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a[\n\tMintEvent\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x04\x12\x14\n\x0crecipient_id\x18\x02 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a[\n\tBurnEvent\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x04\x12\x14\n\x0c\x62urn_from_id\x18\x02 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1aJ\n\x0b\x46reezeEvent\x12\x11\n\tfrozen_id\x18\x01 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1aL\n\rUnfreezeEvent\x12\x11\n\tfrozen_id\x18\x01 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a\x66\n\x17\x44\x65stroyFrozenFundsEvent\x12\x11\n\tfrozen_id\x18\x01 \x01(\x0c\x12\x0e\n\x06\x61mount\x18\x02 \x01(\x04\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a\x64\n\x13SharedEncryptedNote\x12\x18\n\x10sender_key_index\x18\x01 \x01(\r\x12\x1b\n\x13recipient_key_index\x18\x02 \x01(\r\x12\x16\n\x0e\x65ncrypted_data\x18\x03 \x01(\x0c\x1a{\n\x15PersonalEncryptedNote\x12!\n\x19root_encryption_key_index\x18\x01 \x01(\r\x12\'\n\x1f\x64\x65rivation_encryption_key_index\x18\x02 \x01(\r\x12\x16\n\x0e\x65ncrypted_data\x18\x03 \x01(\x0c\x1a\xe9\x01\n\x14\x45mergencyActionEvent\x12\x81\x01\n\x0b\x61\x63tion_type\x18\x01 \x01(\x0e\x32l.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.EmergencyActionEvent.ActionType\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\"#\n\nActionType\x12\t\n\x05PAUSE\x10\x00\x12\n\n\x06RESUME\x10\x01\x42\x0e\n\x0c_public_note\x1a\x64\n\x16TokenConfigUpdateEvent\x12 \n\x18token_config_update_item\x18\x01 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a\xe6\x03\n\x1eUpdateDirectPurchasePriceEvent\x12\x15\n\x0b\x66ixed_price\x18\x01 \x01(\x04H\x00\x12\x95\x01\n\x0evariable_price\x18\x02 \x01(\x0b\x32{.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UpdateDirectPurchasePriceEvent.PricingScheduleH\x00\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x01\x88\x01\x01\x1a\x33\n\x10PriceForQuantity\x12\x10\n\x08quantity\x18\x01 \x01(\x04\x12\r\n\x05price\x18\x02 \x01(\x04\x1a\xac\x01\n\x0fPricingSchedule\x12\x98\x01\n\x12price_for_quantity\x18\x01 \x03(\x0b\x32|.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UpdateDirectPurchasePriceEvent.PriceForQuantityB\x07\n\x05priceB\x0e\n\x0c_public_note\x1a\xfc\x02\n\x10GroupActionEvent\x12n\n\x0btoken_event\x18\x01 \x01(\x0b\x32W.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.TokenEventH\x00\x12t\n\x0e\x64ocument_event\x18\x02 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.DocumentEventH\x00\x12t\n\x0e\x63ontract_event\x18\x03 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.ContractEventH\x00\x42\x0c\n\nevent_type\x1a\x8b\x01\n\rDocumentEvent\x12r\n\x06\x63reate\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.DocumentCreateEventH\x00\x42\x06\n\x04type\x1a/\n\x13\x44ocumentCreateEvent\x12\x18\n\x10\x63reated_document\x18\x01 \x01(\x0c\x1a/\n\x13\x43ontractUpdateEvent\x12\x18\n\x10updated_contract\x18\x01 \x01(\x0c\x1a\x8b\x01\n\rContractEvent\x12r\n\x06update\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.ContractUpdateEventH\x00\x42\x06\n\x04type\x1a\xd1\x07\n\nTokenEvent\x12\x66\n\x04mint\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.MintEventH\x00\x12\x66\n\x04\x62urn\x18\x02 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.BurnEventH\x00\x12j\n\x06\x66reeze\x18\x03 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.FreezeEventH\x00\x12n\n\x08unfreeze\x18\x04 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UnfreezeEventH\x00\x12\x84\x01\n\x14\x64\x65stroy_frozen_funds\x18\x05 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.DestroyFrozenFundsEventH\x00\x12}\n\x10\x65mergency_action\x18\x06 \x01(\x0b\x32\x61.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.EmergencyActionEventH\x00\x12\x82\x01\n\x13token_config_update\x18\x07 \x01(\x0b\x32\x63.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.TokenConfigUpdateEventH\x00\x12\x83\x01\n\x0cupdate_price\x18\x08 \x01(\x0b\x32k.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UpdateDirectPurchasePriceEventH\x00\x42\x06\n\x04type\x1a\x93\x01\n\x10GroupActionEntry\x12\x11\n\taction_id\x18\x01 \x01(\x0c\x12l\n\x05\x65vent\x18\x02 \x01(\x0b\x32].org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.GroupActionEvent\x1a\x84\x01\n\x0cGroupActions\x12t\n\rgroup_actions\x18\x01 \x03(\x0b\x32].org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.GroupActionEntryB\x08\n\x06resultB\t\n\x07version\"\x88\x03\n\x1cGetGroupActionSignersRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetGroupActionSignersRequest.GetGroupActionSignersRequestV0H\x00\x1a\xce\x01\n\x1eGetGroupActionSignersRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17group_contract_position\x18\x02 \x01(\r\x12T\n\x06status\x18\x03 \x01(\x0e\x32\x44.org.dash.platform.dapi.v0.GetGroupActionSignersRequest.ActionStatus\x12\x11\n\taction_id\x18\x04 \x01(\x0c\x12\r\n\x05prove\x18\x05 \x01(\x08\"&\n\x0c\x41\x63tionStatus\x12\n\n\x06\x41\x43TIVE\x10\x00\x12\n\n\x06\x43LOSED\x10\x01\x42\t\n\x07version\"\x8b\x05\n\x1dGetGroupActionSignersResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetGroupActionSignersResponse.GetGroupActionSignersResponseV0H\x00\x1a\xf6\x03\n\x1fGetGroupActionSignersResponseV0\x12\x8b\x01\n\x14group_action_signers\x18\x01 \x01(\x0b\x32k.org.dash.platform.dapi.v0.GetGroupActionSignersResponse.GetGroupActionSignersResponseV0.GroupActionSignersH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x35\n\x11GroupActionSigner\x12\x11\n\tsigner_id\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x02 \x01(\r\x1a\x91\x01\n\x12GroupActionSigners\x12{\n\x07signers\x18\x01 \x03(\x0b\x32j.org.dash.platform.dapi.v0.GetGroupActionSignersResponse.GetGroupActionSignersResponseV0.GroupActionSignerB\x08\n\x06resultB\t\n\x07version\"\xb5\x01\n\x15GetAddressInfoRequest\x12V\n\x02v0\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetAddressInfoRequest.GetAddressInfoRequestV0H\x00\x1a\x39\n\x17GetAddressInfoRequestV0\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x85\x01\n\x10\x41\x64\x64ressInfoEntry\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12J\n\x11\x62\x61lance_and_nonce\x18\x02 \x01(\x0b\x32*.org.dash.platform.dapi.v0.BalanceAndNonceH\x00\x88\x01\x01\x42\x14\n\x12_balance_and_nonce\"1\n\x0f\x42\x61lanceAndNonce\x12\x0f\n\x07\x62\x61lance\x18\x01 \x01(\x04\x12\r\n\x05nonce\x18\x02 \x01(\r\"_\n\x12\x41\x64\x64ressInfoEntries\x12I\n\x14\x61\x64\x64ress_info_entries\x18\x01 \x03(\x0b\x32+.org.dash.platform.dapi.v0.AddressInfoEntry\"m\n\x14\x41\x64\x64ressBalanceChange\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x19\n\x0bset_balance\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x12\x1c\n\x0e\x61\x64\x64_to_balance\x18\x03 \x01(\x04\x42\x02\x30\x01H\x00\x42\x0b\n\toperation\"x\n\x1a\x42lockAddressBalanceChanges\x12\x18\n\x0c\x62lock_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12@\n\x07\x63hanges\x18\x02 \x03(\x0b\x32/.org.dash.platform.dapi.v0.AddressBalanceChange\"k\n\x1b\x41\x64\x64ressBalanceUpdateEntries\x12L\n\rblock_changes\x18\x01 \x03(\x0b\x32\x35.org.dash.platform.dapi.v0.BlockAddressBalanceChanges\"\xe1\x02\n\x16GetAddressInfoResponse\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetAddressInfoResponse.GetAddressInfoResponseV0H\x00\x1a\xe1\x01\n\x18GetAddressInfoResponseV0\x12I\n\x12\x61\x64\x64ress_info_entry\x18\x01 \x01(\x0b\x32+.org.dash.platform.dapi.v0.AddressInfoEntryH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc3\x01\n\x18GetAddressesInfosRequest\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetAddressesInfosRequest.GetAddressesInfosRequestV0H\x00\x1a>\n\x1aGetAddressesInfosRequestV0\x12\x11\n\taddresses\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xf1\x02\n\x19GetAddressesInfosResponse\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetAddressesInfosResponse.GetAddressesInfosResponseV0H\x00\x1a\xe8\x01\n\x1bGetAddressesInfosResponseV0\x12M\n\x14\x61\x64\x64ress_info_entries\x18\x01 \x01(\x0b\x32-.org.dash.platform.dapi.v0.AddressInfoEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xb5\x01\n\x1dGetAddressesTrunkStateRequest\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetAddressesTrunkStateRequest.GetAddressesTrunkStateRequestV0H\x00\x1a!\n\x1fGetAddressesTrunkStateRequestV0B\t\n\x07version\"\xaa\x02\n\x1eGetAddressesTrunkStateResponse\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetAddressesTrunkStateResponse.GetAddressesTrunkStateResponseV0H\x00\x1a\x92\x01\n GetAddressesTrunkStateResponseV0\x12/\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.Proof\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\t\n\x07version\"\xf0\x01\n\x1eGetAddressesBranchStateRequest\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetAddressesBranchStateRequest.GetAddressesBranchStateRequestV0H\x00\x1aY\n GetAddressesBranchStateRequestV0\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\r\n\x05\x64\x65pth\x18\x02 \x01(\r\x12\x19\n\x11\x63heckpoint_height\x18\x03 \x01(\x04\x42\t\n\x07version\"\xd1\x01\n\x1fGetAddressesBranchStateResponse\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetAddressesBranchStateResponse.GetAddressesBranchStateResponseV0H\x00\x1a\x37\n!GetAddressesBranchStateResponseV0\x12\x12\n\nmerk_proof\x18\x02 \x01(\x0c\x42\t\n\x07version\"\xfe\x01\n%GetRecentAddressBalanceChangesRequest\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesRequest.GetRecentAddressBalanceChangesRequestV0H\x00\x1aR\n\'GetRecentAddressBalanceChangesRequestV0\x12\x18\n\x0cstart_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xb8\x03\n&GetRecentAddressBalanceChangesResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesResponse.GetRecentAddressBalanceChangesResponseV0H\x00\x1a\x88\x02\n(GetRecentAddressBalanceChangesResponseV0\x12`\n\x1e\x61\x64\x64ress_balance_update_entries\x18\x01 \x01(\x0b\x32\x36.org.dash.platform.dapi.v0.AddressBalanceUpdateEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"G\n\x16\x42lockHeightCreditEntry\x12\x18\n\x0c\x62lock_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x13\n\x07\x63redits\x18\x02 \x01(\x04\x42\x02\x30\x01\"\xb0\x01\n\x1d\x43ompactedAddressBalanceChange\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x19\n\x0bset_credits\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x12V\n\x19\x61\x64\x64_to_credits_operations\x18\x03 \x01(\x0b\x32\x31.org.dash.platform.dapi.v0.AddToCreditsOperationsH\x00\x42\x0b\n\toperation\"\\\n\x16\x41\x64\x64ToCreditsOperations\x12\x42\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x31.org.dash.platform.dapi.v0.BlockHeightCreditEntry\"\xae\x01\n#CompactedBlockAddressBalanceChanges\x12\x1e\n\x12start_block_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1c\n\x10\x65nd_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12I\n\x07\x63hanges\x18\x03 \x03(\x0b\x32\x38.org.dash.platform.dapi.v0.CompactedAddressBalanceChange\"\x87\x01\n$CompactedAddressBalanceUpdateEntries\x12_\n\x17\x63ompacted_block_changes\x18\x01 \x03(\x0b\x32>.org.dash.platform.dapi.v0.CompactedBlockAddressBalanceChanges\"\xa9\x02\n.GetRecentCompactedAddressBalanceChangesRequest\x12\x88\x01\n\x02v0\x18\x01 \x01(\x0b\x32z.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesRequest.GetRecentCompactedAddressBalanceChangesRequestV0H\x00\x1a\x61\n0GetRecentCompactedAddressBalanceChangesRequestV0\x12\x1e\n\x12start_block_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xf0\x03\n/GetRecentCompactedAddressBalanceChangesResponse\x12\x8a\x01\n\x02v0\x18\x01 \x01(\x0b\x32|.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0H\x00\x1a\xa4\x02\n1GetRecentCompactedAddressBalanceChangesResponseV0\x12s\n(compacted_address_balance_update_entries\x18\x01 \x01(\x0b\x32?.org.dash.platform.dapi.v0.CompactedAddressBalanceUpdateEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xf4\x01\n GetShieldedEncryptedNotesRequest\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0H\x00\x1aW\n\"GetShieldedEncryptedNotesRequestV0\x12\x13\n\x0bstart_index\x18\x01 \x01(\x04\x12\r\n\x05\x63ount\x18\x02 \x01(\r\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\x99\x05\n!GetShieldedEncryptedNotesResponse\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0H\x00\x1a\xf8\x03\n#GetShieldedEncryptedNotesResponseV0\x12\x8a\x01\n\x0f\x65ncrypted_notes\x18\x01 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x34\n\rEncryptedNote\x12\x0b\n\x03\x63mx\x18\x01 \x01(\x0c\x12\x16\n\x0e\x65ncrypted_note\x18\x02 \x01(\x0c\x1a\x91\x01\n\x0e\x45ncryptedNotes\x12\x7f\n\x07\x65ntries\x18\x01 \x03(\x0b\x32n.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNoteB\x08\n\x06resultB\t\n\x07version\"\xb4\x01\n\x19GetShieldedAnchorsRequest\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0H\x00\x1a,\n\x1bGetShieldedAnchorsRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xb1\x03\n\x1aGetShieldedAnchorsResponse\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0H\x00\x1a\xa5\x02\n\x1cGetShieldedAnchorsResponseV0\x12m\n\x07\x61nchors\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.AnchorsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1a\n\x07\x41nchors\x12\x0f\n\x07\x61nchors\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xbc\x01\n\x1bGetShieldedPoolStateRequest\x12\x62\n\x02v0\x18\x01 \x01(\x0b\x32T.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0H\x00\x1a.\n\x1dGetShieldedPoolStateRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xcb\x02\n\x1cGetShieldedPoolStateResponse\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0H\x00\x1a\xb9\x01\n\x1eGetShieldedPoolStateResponseV0\x12\x1b\n\rtotal_balance\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xd4\x01\n\x1cGetShieldedNullifiersRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0H\x00\x1a\x43\n\x1eGetShieldedNullifiersRequestV0\x12\x12\n\nnullifiers\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x86\x05\n\x1dGetShieldedNullifiersResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0H\x00\x1a\xf1\x03\n\x1fGetShieldedNullifiersResponseV0\x12\x88\x01\n\x12nullifier_statuses\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatusesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x36\n\x0fNullifierStatus\x12\x11\n\tnullifier\x18\x01 \x01(\x0c\x12\x10\n\x08is_spent\x18\x02 \x01(\x08\x1a\x8e\x01\n\x11NullifierStatuses\x12y\n\x07\x65ntries\x18\x01 \x03(\x0b\x32h.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatusB\x08\n\x06resultB\t\n\x07version*Z\n\nKeyPurpose\x12\x12\n\x0e\x41UTHENTICATION\x10\x00\x12\x0e\n\nENCRYPTION\x10\x01\x12\x0e\n\nDECRYPTION\x10\x02\x12\x0c\n\x08TRANSFER\x10\x03\x12\n\n\x06VOTING\x10\x05\x32\x9e\x41\n\x08Platform\x12\x93\x01\n\x18\x62roadcastStateTransition\x12:.org.dash.platform.dapi.v0.BroadcastStateTransitionRequest\x1a;.org.dash.platform.dapi.v0.BroadcastStateTransitionResponse\x12l\n\x0bgetIdentity\x12-.org.dash.platform.dapi.v0.GetIdentityRequest\x1a..org.dash.platform.dapi.v0.GetIdentityResponse\x12x\n\x0fgetIdentityKeys\x12\x31.org.dash.platform.dapi.v0.GetIdentityKeysRequest\x1a\x32.org.dash.platform.dapi.v0.GetIdentityKeysResponse\x12\x96\x01\n\x19getIdentitiesContractKeys\x12;.org.dash.platform.dapi.v0.GetIdentitiesContractKeysRequest\x1a<.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse\x12{\n\x10getIdentityNonce\x12\x32.org.dash.platform.dapi.v0.GetIdentityNonceRequest\x1a\x33.org.dash.platform.dapi.v0.GetIdentityNonceResponse\x12\x93\x01\n\x18getIdentityContractNonce\x12:.org.dash.platform.dapi.v0.GetIdentityContractNonceRequest\x1a;.org.dash.platform.dapi.v0.GetIdentityContractNonceResponse\x12\x81\x01\n\x12getIdentityBalance\x12\x34.org.dash.platform.dapi.v0.GetIdentityBalanceRequest\x1a\x35.org.dash.platform.dapi.v0.GetIdentityBalanceResponse\x12\x8a\x01\n\x15getIdentitiesBalances\x12\x37.org.dash.platform.dapi.v0.GetIdentitiesBalancesRequest\x1a\x38.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse\x12\xa2\x01\n\x1dgetIdentityBalanceAndRevision\x12?.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionRequest\x1a@.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionResponse\x12\xaf\x01\n#getEvonodesProposedEpochBlocksByIds\x12\x45.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByIdsRequest\x1a\x41.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse\x12\xb3\x01\n%getEvonodesProposedEpochBlocksByRange\x12G.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByRangeRequest\x1a\x41.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse\x12x\n\x0fgetDataContract\x12\x31.org.dash.platform.dapi.v0.GetDataContractRequest\x1a\x32.org.dash.platform.dapi.v0.GetDataContractResponse\x12\x8d\x01\n\x16getDataContractHistory\x12\x38.org.dash.platform.dapi.v0.GetDataContractHistoryRequest\x1a\x39.org.dash.platform.dapi.v0.GetDataContractHistoryResponse\x12{\n\x10getDataContracts\x12\x32.org.dash.platform.dapi.v0.GetDataContractsRequest\x1a\x33.org.dash.platform.dapi.v0.GetDataContractsResponse\x12o\n\x0cgetDocuments\x12..org.dash.platform.dapi.v0.GetDocumentsRequest\x1a/.org.dash.platform.dapi.v0.GetDocumentsResponse\x12\x99\x01\n\x1agetIdentityByPublicKeyHash\x12<.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashRequest\x1a=.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashResponse\x12\xb4\x01\n#getIdentityByNonUniquePublicKeyHash\x12\x45.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashRequest\x1a\x46.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse\x12\x9f\x01\n\x1cwaitForStateTransitionResult\x12>.org.dash.platform.dapi.v0.WaitForStateTransitionResultRequest\x1a?.org.dash.platform.dapi.v0.WaitForStateTransitionResultResponse\x12\x81\x01\n\x12getConsensusParams\x12\x34.org.dash.platform.dapi.v0.GetConsensusParamsRequest\x1a\x35.org.dash.platform.dapi.v0.GetConsensusParamsResponse\x12\xa5\x01\n\x1egetProtocolVersionUpgradeState\x12@.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateRequest\x1a\x41.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse\x12\xb4\x01\n#getProtocolVersionUpgradeVoteStatus\x12\x45.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusRequest\x1a\x46.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse\x12r\n\rgetEpochsInfo\x12/.org.dash.platform.dapi.v0.GetEpochsInfoRequest\x1a\x30.org.dash.platform.dapi.v0.GetEpochsInfoResponse\x12\x8d\x01\n\x16getFinalizedEpochInfos\x12\x38.org.dash.platform.dapi.v0.GetFinalizedEpochInfosRequest\x1a\x39.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse\x12\x8a\x01\n\x15getContestedResources\x12\x37.org.dash.platform.dapi.v0.GetContestedResourcesRequest\x1a\x38.org.dash.platform.dapi.v0.GetContestedResourcesResponse\x12\xa2\x01\n\x1dgetContestedResourceVoteState\x12?.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest\x1a@.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse\x12\xba\x01\n%getContestedResourceVotersForIdentity\x12G.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityRequest\x1aH.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityResponse\x12\xae\x01\n!getContestedResourceIdentityVotes\x12\x43.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesRequest\x1a\x44.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse\x12\x8a\x01\n\x15getVotePollsByEndDate\x12\x37.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest\x1a\x38.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse\x12\xa5\x01\n\x1egetPrefundedSpecializedBalance\x12@.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceRequest\x1a\x41.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceResponse\x12\x96\x01\n\x19getTotalCreditsInPlatform\x12;.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformRequest\x1a<.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformResponse\x12x\n\x0fgetPathElements\x12\x31.org.dash.platform.dapi.v0.GetPathElementsRequest\x1a\x32.org.dash.platform.dapi.v0.GetPathElementsResponse\x12\x66\n\tgetStatus\x12+.org.dash.platform.dapi.v0.GetStatusRequest\x1a,.org.dash.platform.dapi.v0.GetStatusResponse\x12\x8a\x01\n\x15getCurrentQuorumsInfo\x12\x37.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoRequest\x1a\x38.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse\x12\x93\x01\n\x18getIdentityTokenBalances\x12:.org.dash.platform.dapi.v0.GetIdentityTokenBalancesRequest\x1a;.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse\x12\x99\x01\n\x1agetIdentitiesTokenBalances\x12<.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesRequest\x1a=.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse\x12\x8a\x01\n\x15getIdentityTokenInfos\x12\x37.org.dash.platform.dapi.v0.GetIdentityTokenInfosRequest\x1a\x38.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse\x12\x90\x01\n\x17getIdentitiesTokenInfos\x12\x39.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosRequest\x1a:.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse\x12{\n\x10getTokenStatuses\x12\x32.org.dash.platform.dapi.v0.GetTokenStatusesRequest\x1a\x33.org.dash.platform.dapi.v0.GetTokenStatusesResponse\x12\x9f\x01\n\x1cgetTokenDirectPurchasePrices\x12>.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesRequest\x1a?.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse\x12\x87\x01\n\x14getTokenContractInfo\x12\x36.org.dash.platform.dapi.v0.GetTokenContractInfoRequest\x1a\x37.org.dash.platform.dapi.v0.GetTokenContractInfoResponse\x12\xb1\x01\n\"getTokenPreProgrammedDistributions\x12\x44.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsRequest\x1a\x45.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse\x12\xbd\x01\n&getTokenPerpetualDistributionLastClaim\x12H.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimRequest\x1aI.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimResponse\x12\x84\x01\n\x13getTokenTotalSupply\x12\x35.org.dash.platform.dapi.v0.GetTokenTotalSupplyRequest\x1a\x36.org.dash.platform.dapi.v0.GetTokenTotalSupplyResponse\x12o\n\x0cgetGroupInfo\x12..org.dash.platform.dapi.v0.GetGroupInfoRequest\x1a/.org.dash.platform.dapi.v0.GetGroupInfoResponse\x12r\n\rgetGroupInfos\x12/.org.dash.platform.dapi.v0.GetGroupInfosRequest\x1a\x30.org.dash.platform.dapi.v0.GetGroupInfosResponse\x12x\n\x0fgetGroupActions\x12\x31.org.dash.platform.dapi.v0.GetGroupActionsRequest\x1a\x32.org.dash.platform.dapi.v0.GetGroupActionsResponse\x12\x8a\x01\n\x15getGroupActionSigners\x12\x37.org.dash.platform.dapi.v0.GetGroupActionSignersRequest\x1a\x38.org.dash.platform.dapi.v0.GetGroupActionSignersResponse\x12u\n\x0egetAddressInfo\x12\x30.org.dash.platform.dapi.v0.GetAddressInfoRequest\x1a\x31.org.dash.platform.dapi.v0.GetAddressInfoResponse\x12~\n\x11getAddressesInfos\x12\x33.org.dash.platform.dapi.v0.GetAddressesInfosRequest\x1a\x34.org.dash.platform.dapi.v0.GetAddressesInfosResponse\x12\x8d\x01\n\x16getAddressesTrunkState\x12\x38.org.dash.platform.dapi.v0.GetAddressesTrunkStateRequest\x1a\x39.org.dash.platform.dapi.v0.GetAddressesTrunkStateResponse\x12\x90\x01\n\x17getAddressesBranchState\x12\x39.org.dash.platform.dapi.v0.GetAddressesBranchStateRequest\x1a:.org.dash.platform.dapi.v0.GetAddressesBranchStateResponse\x12\xa5\x01\n\x1egetRecentAddressBalanceChanges\x12@.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesRequest\x1a\x41.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesResponse\x12\xc0\x01\n\'getRecentCompactedAddressBalanceChanges\x12I.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesRequest\x1aJ.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse\x12\x96\x01\n\x19getShieldedEncryptedNotes\x12;.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest\x1a<.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse\x12\x81\x01\n\x12getShieldedAnchors\x12\x34.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest\x1a\x35.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse\x12\x87\x01\n\x14getShieldedPoolState\x12\x36.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest\x1a\x37.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse\x12\x8a\x01\n\x15getShieldedNullifiers\x12\x37.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest\x1a\x38.org.dash.platform.dapi.v0.GetShieldedNullifiersResponseb\x06proto3' , dependencies=[google_dot_protobuf_dot_wrappers__pb2.DESCRIPTOR,google_dot_protobuf_dot_struct__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,]) @@ -62,8 +62,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=55812, - serialized_end=55902, + serialized_start=58735, + serialized_end=58825, ) _sym_db.RegisterEnumDescriptor(_KEYPURPOSE) @@ -14725,6 +14725,816 @@ serialized_end=55810, ) + +_GETSHIELDEDENCRYPTEDNOTESREQUEST_GETSHIELDEDENCRYPTEDNOTESREQUESTV0 = _descriptor.Descriptor( + name='GetShieldedEncryptedNotesRequestV0', + full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='start_index', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.start_index', index=0, + number=1, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='count', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.count', index=1, + number=2, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='prove', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.prove', index=2, + number=3, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=55959, + serialized_end=56046, +) + +_GETSHIELDEDENCRYPTEDNOTESREQUEST = _descriptor.Descriptor( + name='GetShieldedEncryptedNotesRequest', + full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='v0', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.v0', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETSHIELDEDENCRYPTEDNOTESREQUEST_GETSHIELDEDENCRYPTEDNOTESREQUESTV0, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='version', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.version', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=55813, + serialized_end=56057, +) + + +_GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0_ENCRYPTEDNOTE = _descriptor.Descriptor( + name='EncryptedNote', + full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='cmx', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.cmx', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='encrypted_note', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.encrypted_note', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=56504, + serialized_end=56556, +) + +_GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0_ENCRYPTEDNOTES = _descriptor.Descriptor( + name='EncryptedNotes', + full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='entries', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.entries', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=56559, + serialized_end=56704, +) + +_GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0 = _descriptor.Descriptor( + name='GetShieldedEncryptedNotesResponseV0', + full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='encrypted_notes', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.encrypted_notes', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='proof', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.proof', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='metadata', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.metadata', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0_ENCRYPTEDNOTE, _GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0_ENCRYPTEDNOTES, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='result', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.result', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=56210, + serialized_end=56714, +) + +_GETSHIELDEDENCRYPTEDNOTESRESPONSE = _descriptor.Descriptor( + name='GetShieldedEncryptedNotesResponse', + full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='v0', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.v0', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='version', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.version', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=56060, + serialized_end=56725, +) + + +_GETSHIELDEDANCHORSREQUEST_GETSHIELDEDANCHORSREQUESTV0 = _descriptor.Descriptor( + name='GetShieldedAnchorsRequestV0', + full_name='org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='prove', full_name='org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.prove', index=0, + number=1, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=56853, + serialized_end=56897, +) + +_GETSHIELDEDANCHORSREQUEST = _descriptor.Descriptor( + name='GetShieldedAnchorsRequest', + full_name='org.dash.platform.dapi.v0.GetShieldedAnchorsRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='v0', full_name='org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.v0', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETSHIELDEDANCHORSREQUEST_GETSHIELDEDANCHORSREQUESTV0, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='version', full_name='org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.version', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=56728, + serialized_end=56908, +) + + +_GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0_ANCHORS = _descriptor.Descriptor( + name='Anchors', + full_name='org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='anchors', full_name='org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.anchors', index=0, + number=1, type=12, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=57297, + serialized_end=57323, +) + +_GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0 = _descriptor.Descriptor( + name='GetShieldedAnchorsResponseV0', + full_name='org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='anchors', full_name='org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.anchors', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='proof', full_name='org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.proof', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='metadata', full_name='org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.metadata', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0_ANCHORS, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='result', full_name='org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.result', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=57040, + serialized_end=57333, +) + +_GETSHIELDEDANCHORSRESPONSE = _descriptor.Descriptor( + name='GetShieldedAnchorsResponse', + full_name='org.dash.platform.dapi.v0.GetShieldedAnchorsResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='v0', full_name='org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.v0', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='version', full_name='org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.version', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=56911, + serialized_end=57344, +) + + +_GETSHIELDEDPOOLSTATEREQUEST_GETSHIELDEDPOOLSTATEREQUESTV0 = _descriptor.Descriptor( + name='GetShieldedPoolStateRequestV0', + full_name='org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='prove', full_name='org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.prove', index=0, + number=1, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=57478, + serialized_end=57524, +) + +_GETSHIELDEDPOOLSTATEREQUEST = _descriptor.Descriptor( + name='GetShieldedPoolStateRequest', + full_name='org.dash.platform.dapi.v0.GetShieldedPoolStateRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='v0', full_name='org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.v0', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETSHIELDEDPOOLSTATEREQUEST_GETSHIELDEDPOOLSTATEREQUESTV0, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='version', full_name='org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.version', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=57347, + serialized_end=57535, +) + + +_GETSHIELDEDPOOLSTATERESPONSE_GETSHIELDEDPOOLSTATERESPONSEV0 = _descriptor.Descriptor( + name='GetShieldedPoolStateResponseV0', + full_name='org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='total_balance', full_name='org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.total_balance', index=0, + number=1, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=b'0\001', file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='proof', full_name='org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.proof', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='metadata', full_name='org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.metadata', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='result', full_name='org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.result', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=57673, + serialized_end=57858, +) + +_GETSHIELDEDPOOLSTATERESPONSE = _descriptor.Descriptor( + name='GetShieldedPoolStateResponse', + full_name='org.dash.platform.dapi.v0.GetShieldedPoolStateResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='v0', full_name='org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.v0', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETSHIELDEDPOOLSTATERESPONSE_GETSHIELDEDPOOLSTATERESPONSEV0, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='version', full_name='org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.version', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=57538, + serialized_end=57869, +) + + +_GETSHIELDEDNULLIFIERSREQUEST_GETSHIELDEDNULLIFIERSREQUESTV0 = _descriptor.Descriptor( + name='GetShieldedNullifiersRequestV0', + full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='nullifiers', full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.nullifiers', index=0, + number=1, type=12, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='prove', full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prove', index=1, + number=2, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=58006, + serialized_end=58073, +) + +_GETSHIELDEDNULLIFIERSREQUEST = _descriptor.Descriptor( + name='GetShieldedNullifiersRequest', + full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='v0', full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.v0', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETSHIELDEDNULLIFIERSREQUEST_GETSHIELDEDNULLIFIERSREQUESTV0, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='version', full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.version', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=57872, + serialized_end=58084, +) + + +_GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0_NULLIFIERSTATUS = _descriptor.Descriptor( + name='NullifierStatus', + full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='nullifier', full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.nullifier', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='is_spent', full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.is_spent', index=1, + number=2, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=58513, + serialized_end=58567, +) + +_GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0_NULLIFIERSTATUSES = _descriptor.Descriptor( + name='NullifierStatuses', + full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='entries', full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.entries', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=58570, + serialized_end=58712, +) + +_GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0 = _descriptor.Descriptor( + name='GetShieldedNullifiersResponseV0', + full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='nullifier_statuses', full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.nullifier_statuses', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='proof', full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.proof', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='metadata', full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.metadata', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0_NULLIFIERSTATUS, _GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0_NULLIFIERSTATUSES, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='result', full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.result', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=58225, + serialized_end=58722, +) + +_GETSHIELDEDNULLIFIERSRESPONSE = _descriptor.Descriptor( + name='GetShieldedNullifiersResponse', + full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='v0', full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.v0', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='version', full_name='org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.version', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=58087, + serialized_end=58733, +) + _GETIDENTITYREQUEST_GETIDENTITYREQUESTV0.containing_type = _GETIDENTITYREQUEST _GETIDENTITYREQUEST.fields_by_name['v0'].message_type = _GETIDENTITYREQUEST_GETIDENTITYREQUESTV0 _GETIDENTITYREQUEST.oneofs_by_name['version'].fields.append( @@ -16142,6 +16952,88 @@ _GETRECENTCOMPACTEDADDRESSBALANCECHANGESRESPONSE.oneofs_by_name['version'].fields.append( _GETRECENTCOMPACTEDADDRESSBALANCECHANGESRESPONSE.fields_by_name['v0']) _GETRECENTCOMPACTEDADDRESSBALANCECHANGESRESPONSE.fields_by_name['v0'].containing_oneof = _GETRECENTCOMPACTEDADDRESSBALANCECHANGESRESPONSE.oneofs_by_name['version'] +_GETSHIELDEDENCRYPTEDNOTESREQUEST_GETSHIELDEDENCRYPTEDNOTESREQUESTV0.containing_type = _GETSHIELDEDENCRYPTEDNOTESREQUEST +_GETSHIELDEDENCRYPTEDNOTESREQUEST.fields_by_name['v0'].message_type = _GETSHIELDEDENCRYPTEDNOTESREQUEST_GETSHIELDEDENCRYPTEDNOTESREQUESTV0 +_GETSHIELDEDENCRYPTEDNOTESREQUEST.oneofs_by_name['version'].fields.append( + _GETSHIELDEDENCRYPTEDNOTESREQUEST.fields_by_name['v0']) +_GETSHIELDEDENCRYPTEDNOTESREQUEST.fields_by_name['v0'].containing_oneof = _GETSHIELDEDENCRYPTEDNOTESREQUEST.oneofs_by_name['version'] +_GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0_ENCRYPTEDNOTE.containing_type = _GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0 +_GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0_ENCRYPTEDNOTES.fields_by_name['entries'].message_type = _GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0_ENCRYPTEDNOTE +_GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0_ENCRYPTEDNOTES.containing_type = _GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0 +_GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0.fields_by_name['encrypted_notes'].message_type = _GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0_ENCRYPTEDNOTES +_GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0.fields_by_name['proof'].message_type = _PROOF +_GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0.fields_by_name['metadata'].message_type = _RESPONSEMETADATA +_GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0.containing_type = _GETSHIELDEDENCRYPTEDNOTESRESPONSE +_GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0.oneofs_by_name['result'].fields.append( + _GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0.fields_by_name['encrypted_notes']) +_GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0.fields_by_name['encrypted_notes'].containing_oneof = _GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0.oneofs_by_name['result'] +_GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0.oneofs_by_name['result'].fields.append( + _GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0.fields_by_name['proof']) +_GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0.fields_by_name['proof'].containing_oneof = _GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0.oneofs_by_name['result'] +_GETSHIELDEDENCRYPTEDNOTESRESPONSE.fields_by_name['v0'].message_type = _GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0 +_GETSHIELDEDENCRYPTEDNOTESRESPONSE.oneofs_by_name['version'].fields.append( + _GETSHIELDEDENCRYPTEDNOTESRESPONSE.fields_by_name['v0']) +_GETSHIELDEDENCRYPTEDNOTESRESPONSE.fields_by_name['v0'].containing_oneof = _GETSHIELDEDENCRYPTEDNOTESRESPONSE.oneofs_by_name['version'] +_GETSHIELDEDANCHORSREQUEST_GETSHIELDEDANCHORSREQUESTV0.containing_type = _GETSHIELDEDANCHORSREQUEST +_GETSHIELDEDANCHORSREQUEST.fields_by_name['v0'].message_type = _GETSHIELDEDANCHORSREQUEST_GETSHIELDEDANCHORSREQUESTV0 +_GETSHIELDEDANCHORSREQUEST.oneofs_by_name['version'].fields.append( + _GETSHIELDEDANCHORSREQUEST.fields_by_name['v0']) +_GETSHIELDEDANCHORSREQUEST.fields_by_name['v0'].containing_oneof = _GETSHIELDEDANCHORSREQUEST.oneofs_by_name['version'] +_GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0_ANCHORS.containing_type = _GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0 +_GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0.fields_by_name['anchors'].message_type = _GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0_ANCHORS +_GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0.fields_by_name['proof'].message_type = _PROOF +_GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0.fields_by_name['metadata'].message_type = _RESPONSEMETADATA +_GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0.containing_type = _GETSHIELDEDANCHORSRESPONSE +_GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0.oneofs_by_name['result'].fields.append( + _GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0.fields_by_name['anchors']) +_GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0.fields_by_name['anchors'].containing_oneof = _GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0.oneofs_by_name['result'] +_GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0.oneofs_by_name['result'].fields.append( + _GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0.fields_by_name['proof']) +_GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0.fields_by_name['proof'].containing_oneof = _GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0.oneofs_by_name['result'] +_GETSHIELDEDANCHORSRESPONSE.fields_by_name['v0'].message_type = _GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0 +_GETSHIELDEDANCHORSRESPONSE.oneofs_by_name['version'].fields.append( + _GETSHIELDEDANCHORSRESPONSE.fields_by_name['v0']) +_GETSHIELDEDANCHORSRESPONSE.fields_by_name['v0'].containing_oneof = _GETSHIELDEDANCHORSRESPONSE.oneofs_by_name['version'] +_GETSHIELDEDPOOLSTATEREQUEST_GETSHIELDEDPOOLSTATEREQUESTV0.containing_type = _GETSHIELDEDPOOLSTATEREQUEST +_GETSHIELDEDPOOLSTATEREQUEST.fields_by_name['v0'].message_type = _GETSHIELDEDPOOLSTATEREQUEST_GETSHIELDEDPOOLSTATEREQUESTV0 +_GETSHIELDEDPOOLSTATEREQUEST.oneofs_by_name['version'].fields.append( + _GETSHIELDEDPOOLSTATEREQUEST.fields_by_name['v0']) +_GETSHIELDEDPOOLSTATEREQUEST.fields_by_name['v0'].containing_oneof = _GETSHIELDEDPOOLSTATEREQUEST.oneofs_by_name['version'] +_GETSHIELDEDPOOLSTATERESPONSE_GETSHIELDEDPOOLSTATERESPONSEV0.fields_by_name['proof'].message_type = _PROOF +_GETSHIELDEDPOOLSTATERESPONSE_GETSHIELDEDPOOLSTATERESPONSEV0.fields_by_name['metadata'].message_type = _RESPONSEMETADATA +_GETSHIELDEDPOOLSTATERESPONSE_GETSHIELDEDPOOLSTATERESPONSEV0.containing_type = _GETSHIELDEDPOOLSTATERESPONSE +_GETSHIELDEDPOOLSTATERESPONSE_GETSHIELDEDPOOLSTATERESPONSEV0.oneofs_by_name['result'].fields.append( + _GETSHIELDEDPOOLSTATERESPONSE_GETSHIELDEDPOOLSTATERESPONSEV0.fields_by_name['total_balance']) +_GETSHIELDEDPOOLSTATERESPONSE_GETSHIELDEDPOOLSTATERESPONSEV0.fields_by_name['total_balance'].containing_oneof = _GETSHIELDEDPOOLSTATERESPONSE_GETSHIELDEDPOOLSTATERESPONSEV0.oneofs_by_name['result'] +_GETSHIELDEDPOOLSTATERESPONSE_GETSHIELDEDPOOLSTATERESPONSEV0.oneofs_by_name['result'].fields.append( + _GETSHIELDEDPOOLSTATERESPONSE_GETSHIELDEDPOOLSTATERESPONSEV0.fields_by_name['proof']) +_GETSHIELDEDPOOLSTATERESPONSE_GETSHIELDEDPOOLSTATERESPONSEV0.fields_by_name['proof'].containing_oneof = _GETSHIELDEDPOOLSTATERESPONSE_GETSHIELDEDPOOLSTATERESPONSEV0.oneofs_by_name['result'] +_GETSHIELDEDPOOLSTATERESPONSE.fields_by_name['v0'].message_type = _GETSHIELDEDPOOLSTATERESPONSE_GETSHIELDEDPOOLSTATERESPONSEV0 +_GETSHIELDEDPOOLSTATERESPONSE.oneofs_by_name['version'].fields.append( + _GETSHIELDEDPOOLSTATERESPONSE.fields_by_name['v0']) +_GETSHIELDEDPOOLSTATERESPONSE.fields_by_name['v0'].containing_oneof = _GETSHIELDEDPOOLSTATERESPONSE.oneofs_by_name['version'] +_GETSHIELDEDNULLIFIERSREQUEST_GETSHIELDEDNULLIFIERSREQUESTV0.containing_type = _GETSHIELDEDNULLIFIERSREQUEST +_GETSHIELDEDNULLIFIERSREQUEST.fields_by_name['v0'].message_type = _GETSHIELDEDNULLIFIERSREQUEST_GETSHIELDEDNULLIFIERSREQUESTV0 +_GETSHIELDEDNULLIFIERSREQUEST.oneofs_by_name['version'].fields.append( + _GETSHIELDEDNULLIFIERSREQUEST.fields_by_name['v0']) +_GETSHIELDEDNULLIFIERSREQUEST.fields_by_name['v0'].containing_oneof = _GETSHIELDEDNULLIFIERSREQUEST.oneofs_by_name['version'] +_GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0_NULLIFIERSTATUS.containing_type = _GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0 +_GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0_NULLIFIERSTATUSES.fields_by_name['entries'].message_type = _GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0_NULLIFIERSTATUS +_GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0_NULLIFIERSTATUSES.containing_type = _GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0 +_GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0.fields_by_name['nullifier_statuses'].message_type = _GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0_NULLIFIERSTATUSES +_GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0.fields_by_name['proof'].message_type = _PROOF +_GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0.fields_by_name['metadata'].message_type = _RESPONSEMETADATA +_GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0.containing_type = _GETSHIELDEDNULLIFIERSRESPONSE +_GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0.oneofs_by_name['result'].fields.append( + _GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0.fields_by_name['nullifier_statuses']) +_GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0.fields_by_name['nullifier_statuses'].containing_oneof = _GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0.oneofs_by_name['result'] +_GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0.oneofs_by_name['result'].fields.append( + _GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0.fields_by_name['proof']) +_GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0.fields_by_name['proof'].containing_oneof = _GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0.oneofs_by_name['result'] +_GETSHIELDEDNULLIFIERSRESPONSE.fields_by_name['v0'].message_type = _GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0 +_GETSHIELDEDNULLIFIERSRESPONSE.oneofs_by_name['version'].fields.append( + _GETSHIELDEDNULLIFIERSRESPONSE.fields_by_name['v0']) +_GETSHIELDEDNULLIFIERSRESPONSE.fields_by_name['v0'].containing_oneof = _GETSHIELDEDNULLIFIERSRESPONSE.oneofs_by_name['version'] DESCRIPTOR.message_types_by_name['Proof'] = _PROOF DESCRIPTOR.message_types_by_name['ResponseMetadata'] = _RESPONSEMETADATA DESCRIPTOR.message_types_by_name['StateTransitionBroadcastError'] = _STATETRANSITIONBROADCASTERROR @@ -16266,6 +17158,14 @@ DESCRIPTOR.message_types_by_name['CompactedAddressBalanceUpdateEntries'] = _COMPACTEDADDRESSBALANCEUPDATEENTRIES DESCRIPTOR.message_types_by_name['GetRecentCompactedAddressBalanceChangesRequest'] = _GETRECENTCOMPACTEDADDRESSBALANCECHANGESREQUEST DESCRIPTOR.message_types_by_name['GetRecentCompactedAddressBalanceChangesResponse'] = _GETRECENTCOMPACTEDADDRESSBALANCECHANGESRESPONSE +DESCRIPTOR.message_types_by_name['GetShieldedEncryptedNotesRequest'] = _GETSHIELDEDENCRYPTEDNOTESREQUEST +DESCRIPTOR.message_types_by_name['GetShieldedEncryptedNotesResponse'] = _GETSHIELDEDENCRYPTEDNOTESRESPONSE +DESCRIPTOR.message_types_by_name['GetShieldedAnchorsRequest'] = _GETSHIELDEDANCHORSREQUEST +DESCRIPTOR.message_types_by_name['GetShieldedAnchorsResponse'] = _GETSHIELDEDANCHORSRESPONSE +DESCRIPTOR.message_types_by_name['GetShieldedPoolStateRequest'] = _GETSHIELDEDPOOLSTATEREQUEST +DESCRIPTOR.message_types_by_name['GetShieldedPoolStateResponse'] = _GETSHIELDEDPOOLSTATERESPONSE +DESCRIPTOR.message_types_by_name['GetShieldedNullifiersRequest'] = _GETSHIELDEDNULLIFIERSREQUEST +DESCRIPTOR.message_types_by_name['GetShieldedNullifiersResponse'] = _GETSHIELDEDNULLIFIERSRESPONSE DESCRIPTOR.enum_types_by_name['KeyPurpose'] = _KEYPURPOSE _sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -18857,6 +19757,166 @@ _sym_db.RegisterMessage(GetRecentCompactedAddressBalanceChangesResponse) _sym_db.RegisterMessage(GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0) +GetShieldedEncryptedNotesRequest = _reflection.GeneratedProtocolMessageType('GetShieldedEncryptedNotesRequest', (_message.Message,), { + + 'GetShieldedEncryptedNotesRequestV0' : _reflection.GeneratedProtocolMessageType('GetShieldedEncryptedNotesRequestV0', (_message.Message,), { + 'DESCRIPTOR' : _GETSHIELDEDENCRYPTEDNOTESREQUEST_GETSHIELDEDENCRYPTEDNOTESREQUESTV0, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0) + }) + , + 'DESCRIPTOR' : _GETSHIELDEDENCRYPTEDNOTESREQUEST, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest) + }) +_sym_db.RegisterMessage(GetShieldedEncryptedNotesRequest) +_sym_db.RegisterMessage(GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0) + +GetShieldedEncryptedNotesResponse = _reflection.GeneratedProtocolMessageType('GetShieldedEncryptedNotesResponse', (_message.Message,), { + + 'GetShieldedEncryptedNotesResponseV0' : _reflection.GeneratedProtocolMessageType('GetShieldedEncryptedNotesResponseV0', (_message.Message,), { + + 'EncryptedNote' : _reflection.GeneratedProtocolMessageType('EncryptedNote', (_message.Message,), { + 'DESCRIPTOR' : _GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0_ENCRYPTEDNOTE, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote) + }) + , + + 'EncryptedNotes' : _reflection.GeneratedProtocolMessageType('EncryptedNotes', (_message.Message,), { + 'DESCRIPTOR' : _GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0_ENCRYPTEDNOTES, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes) + }) + , + 'DESCRIPTOR' : _GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0) + }) + , + 'DESCRIPTOR' : _GETSHIELDEDENCRYPTEDNOTESRESPONSE, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse) + }) +_sym_db.RegisterMessage(GetShieldedEncryptedNotesResponse) +_sym_db.RegisterMessage(GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0) +_sym_db.RegisterMessage(GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote) +_sym_db.RegisterMessage(GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes) + +GetShieldedAnchorsRequest = _reflection.GeneratedProtocolMessageType('GetShieldedAnchorsRequest', (_message.Message,), { + + 'GetShieldedAnchorsRequestV0' : _reflection.GeneratedProtocolMessageType('GetShieldedAnchorsRequestV0', (_message.Message,), { + 'DESCRIPTOR' : _GETSHIELDEDANCHORSREQUEST_GETSHIELDEDANCHORSREQUESTV0, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0) + }) + , + 'DESCRIPTOR' : _GETSHIELDEDANCHORSREQUEST, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedAnchorsRequest) + }) +_sym_db.RegisterMessage(GetShieldedAnchorsRequest) +_sym_db.RegisterMessage(GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0) + +GetShieldedAnchorsResponse = _reflection.GeneratedProtocolMessageType('GetShieldedAnchorsResponse', (_message.Message,), { + + 'GetShieldedAnchorsResponseV0' : _reflection.GeneratedProtocolMessageType('GetShieldedAnchorsResponseV0', (_message.Message,), { + + 'Anchors' : _reflection.GeneratedProtocolMessageType('Anchors', (_message.Message,), { + 'DESCRIPTOR' : _GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0_ANCHORS, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors) + }) + , + 'DESCRIPTOR' : _GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0) + }) + , + 'DESCRIPTOR' : _GETSHIELDEDANCHORSRESPONSE, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedAnchorsResponse) + }) +_sym_db.RegisterMessage(GetShieldedAnchorsResponse) +_sym_db.RegisterMessage(GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0) +_sym_db.RegisterMessage(GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors) + +GetShieldedPoolStateRequest = _reflection.GeneratedProtocolMessageType('GetShieldedPoolStateRequest', (_message.Message,), { + + 'GetShieldedPoolStateRequestV0' : _reflection.GeneratedProtocolMessageType('GetShieldedPoolStateRequestV0', (_message.Message,), { + 'DESCRIPTOR' : _GETSHIELDEDPOOLSTATEREQUEST_GETSHIELDEDPOOLSTATEREQUESTV0, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0) + }) + , + 'DESCRIPTOR' : _GETSHIELDEDPOOLSTATEREQUEST, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedPoolStateRequest) + }) +_sym_db.RegisterMessage(GetShieldedPoolStateRequest) +_sym_db.RegisterMessage(GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0) + +GetShieldedPoolStateResponse = _reflection.GeneratedProtocolMessageType('GetShieldedPoolStateResponse', (_message.Message,), { + + 'GetShieldedPoolStateResponseV0' : _reflection.GeneratedProtocolMessageType('GetShieldedPoolStateResponseV0', (_message.Message,), { + 'DESCRIPTOR' : _GETSHIELDEDPOOLSTATERESPONSE_GETSHIELDEDPOOLSTATERESPONSEV0, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0) + }) + , + 'DESCRIPTOR' : _GETSHIELDEDPOOLSTATERESPONSE, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedPoolStateResponse) + }) +_sym_db.RegisterMessage(GetShieldedPoolStateResponse) +_sym_db.RegisterMessage(GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0) + +GetShieldedNullifiersRequest = _reflection.GeneratedProtocolMessageType('GetShieldedNullifiersRequest', (_message.Message,), { + + 'GetShieldedNullifiersRequestV0' : _reflection.GeneratedProtocolMessageType('GetShieldedNullifiersRequestV0', (_message.Message,), { + 'DESCRIPTOR' : _GETSHIELDEDNULLIFIERSREQUEST_GETSHIELDEDNULLIFIERSREQUESTV0, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0) + }) + , + 'DESCRIPTOR' : _GETSHIELDEDNULLIFIERSREQUEST, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedNullifiersRequest) + }) +_sym_db.RegisterMessage(GetShieldedNullifiersRequest) +_sym_db.RegisterMessage(GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0) + +GetShieldedNullifiersResponse = _reflection.GeneratedProtocolMessageType('GetShieldedNullifiersResponse', (_message.Message,), { + + 'GetShieldedNullifiersResponseV0' : _reflection.GeneratedProtocolMessageType('GetShieldedNullifiersResponseV0', (_message.Message,), { + + 'NullifierStatus' : _reflection.GeneratedProtocolMessageType('NullifierStatus', (_message.Message,), { + 'DESCRIPTOR' : _GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0_NULLIFIERSTATUS, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus) + }) + , + + 'NullifierStatuses' : _reflection.GeneratedProtocolMessageType('NullifierStatuses', (_message.Message,), { + 'DESCRIPTOR' : _GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0_NULLIFIERSTATUSES, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses) + }) + , + 'DESCRIPTOR' : _GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0) + }) + , + 'DESCRIPTOR' : _GETSHIELDEDNULLIFIERSRESPONSE, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetShieldedNullifiersResponse) + }) +_sym_db.RegisterMessage(GetShieldedNullifiersResponse) +_sym_db.RegisterMessage(GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0) +_sym_db.RegisterMessage(GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus) +_sym_db.RegisterMessage(GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses) + _RESPONSEMETADATA.fields_by_name['height']._options = None _RESPONSEMETADATA.fields_by_name['time_ms']._options = None @@ -18912,6 +19972,7 @@ _COMPACTEDBLOCKADDRESSBALANCECHANGES.fields_by_name['start_block_height']._options = None _COMPACTEDBLOCKADDRESSBALANCECHANGES.fields_by_name['end_block_height']._options = None _GETRECENTCOMPACTEDADDRESSBALANCECHANGESREQUEST_GETRECENTCOMPACTEDADDRESSBALANCECHANGESREQUESTV0.fields_by_name['start_block_height']._options = None +_GETSHIELDEDPOOLSTATERESPONSE_GETSHIELDEDPOOLSTATERESPONSEV0.fields_by_name['total_balance']._options = None _PLATFORM = _descriptor.ServiceDescriptor( name='Platform', @@ -18920,8 +19981,8 @@ index=0, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=55905, - serialized_end=63691, + serialized_start=58828, + serialized_end=67178, methods=[ _descriptor.MethodDescriptor( name='broadcastStateTransition', @@ -19453,6 +20514,46 @@ serialized_options=None, create_key=_descriptor._internal_create_key, ), + _descriptor.MethodDescriptor( + name='getShieldedEncryptedNotes', + full_name='org.dash.platform.dapi.v0.Platform.getShieldedEncryptedNotes', + index=53, + containing_service=None, + input_type=_GETSHIELDEDENCRYPTEDNOTESREQUEST, + output_type=_GETSHIELDEDENCRYPTEDNOTESRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='getShieldedAnchors', + full_name='org.dash.platform.dapi.v0.Platform.getShieldedAnchors', + index=54, + containing_service=None, + input_type=_GETSHIELDEDANCHORSREQUEST, + output_type=_GETSHIELDEDANCHORSRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='getShieldedPoolState', + full_name='org.dash.platform.dapi.v0.Platform.getShieldedPoolState', + index=55, + containing_service=None, + input_type=_GETSHIELDEDPOOLSTATEREQUEST, + output_type=_GETSHIELDEDPOOLSTATERESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='getShieldedNullifiers', + full_name='org.dash.platform.dapi.v0.Platform.getShieldedNullifiers', + index=56, + containing_service=None, + input_type=_GETSHIELDEDNULLIFIERSREQUEST, + output_type=_GETSHIELDEDNULLIFIERSRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), ]) _sym_db.RegisterServiceDescriptor(_PLATFORM) diff --git a/packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py b/packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py index d6e844363d0..47dcf5b6802 100644 --- a/packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py +++ b/packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py @@ -279,6 +279,26 @@ def __init__(self, channel): request_serializer=platform__pb2.GetRecentCompactedAddressBalanceChangesRequest.SerializeToString, response_deserializer=platform__pb2.GetRecentCompactedAddressBalanceChangesResponse.FromString, ) + self.getShieldedEncryptedNotes = channel.unary_unary( + '/org.dash.platform.dapi.v0.Platform/getShieldedEncryptedNotes', + request_serializer=platform__pb2.GetShieldedEncryptedNotesRequest.SerializeToString, + response_deserializer=platform__pb2.GetShieldedEncryptedNotesResponse.FromString, + ) + self.getShieldedAnchors = channel.unary_unary( + '/org.dash.platform.dapi.v0.Platform/getShieldedAnchors', + request_serializer=platform__pb2.GetShieldedAnchorsRequest.SerializeToString, + response_deserializer=platform__pb2.GetShieldedAnchorsResponse.FromString, + ) + self.getShieldedPoolState = channel.unary_unary( + '/org.dash.platform.dapi.v0.Platform/getShieldedPoolState', + request_serializer=platform__pb2.GetShieldedPoolStateRequest.SerializeToString, + response_deserializer=platform__pb2.GetShieldedPoolStateResponse.FromString, + ) + self.getShieldedNullifiers = channel.unary_unary( + '/org.dash.platform.dapi.v0.Platform/getShieldedNullifiers', + request_serializer=platform__pb2.GetShieldedNullifiersRequest.SerializeToString, + response_deserializer=platform__pb2.GetShieldedNullifiersResponse.FromString, + ) class PlatformServicer(object): @@ -607,6 +627,30 @@ def getRecentCompactedAddressBalanceChanges(self, request, context): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def getShieldedEncryptedNotes(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def getShieldedAnchors(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def getShieldedPoolState(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def getShieldedNullifiers(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def add_PlatformServicer_to_server(servicer, server): rpc_method_handlers = { @@ -875,6 +919,26 @@ def add_PlatformServicer_to_server(servicer, server): request_deserializer=platform__pb2.GetRecentCompactedAddressBalanceChangesRequest.FromString, response_serializer=platform__pb2.GetRecentCompactedAddressBalanceChangesResponse.SerializeToString, ), + 'getShieldedEncryptedNotes': grpc.unary_unary_rpc_method_handler( + servicer.getShieldedEncryptedNotes, + request_deserializer=platform__pb2.GetShieldedEncryptedNotesRequest.FromString, + response_serializer=platform__pb2.GetShieldedEncryptedNotesResponse.SerializeToString, + ), + 'getShieldedAnchors': grpc.unary_unary_rpc_method_handler( + servicer.getShieldedAnchors, + request_deserializer=platform__pb2.GetShieldedAnchorsRequest.FromString, + response_serializer=platform__pb2.GetShieldedAnchorsResponse.SerializeToString, + ), + 'getShieldedPoolState': grpc.unary_unary_rpc_method_handler( + servicer.getShieldedPoolState, + request_deserializer=platform__pb2.GetShieldedPoolStateRequest.FromString, + response_serializer=platform__pb2.GetShieldedPoolStateResponse.SerializeToString, + ), + 'getShieldedNullifiers': grpc.unary_unary_rpc_method_handler( + servicer.getShieldedNullifiers, + request_deserializer=platform__pb2.GetShieldedNullifiersRequest.FromString, + response_serializer=platform__pb2.GetShieldedNullifiersResponse.SerializeToString, + ), } generic_handler = grpc.method_handlers_generic_handler( 'org.dash.platform.dapi.v0.Platform', rpc_method_handlers) @@ -1785,3 +1849,71 @@ def getRecentCompactedAddressBalanceChanges(request, platform__pb2.GetRecentCompactedAddressBalanceChangesResponse.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def getShieldedEncryptedNotes(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/org.dash.platform.dapi.v0.Platform/getShieldedEncryptedNotes', + platform__pb2.GetShieldedEncryptedNotesRequest.SerializeToString, + platform__pb2.GetShieldedEncryptedNotesResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def getShieldedAnchors(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/org.dash.platform.dapi.v0.Platform/getShieldedAnchors', + platform__pb2.GetShieldedAnchorsRequest.SerializeToString, + platform__pb2.GetShieldedAnchorsResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def getShieldedPoolState(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/org.dash.platform.dapi.v0.Platform/getShieldedPoolState', + platform__pb2.GetShieldedPoolStateRequest.SerializeToString, + platform__pb2.GetShieldedPoolStateResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def getShieldedNullifiers(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/org.dash.platform.dapi.v0.Platform/getShieldedNullifiers', + platform__pb2.GetShieldedNullifiersRequest.SerializeToString, + platform__pb2.GetShieldedNullifiersResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts b/packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts index 25872f5db6c..e6c480d626d 100644 --- a/packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts +++ b/packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts @@ -10502,6 +10502,612 @@ export namespace GetRecentCompactedAddressBalanceChangesResponse { } } +export class GetShieldedEncryptedNotesRequest extends jspb.Message { + hasV0(): boolean; + clearV0(): void; + getV0(): GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 | undefined; + setV0(value?: GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0): void; + + getVersionCase(): GetShieldedEncryptedNotesRequest.VersionCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetShieldedEncryptedNotesRequest.AsObject; + static toObject(includeInstance: boolean, msg: GetShieldedEncryptedNotesRequest): GetShieldedEncryptedNotesRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetShieldedEncryptedNotesRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetShieldedEncryptedNotesRequest; + static deserializeBinaryFromReader(message: GetShieldedEncryptedNotesRequest, reader: jspb.BinaryReader): GetShieldedEncryptedNotesRequest; +} + +export namespace GetShieldedEncryptedNotesRequest { + export type AsObject = { + v0?: GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.AsObject, + } + + export class GetShieldedEncryptedNotesRequestV0 extends jspb.Message { + getStartIndex(): number; + setStartIndex(value: number): void; + + getCount(): number; + setCount(value: number): void; + + getProve(): boolean; + setProve(value: boolean): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetShieldedEncryptedNotesRequestV0.AsObject; + static toObject(includeInstance: boolean, msg: GetShieldedEncryptedNotesRequestV0): GetShieldedEncryptedNotesRequestV0.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetShieldedEncryptedNotesRequestV0, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetShieldedEncryptedNotesRequestV0; + static deserializeBinaryFromReader(message: GetShieldedEncryptedNotesRequestV0, reader: jspb.BinaryReader): GetShieldedEncryptedNotesRequestV0; + } + + export namespace GetShieldedEncryptedNotesRequestV0 { + export type AsObject = { + startIndex: number, + count: number, + prove: boolean, + } + } + + export enum VersionCase { + VERSION_NOT_SET = 0, + V0 = 1, + } +} + +export class GetShieldedEncryptedNotesResponse extends jspb.Message { + hasV0(): boolean; + clearV0(): void; + getV0(): GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 | undefined; + setV0(value?: GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0): void; + + getVersionCase(): GetShieldedEncryptedNotesResponse.VersionCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetShieldedEncryptedNotesResponse.AsObject; + static toObject(includeInstance: boolean, msg: GetShieldedEncryptedNotesResponse): GetShieldedEncryptedNotesResponse.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetShieldedEncryptedNotesResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetShieldedEncryptedNotesResponse; + static deserializeBinaryFromReader(message: GetShieldedEncryptedNotesResponse, reader: jspb.BinaryReader): GetShieldedEncryptedNotesResponse; +} + +export namespace GetShieldedEncryptedNotesResponse { + export type AsObject = { + v0?: GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.AsObject, + } + + export class GetShieldedEncryptedNotesResponseV0 extends jspb.Message { + hasEncryptedNotes(): boolean; + clearEncryptedNotes(): void; + getEncryptedNotes(): GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes | undefined; + setEncryptedNotes(value?: GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes): void; + + hasProof(): boolean; + clearProof(): void; + getProof(): Proof | undefined; + setProof(value?: Proof): void; + + hasMetadata(): boolean; + clearMetadata(): void; + getMetadata(): ResponseMetadata | undefined; + setMetadata(value?: ResponseMetadata): void; + + getResultCase(): GetShieldedEncryptedNotesResponseV0.ResultCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetShieldedEncryptedNotesResponseV0.AsObject; + static toObject(includeInstance: boolean, msg: GetShieldedEncryptedNotesResponseV0): GetShieldedEncryptedNotesResponseV0.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetShieldedEncryptedNotesResponseV0, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetShieldedEncryptedNotesResponseV0; + static deserializeBinaryFromReader(message: GetShieldedEncryptedNotesResponseV0, reader: jspb.BinaryReader): GetShieldedEncryptedNotesResponseV0; + } + + export namespace GetShieldedEncryptedNotesResponseV0 { + export type AsObject = { + encryptedNotes?: GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.AsObject, + proof?: Proof.AsObject, + metadata?: ResponseMetadata.AsObject, + } + + export class EncryptedNote extends jspb.Message { + getCmx(): Uint8Array | string; + getCmx_asU8(): Uint8Array; + getCmx_asB64(): string; + setCmx(value: Uint8Array | string): void; + + getEncryptedNote(): Uint8Array | string; + getEncryptedNote_asU8(): Uint8Array; + getEncryptedNote_asB64(): string; + setEncryptedNote(value: Uint8Array | string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): EncryptedNote.AsObject; + static toObject(includeInstance: boolean, msg: EncryptedNote): EncryptedNote.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: EncryptedNote, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): EncryptedNote; + static deserializeBinaryFromReader(message: EncryptedNote, reader: jspb.BinaryReader): EncryptedNote; + } + + export namespace EncryptedNote { + export type AsObject = { + cmx: Uint8Array | string, + encryptedNote: Uint8Array | string, + } + } + + export class EncryptedNotes extends jspb.Message { + clearEntriesList(): void; + getEntriesList(): Array; + setEntriesList(value: Array): void; + addEntries(value?: GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote, index?: number): GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): EncryptedNotes.AsObject; + static toObject(includeInstance: boolean, msg: EncryptedNotes): EncryptedNotes.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: EncryptedNotes, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): EncryptedNotes; + static deserializeBinaryFromReader(message: EncryptedNotes, reader: jspb.BinaryReader): EncryptedNotes; + } + + export namespace EncryptedNotes { + export type AsObject = { + entriesList: Array, + } + } + + export enum ResultCase { + RESULT_NOT_SET = 0, + ENCRYPTED_NOTES = 1, + PROOF = 2, + } + } + + export enum VersionCase { + VERSION_NOT_SET = 0, + V0 = 1, + } +} + +export class GetShieldedAnchorsRequest extends jspb.Message { + hasV0(): boolean; + clearV0(): void; + getV0(): GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 | undefined; + setV0(value?: GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0): void; + + getVersionCase(): GetShieldedAnchorsRequest.VersionCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetShieldedAnchorsRequest.AsObject; + static toObject(includeInstance: boolean, msg: GetShieldedAnchorsRequest): GetShieldedAnchorsRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetShieldedAnchorsRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetShieldedAnchorsRequest; + static deserializeBinaryFromReader(message: GetShieldedAnchorsRequest, reader: jspb.BinaryReader): GetShieldedAnchorsRequest; +} + +export namespace GetShieldedAnchorsRequest { + export type AsObject = { + v0?: GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.AsObject, + } + + export class GetShieldedAnchorsRequestV0 extends jspb.Message { + getProve(): boolean; + setProve(value: boolean): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetShieldedAnchorsRequestV0.AsObject; + static toObject(includeInstance: boolean, msg: GetShieldedAnchorsRequestV0): GetShieldedAnchorsRequestV0.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetShieldedAnchorsRequestV0, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetShieldedAnchorsRequestV0; + static deserializeBinaryFromReader(message: GetShieldedAnchorsRequestV0, reader: jspb.BinaryReader): GetShieldedAnchorsRequestV0; + } + + export namespace GetShieldedAnchorsRequestV0 { + export type AsObject = { + prove: boolean, + } + } + + export enum VersionCase { + VERSION_NOT_SET = 0, + V0 = 1, + } +} + +export class GetShieldedAnchorsResponse extends jspb.Message { + hasV0(): boolean; + clearV0(): void; + getV0(): GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 | undefined; + setV0(value?: GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0): void; + + getVersionCase(): GetShieldedAnchorsResponse.VersionCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetShieldedAnchorsResponse.AsObject; + static toObject(includeInstance: boolean, msg: GetShieldedAnchorsResponse): GetShieldedAnchorsResponse.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetShieldedAnchorsResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetShieldedAnchorsResponse; + static deserializeBinaryFromReader(message: GetShieldedAnchorsResponse, reader: jspb.BinaryReader): GetShieldedAnchorsResponse; +} + +export namespace GetShieldedAnchorsResponse { + export type AsObject = { + v0?: GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.AsObject, + } + + export class GetShieldedAnchorsResponseV0 extends jspb.Message { + hasAnchors(): boolean; + clearAnchors(): void; + getAnchors(): GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors | undefined; + setAnchors(value?: GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors): void; + + hasProof(): boolean; + clearProof(): void; + getProof(): Proof | undefined; + setProof(value?: Proof): void; + + hasMetadata(): boolean; + clearMetadata(): void; + getMetadata(): ResponseMetadata | undefined; + setMetadata(value?: ResponseMetadata): void; + + getResultCase(): GetShieldedAnchorsResponseV0.ResultCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetShieldedAnchorsResponseV0.AsObject; + static toObject(includeInstance: boolean, msg: GetShieldedAnchorsResponseV0): GetShieldedAnchorsResponseV0.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetShieldedAnchorsResponseV0, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetShieldedAnchorsResponseV0; + static deserializeBinaryFromReader(message: GetShieldedAnchorsResponseV0, reader: jspb.BinaryReader): GetShieldedAnchorsResponseV0; + } + + export namespace GetShieldedAnchorsResponseV0 { + export type AsObject = { + anchors?: GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.AsObject, + proof?: Proof.AsObject, + metadata?: ResponseMetadata.AsObject, + } + + export class Anchors extends jspb.Message { + clearAnchorsList(): void; + getAnchorsList(): Array; + getAnchorsList_asU8(): Array; + getAnchorsList_asB64(): Array; + setAnchorsList(value: Array): void; + addAnchors(value: Uint8Array | string, index?: number): Uint8Array | string; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): Anchors.AsObject; + static toObject(includeInstance: boolean, msg: Anchors): Anchors.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: Anchors, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): Anchors; + static deserializeBinaryFromReader(message: Anchors, reader: jspb.BinaryReader): Anchors; + } + + export namespace Anchors { + export type AsObject = { + anchorsList: Array, + } + } + + export enum ResultCase { + RESULT_NOT_SET = 0, + ANCHORS = 1, + PROOF = 2, + } + } + + export enum VersionCase { + VERSION_NOT_SET = 0, + V0 = 1, + } +} + +export class GetShieldedPoolStateRequest extends jspb.Message { + hasV0(): boolean; + clearV0(): void; + getV0(): GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 | undefined; + setV0(value?: GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0): void; + + getVersionCase(): GetShieldedPoolStateRequest.VersionCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetShieldedPoolStateRequest.AsObject; + static toObject(includeInstance: boolean, msg: GetShieldedPoolStateRequest): GetShieldedPoolStateRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetShieldedPoolStateRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetShieldedPoolStateRequest; + static deserializeBinaryFromReader(message: GetShieldedPoolStateRequest, reader: jspb.BinaryReader): GetShieldedPoolStateRequest; +} + +export namespace GetShieldedPoolStateRequest { + export type AsObject = { + v0?: GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.AsObject, + } + + export class GetShieldedPoolStateRequestV0 extends jspb.Message { + getProve(): boolean; + setProve(value: boolean): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetShieldedPoolStateRequestV0.AsObject; + static toObject(includeInstance: boolean, msg: GetShieldedPoolStateRequestV0): GetShieldedPoolStateRequestV0.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetShieldedPoolStateRequestV0, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetShieldedPoolStateRequestV0; + static deserializeBinaryFromReader(message: GetShieldedPoolStateRequestV0, reader: jspb.BinaryReader): GetShieldedPoolStateRequestV0; + } + + export namespace GetShieldedPoolStateRequestV0 { + export type AsObject = { + prove: boolean, + } + } + + export enum VersionCase { + VERSION_NOT_SET = 0, + V0 = 1, + } +} + +export class GetShieldedPoolStateResponse extends jspb.Message { + hasV0(): boolean; + clearV0(): void; + getV0(): GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 | undefined; + setV0(value?: GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0): void; + + getVersionCase(): GetShieldedPoolStateResponse.VersionCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetShieldedPoolStateResponse.AsObject; + static toObject(includeInstance: boolean, msg: GetShieldedPoolStateResponse): GetShieldedPoolStateResponse.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetShieldedPoolStateResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetShieldedPoolStateResponse; + static deserializeBinaryFromReader(message: GetShieldedPoolStateResponse, reader: jspb.BinaryReader): GetShieldedPoolStateResponse; +} + +export namespace GetShieldedPoolStateResponse { + export type AsObject = { + v0?: GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.AsObject, + } + + export class GetShieldedPoolStateResponseV0 extends jspb.Message { + hasTotalBalance(): boolean; + clearTotalBalance(): void; + getTotalBalance(): string; + setTotalBalance(value: string): void; + + hasProof(): boolean; + clearProof(): void; + getProof(): Proof | undefined; + setProof(value?: Proof): void; + + hasMetadata(): boolean; + clearMetadata(): void; + getMetadata(): ResponseMetadata | undefined; + setMetadata(value?: ResponseMetadata): void; + + getResultCase(): GetShieldedPoolStateResponseV0.ResultCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetShieldedPoolStateResponseV0.AsObject; + static toObject(includeInstance: boolean, msg: GetShieldedPoolStateResponseV0): GetShieldedPoolStateResponseV0.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetShieldedPoolStateResponseV0, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetShieldedPoolStateResponseV0; + static deserializeBinaryFromReader(message: GetShieldedPoolStateResponseV0, reader: jspb.BinaryReader): GetShieldedPoolStateResponseV0; + } + + export namespace GetShieldedPoolStateResponseV0 { + export type AsObject = { + totalBalance: string, + proof?: Proof.AsObject, + metadata?: ResponseMetadata.AsObject, + } + + export enum ResultCase { + RESULT_NOT_SET = 0, + TOTAL_BALANCE = 1, + PROOF = 2, + } + } + + export enum VersionCase { + VERSION_NOT_SET = 0, + V0 = 1, + } +} + +export class GetShieldedNullifiersRequest extends jspb.Message { + hasV0(): boolean; + clearV0(): void; + getV0(): GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 | undefined; + setV0(value?: GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0): void; + + getVersionCase(): GetShieldedNullifiersRequest.VersionCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetShieldedNullifiersRequest.AsObject; + static toObject(includeInstance: boolean, msg: GetShieldedNullifiersRequest): GetShieldedNullifiersRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetShieldedNullifiersRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetShieldedNullifiersRequest; + static deserializeBinaryFromReader(message: GetShieldedNullifiersRequest, reader: jspb.BinaryReader): GetShieldedNullifiersRequest; +} + +export namespace GetShieldedNullifiersRequest { + export type AsObject = { + v0?: GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.AsObject, + } + + export class GetShieldedNullifiersRequestV0 extends jspb.Message { + clearNullifiersList(): void; + getNullifiersList(): Array; + getNullifiersList_asU8(): Array; + getNullifiersList_asB64(): Array; + setNullifiersList(value: Array): void; + addNullifiers(value: Uint8Array | string, index?: number): Uint8Array | string; + + getProve(): boolean; + setProve(value: boolean): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetShieldedNullifiersRequestV0.AsObject; + static toObject(includeInstance: boolean, msg: GetShieldedNullifiersRequestV0): GetShieldedNullifiersRequestV0.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetShieldedNullifiersRequestV0, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetShieldedNullifiersRequestV0; + static deserializeBinaryFromReader(message: GetShieldedNullifiersRequestV0, reader: jspb.BinaryReader): GetShieldedNullifiersRequestV0; + } + + export namespace GetShieldedNullifiersRequestV0 { + export type AsObject = { + nullifiersList: Array, + prove: boolean, + } + } + + export enum VersionCase { + VERSION_NOT_SET = 0, + V0 = 1, + } +} + +export class GetShieldedNullifiersResponse extends jspb.Message { + hasV0(): boolean; + clearV0(): void; + getV0(): GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 | undefined; + setV0(value?: GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0): void; + + getVersionCase(): GetShieldedNullifiersResponse.VersionCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetShieldedNullifiersResponse.AsObject; + static toObject(includeInstance: boolean, msg: GetShieldedNullifiersResponse): GetShieldedNullifiersResponse.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetShieldedNullifiersResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetShieldedNullifiersResponse; + static deserializeBinaryFromReader(message: GetShieldedNullifiersResponse, reader: jspb.BinaryReader): GetShieldedNullifiersResponse; +} + +export namespace GetShieldedNullifiersResponse { + export type AsObject = { + v0?: GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.AsObject, + } + + export class GetShieldedNullifiersResponseV0 extends jspb.Message { + hasNullifierStatuses(): boolean; + clearNullifierStatuses(): void; + getNullifierStatuses(): GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses | undefined; + setNullifierStatuses(value?: GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses): void; + + hasProof(): boolean; + clearProof(): void; + getProof(): Proof | undefined; + setProof(value?: Proof): void; + + hasMetadata(): boolean; + clearMetadata(): void; + getMetadata(): ResponseMetadata | undefined; + setMetadata(value?: ResponseMetadata): void; + + getResultCase(): GetShieldedNullifiersResponseV0.ResultCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetShieldedNullifiersResponseV0.AsObject; + static toObject(includeInstance: boolean, msg: GetShieldedNullifiersResponseV0): GetShieldedNullifiersResponseV0.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetShieldedNullifiersResponseV0, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetShieldedNullifiersResponseV0; + static deserializeBinaryFromReader(message: GetShieldedNullifiersResponseV0, reader: jspb.BinaryReader): GetShieldedNullifiersResponseV0; + } + + export namespace GetShieldedNullifiersResponseV0 { + export type AsObject = { + nullifierStatuses?: GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.AsObject, + proof?: Proof.AsObject, + metadata?: ResponseMetadata.AsObject, + } + + export class NullifierStatus extends jspb.Message { + getNullifier(): Uint8Array | string; + getNullifier_asU8(): Uint8Array; + getNullifier_asB64(): string; + setNullifier(value: Uint8Array | string): void; + + getIsSpent(): boolean; + setIsSpent(value: boolean): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): NullifierStatus.AsObject; + static toObject(includeInstance: boolean, msg: NullifierStatus): NullifierStatus.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: NullifierStatus, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): NullifierStatus; + static deserializeBinaryFromReader(message: NullifierStatus, reader: jspb.BinaryReader): NullifierStatus; + } + + export namespace NullifierStatus { + export type AsObject = { + nullifier: Uint8Array | string, + isSpent: boolean, + } + } + + export class NullifierStatuses extends jspb.Message { + clearEntriesList(): void; + getEntriesList(): Array; + setEntriesList(value: Array): void; + addEntries(value?: GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus, index?: number): GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): NullifierStatuses.AsObject; + static toObject(includeInstance: boolean, msg: NullifierStatuses): NullifierStatuses.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: NullifierStatuses, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): NullifierStatuses; + static deserializeBinaryFromReader(message: NullifierStatuses, reader: jspb.BinaryReader): NullifierStatuses; + } + + export namespace NullifierStatuses { + export type AsObject = { + entriesList: Array, + } + } + + export enum ResultCase { + RESULT_NOT_SET = 0, + NULLIFIER_STATUSES = 1, + PROOF = 2, + } + } + + export enum VersionCase { + VERSION_NOT_SET = 0, + V0 = 1, + } +} + export interface KeyPurposeMap { AUTHENTICATION: 0; ENCRYPTION: 1; diff --git a/packages/dapi-grpc/clients/platform/v0/web/platform_pb.js b/packages/dapi-grpc/clients/platform/v0/web/platform_pb.js index 046bd95f81c..f38425b23af 100644 --- a/packages/dapi-grpc/clients/platform/v0/web/platform_pb.js +++ b/packages/dapi-grpc/clients/platform/v0/web/platform_pb.js @@ -418,6 +418,39 @@ goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBala goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0.ResultCase', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.ResultCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.ResultCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.ResultCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.ResultCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.VersionCase', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetStatusRequest', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetStatusRequest.GetStatusRequestV0', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetStatusRequest.VersionCase', null, { proto }); @@ -7604,6 +7637,447 @@ if (goog.DEBUG && !COMPILED) { */ proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0.displayName = 'proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.repeatedFields_, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.repeatedFields_, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.repeatedFields_, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.repeatedFields_, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses'; +} @@ -79673,6 +80147,4079 @@ proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse. }; + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest; + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.toObject = function(includeInstance, msg) { + var f, obj = { + startIndex: jspb.Message.getFieldWithDefault(msg, 1, 0), + count: jspb.Message.getFieldWithDefault(msg, 2, 0), + prove: jspb.Message.getBooleanFieldWithDefault(msg, 3, false) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0; + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readUint64()); + msg.setStartIndex(value); + break; + case 2: + var value = /** @type {number} */ (reader.readUint32()); + msg.setCount(value); + break; + case 3: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setProve(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getStartIndex(); + if (f !== 0) { + writer.writeUint64( + 1, + f + ); + } + f = message.getCount(); + if (f !== 0) { + writer.writeUint32( + 2, + f + ); + } + f = message.getProve(); + if (f) { + writer.writeBool( + 3, + f + ); + } +}; + + +/** + * optional uint64 start_index = 1; + * @return {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.prototype.getStartIndex = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.prototype.setStartIndex = function(value) { + return jspb.Message.setProto3IntField(this, 1, value); +}; + + +/** + * optional uint32 count = 2; + * @return {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.prototype.getCount = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 2, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.prototype.setCount = function(value) { + return jspb.Message.setProto3IntField(this, 2, value); +}; + + +/** + * optional bool prove = 3; + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.prototype.getProve = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 3, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0.prototype.setProve = function(value) { + return jspb.Message.setProto3BooleanField(this, 3, value); +}; + + +/** + * optional GetShieldedEncryptedNotesRequestV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse; + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.serializeBinaryToWriter + ); + } +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.oneofGroups_ = [[1,2]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.ResultCase = { + RESULT_NOT_SET: 0, + ENCRYPTED_NOTES: 1, + PROOF: 2 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.ResultCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.getResultCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.ResultCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.toObject = function(includeInstance, msg) { + var f, obj = { + encryptedNotes: (f = msg.getEncryptedNotes()) && proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.toObject(includeInstance, f), + proof: (f = msg.getProof()) && proto.org.dash.platform.dapi.v0.Proof.toObject(includeInstance, f), + metadata: (f = msg.getMetadata()) && proto.org.dash.platform.dapi.v0.ResponseMetadata.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0; + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.deserializeBinaryFromReader); + msg.setEncryptedNotes(value); + break; + case 2: + var value = new proto.org.dash.platform.dapi.v0.Proof; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.Proof.deserializeBinaryFromReader); + msg.setProof(value); + break; + case 3: + var value = new proto.org.dash.platform.dapi.v0.ResponseMetadata; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.ResponseMetadata.deserializeBinaryFromReader); + msg.setMetadata(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getEncryptedNotes(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.serializeBinaryToWriter + ); + } + f = message.getProof(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.org.dash.platform.dapi.v0.Proof.serializeBinaryToWriter + ); + } + f = message.getMetadata(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.org.dash.platform.dapi.v0.ResponseMetadata.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.toObject = function(includeInstance, msg) { + var f, obj = { + cmx: msg.getCmx_asB64(), + encryptedNote: msg.getEncryptedNote_asB64() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote; + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setCmx(value); + break; + case 2: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setEncryptedNote(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getCmx_asU8(); + if (f.length > 0) { + writer.writeBytes( + 1, + f + ); + } + f = message.getEncryptedNote_asU8(); + if (f.length > 0) { + writer.writeBytes( + 2, + f + ); + } +}; + + +/** + * optional bytes cmx = 1; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getCmx = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * optional bytes cmx = 1; + * This is a type-conversion wrapper around `getCmx()` + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getCmx_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getCmx())); +}; + + +/** + * optional bytes cmx = 1; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getCmx()` + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getCmx_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getCmx())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.setCmx = function(value) { + return jspb.Message.setProto3BytesField(this, 1, value); +}; + + +/** + * optional bytes encrypted_note = 2; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getEncryptedNote = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * optional bytes encrypted_note = 2; + * This is a type-conversion wrapper around `getEncryptedNote()` + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getEncryptedNote_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getEncryptedNote())); +}; + + +/** + * optional bytes encrypted_note = 2; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getEncryptedNote()` + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getEncryptedNote_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getEncryptedNote())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.setEncryptedNote = function(value) { + return jspb.Message.setProto3BytesField(this, 2, value); +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.toObject = function(includeInstance, msg) { + var f, obj = { + entriesList: jspb.Message.toObjectList(msg.getEntriesList(), + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.toObject, includeInstance) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes; + return proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.deserializeBinaryFromReader); + msg.addEntries(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getEntriesList(); + if (f.length > 0) { + writer.writeRepeatedMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.serializeBinaryToWriter + ); + } +}; + + +/** + * repeated EncryptedNote entries = 1; + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.prototype.getEntriesList = function() { + return /** @type{!Array} */ ( + jspb.Message.getRepeatedWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote, 1)); +}; + + +/** + * @param {!Array} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.prototype.setEntriesList = function(value) { + return jspb.Message.setRepeatedWrapperField(this, 1, value); +}; + + +/** + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote=} opt_value + * @param {number=} opt_index + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.prototype.addEntries = function(opt_value, opt_index) { + return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes.prototype.clearEntriesList = function() { + return this.setEntriesList([]); +}; + + +/** + * optional EncryptedNotes encrypted_notes = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.getEncryptedNotes = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotes|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.setEncryptedNotes = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.clearEncryptedNotes = function() { + return this.setEncryptedNotes(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.hasEncryptedNotes = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional Proof proof = 2; + * @return {?proto.org.dash.platform.dapi.v0.Proof} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.getProof = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.Proof} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.Proof, 2)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.Proof|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.setProof = function(value) { + return jspb.Message.setOneofWrapperField(this, 2, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.clearProof = function() { + return this.setProof(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.hasProof = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional ResponseMetadata metadata = 3; + * @return {?proto.org.dash.platform.dapi.v0.ResponseMetadata} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.getMetadata = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.ResponseMetadata} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.ResponseMetadata, 3)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.ResponseMetadata|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.setMetadata = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.clearMetadata = function() { + return this.setMetadata(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.prototype.hasMetadata = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional GetShieldedEncryptedNotesResponseV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest; + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.toObject = function(includeInstance, msg) { + var f, obj = { + prove: jspb.Message.getBooleanFieldWithDefault(msg, 1, false) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0; + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setProve(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getProve(); + if (f) { + writer.writeBool( + 1, + f + ); + } +}; + + +/** + * optional bool prove = 1; + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.prototype.getProve = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 1, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0.prototype.setProve = function(value) { + return jspb.Message.setProto3BooleanField(this, 1, value); +}; + + +/** + * optional GetShieldedAnchorsRequestV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse; + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.serializeBinaryToWriter + ); + } +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.oneofGroups_ = [[1,2]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.ResultCase = { + RESULT_NOT_SET: 0, + ANCHORS: 1, + PROOF: 2 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.ResultCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.getResultCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.ResultCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.toObject = function(includeInstance, msg) { + var f, obj = { + anchors: (f = msg.getAnchors()) && proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.toObject(includeInstance, f), + proof: (f = msg.getProof()) && proto.org.dash.platform.dapi.v0.Proof.toObject(includeInstance, f), + metadata: (f = msg.getMetadata()) && proto.org.dash.platform.dapi.v0.ResponseMetadata.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0; + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.deserializeBinaryFromReader); + msg.setAnchors(value); + break; + case 2: + var value = new proto.org.dash.platform.dapi.v0.Proof; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.Proof.deserializeBinaryFromReader); + msg.setProof(value); + break; + case 3: + var value = new proto.org.dash.platform.dapi.v0.ResponseMetadata; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.ResponseMetadata.deserializeBinaryFromReader); + msg.setMetadata(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getAnchors(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.serializeBinaryToWriter + ); + } + f = message.getProof(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.org.dash.platform.dapi.v0.Proof.serializeBinaryToWriter + ); + } + f = message.getMetadata(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.org.dash.platform.dapi.v0.ResponseMetadata.serializeBinaryToWriter + ); + } +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.toObject = function(includeInstance, msg) { + var f, obj = { + anchorsList: msg.getAnchorsList_asB64() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors; + return proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.addAnchors(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getAnchorsList_asU8(); + if (f.length > 0) { + writer.writeRepeatedBytes( + 1, + f + ); + } +}; + + +/** + * repeated bytes anchors = 1; + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.prototype.getAnchorsList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 1)); +}; + + +/** + * repeated bytes anchors = 1; + * This is a type-conversion wrapper around `getAnchorsList()` + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.prototype.getAnchorsList_asB64 = function() { + return /** @type {!Array} */ (jspb.Message.bytesListAsB64( + this.getAnchorsList())); +}; + + +/** + * repeated bytes anchors = 1; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getAnchorsList()` + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.prototype.getAnchorsList_asU8 = function() { + return /** @type {!Array} */ (jspb.Message.bytesListAsU8( + this.getAnchorsList())); +}; + + +/** + * @param {!(Array|Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.prototype.setAnchorsList = function(value) { + return jspb.Message.setField(this, 1, value || []); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @param {number=} opt_index + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.prototype.addAnchors = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 1, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors.prototype.clearAnchorsList = function() { + return this.setAnchorsList([]); +}; + + +/** + * optional Anchors anchors = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.getAnchors = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.Anchors|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.setAnchors = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.clearAnchors = function() { + return this.setAnchors(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.hasAnchors = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional Proof proof = 2; + * @return {?proto.org.dash.platform.dapi.v0.Proof} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.getProof = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.Proof} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.Proof, 2)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.Proof|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.setProof = function(value) { + return jspb.Message.setOneofWrapperField(this, 2, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.clearProof = function() { + return this.setProof(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.hasProof = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional ResponseMetadata metadata = 3; + * @return {?proto.org.dash.platform.dapi.v0.ResponseMetadata} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.getMetadata = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.ResponseMetadata} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.ResponseMetadata, 3)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.ResponseMetadata|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.setMetadata = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.clearMetadata = function() { + return this.setMetadata(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.prototype.hasMetadata = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional GetShieldedAnchorsResponseV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest; + return proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.toObject = function(includeInstance, msg) { + var f, obj = { + prove: jspb.Message.getBooleanFieldWithDefault(msg, 1, false) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0; + return proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setProve(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getProve(); + if (f) { + writer.writeBool( + 1, + f + ); + } +}; + + +/** + * optional bool prove = 1; + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.prototype.getProve = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 1, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0.prototype.setProve = function(value) { + return jspb.Message.setProto3BooleanField(this, 1, value); +}; + + +/** + * optional GetShieldedPoolStateRequestV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse; + return proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.serializeBinaryToWriter + ); + } +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.oneofGroups_ = [[1,2]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.ResultCase = { + RESULT_NOT_SET: 0, + TOTAL_BALANCE: 1, + PROOF: 2 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.ResultCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.getResultCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.ResultCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.toObject = function(includeInstance, msg) { + var f, obj = { + totalBalance: jspb.Message.getFieldWithDefault(msg, 1, "0"), + proof: (f = msg.getProof()) && proto.org.dash.platform.dapi.v0.Proof.toObject(includeInstance, f), + metadata: (f = msg.getMetadata()) && proto.org.dash.platform.dapi.v0.ResponseMetadata.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0; + return proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setTotalBalance(value); + break; + case 2: + var value = new proto.org.dash.platform.dapi.v0.Proof; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.Proof.deserializeBinaryFromReader); + msg.setProof(value); + break; + case 3: + var value = new proto.org.dash.platform.dapi.v0.ResponseMetadata; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.ResponseMetadata.deserializeBinaryFromReader); + msg.setMetadata(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = /** @type {string} */ (jspb.Message.getField(message, 1)); + if (f != null) { + writer.writeUint64String( + 1, + f + ); + } + f = message.getProof(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.org.dash.platform.dapi.v0.Proof.serializeBinaryToWriter + ); + } + f = message.getMetadata(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.org.dash.platform.dapi.v0.ResponseMetadata.serializeBinaryToWriter + ); + } +}; + + +/** + * optional uint64 total_balance = 1; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.getTotalBalance = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.setTotalBalance = function(value) { + return jspb.Message.setOneofField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.clearTotalBalance = function() { + return jspb.Message.setOneofField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.oneofGroups_[0], undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.hasTotalBalance = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional Proof proof = 2; + * @return {?proto.org.dash.platform.dapi.v0.Proof} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.getProof = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.Proof} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.Proof, 2)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.Proof|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.setProof = function(value) { + return jspb.Message.setOneofWrapperField(this, 2, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.clearProof = function() { + return this.setProof(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.hasProof = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional ResponseMetadata metadata = 3; + * @return {?proto.org.dash.platform.dapi.v0.ResponseMetadata} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.getMetadata = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.ResponseMetadata} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.ResponseMetadata, 3)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.ResponseMetadata|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.setMetadata = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.clearMetadata = function() { + return this.setMetadata(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0.prototype.hasMetadata = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional GetShieldedPoolStateResponseV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest; + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.serializeBinaryToWriter + ); + } +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.toObject = function(includeInstance, msg) { + var f, obj = { + nullifiersList: msg.getNullifiersList_asB64(), + prove: jspb.Message.getBooleanFieldWithDefault(msg, 2, false) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0; + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.addNullifiers(value); + break; + case 2: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setProve(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getNullifiersList_asU8(); + if (f.length > 0) { + writer.writeRepeatedBytes( + 1, + f + ); + } + f = message.getProve(); + if (f) { + writer.writeBool( + 2, + f + ); + } +}; + + +/** + * repeated bytes nullifiers = 1; + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.getNullifiersList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 1)); +}; + + +/** + * repeated bytes nullifiers = 1; + * This is a type-conversion wrapper around `getNullifiersList()` + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.getNullifiersList_asB64 = function() { + return /** @type {!Array} */ (jspb.Message.bytesListAsB64( + this.getNullifiersList())); +}; + + +/** + * repeated bytes nullifiers = 1; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getNullifiersList()` + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.getNullifiersList_asU8 = function() { + return /** @type {!Array} */ (jspb.Message.bytesListAsU8( + this.getNullifiersList())); +}; + + +/** + * @param {!(Array|Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.setNullifiersList = function(value) { + return jspb.Message.setField(this, 1, value || []); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @param {number=} opt_index + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.addNullifiers = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 1, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.clearNullifiersList = function() { + return this.setNullifiersList([]); +}; + + +/** + * optional bool prove = 2; + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.getProve = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 2, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0.prototype.setProve = function(value) { + return jspb.Message.setProto3BooleanField(this, 2, value); +}; + + +/** + * optional GetShieldedNullifiersRequestV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse; + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.serializeBinaryToWriter + ); + } +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.oneofGroups_ = [[1,2]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.ResultCase = { + RESULT_NOT_SET: 0, + NULLIFIER_STATUSES: 1, + PROOF: 2 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.ResultCase} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.getResultCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.ResultCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.toObject = function(includeInstance, msg) { + var f, obj = { + nullifierStatuses: (f = msg.getNullifierStatuses()) && proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.toObject(includeInstance, f), + proof: (f = msg.getProof()) && proto.org.dash.platform.dapi.v0.Proof.toObject(includeInstance, f), + metadata: (f = msg.getMetadata()) && proto.org.dash.platform.dapi.v0.ResponseMetadata.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0; + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.deserializeBinaryFromReader); + msg.setNullifierStatuses(value); + break; + case 2: + var value = new proto.org.dash.platform.dapi.v0.Proof; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.Proof.deserializeBinaryFromReader); + msg.setProof(value); + break; + case 3: + var value = new proto.org.dash.platform.dapi.v0.ResponseMetadata; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.ResponseMetadata.deserializeBinaryFromReader); + msg.setMetadata(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getNullifierStatuses(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.serializeBinaryToWriter + ); + } + f = message.getProof(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.org.dash.platform.dapi.v0.Proof.serializeBinaryToWriter + ); + } + f = message.getMetadata(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.org.dash.platform.dapi.v0.ResponseMetadata.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.toObject = function(includeInstance, msg) { + var f, obj = { + nullifier: msg.getNullifier_asB64(), + isSpent: jspb.Message.getBooleanFieldWithDefault(msg, 2, false) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus; + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setNullifier(value); + break; + case 2: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setIsSpent(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getNullifier_asU8(); + if (f.length > 0) { + writer.writeBytes( + 1, + f + ); + } + f = message.getIsSpent(); + if (f) { + writer.writeBool( + 2, + f + ); + } +}; + + +/** + * optional bytes nullifier = 1; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.prototype.getNullifier = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); +}; + + +/** + * optional bytes nullifier = 1; + * This is a type-conversion wrapper around `getNullifier()` + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.prototype.getNullifier_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getNullifier())); +}; + + +/** + * optional bytes nullifier = 1; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getNullifier()` + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.prototype.getNullifier_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getNullifier())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.prototype.setNullifier = function(value) { + return jspb.Message.setProto3BytesField(this, 1, value); +}; + + +/** + * optional bool is_spent = 2; + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.prototype.getIsSpent = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 2, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.prototype.setIsSpent = function(value) { + return jspb.Message.setProto3BooleanField(this, 2, value); +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.toObject = function(includeInstance, msg) { + var f, obj = { + entriesList: jspb.Message.toObjectList(msg.getEntriesList(), + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.toObject, includeInstance) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses; + return proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.deserializeBinaryFromReader); + msg.addEntries(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getEntriesList(); + if (f.length > 0) { + writer.writeRepeatedMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus.serializeBinaryToWriter + ); + } +}; + + +/** + * repeated NullifierStatus entries = 1; + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.prototype.getEntriesList = function() { + return /** @type{!Array} */ ( + jspb.Message.getRepeatedWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus, 1)); +}; + + +/** + * @param {!Array} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.prototype.setEntriesList = function(value) { + return jspb.Message.setRepeatedWrapperField(this, 1, value); +}; + + +/** + * @param {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus=} opt_value + * @param {number=} opt_index + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.prototype.addEntries = function(opt_value, opt_index) { + return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.prototype.clearEntriesList = function() { + return this.setEntriesList([]); +}; + + +/** + * optional NullifierStatuses nullifier_statuses = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.getNullifierStatuses = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.setNullifierStatuses = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.clearNullifierStatuses = function() { + return this.setNullifierStatuses(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.hasNullifierStatuses = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional Proof proof = 2; + * @return {?proto.org.dash.platform.dapi.v0.Proof} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.getProof = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.Proof} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.Proof, 2)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.Proof|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.setProof = function(value) { + return jspb.Message.setOneofWrapperField(this, 2, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.clearProof = function() { + return this.setProof(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.hasProof = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional ResponseMetadata metadata = 3; + * @return {?proto.org.dash.platform.dapi.v0.ResponseMetadata} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.getMetadata = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.ResponseMetadata} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.ResponseMetadata, 3)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.ResponseMetadata|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.setMetadata = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.clearMetadata = function() { + return this.setMetadata(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.prototype.hasMetadata = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional GetShieldedNullifiersResponseV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} returns this +*/ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + /** * @enum {number} */ diff --git a/packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.d.ts b/packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.d.ts index 99ae8d11aab..72393c9b9aa 100644 --- a/packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.d.ts +++ b/packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.d.ts @@ -481,6 +481,42 @@ type PlatformgetRecentCompactedAddressBalanceChanges = { readonly responseType: typeof platform_pb.GetRecentCompactedAddressBalanceChangesResponse; }; +type PlatformgetShieldedEncryptedNotes = { + readonly methodName: string; + readonly service: typeof Platform; + readonly requestStream: false; + readonly responseStream: false; + readonly requestType: typeof platform_pb.GetShieldedEncryptedNotesRequest; + readonly responseType: typeof platform_pb.GetShieldedEncryptedNotesResponse; +}; + +type PlatformgetShieldedAnchors = { + readonly methodName: string; + readonly service: typeof Platform; + readonly requestStream: false; + readonly responseStream: false; + readonly requestType: typeof platform_pb.GetShieldedAnchorsRequest; + readonly responseType: typeof platform_pb.GetShieldedAnchorsResponse; +}; + +type PlatformgetShieldedPoolState = { + readonly methodName: string; + readonly service: typeof Platform; + readonly requestStream: false; + readonly responseStream: false; + readonly requestType: typeof platform_pb.GetShieldedPoolStateRequest; + readonly responseType: typeof platform_pb.GetShieldedPoolStateResponse; +}; + +type PlatformgetShieldedNullifiers = { + readonly methodName: string; + readonly service: typeof Platform; + readonly requestStream: false; + readonly responseStream: false; + readonly requestType: typeof platform_pb.GetShieldedNullifiersRequest; + readonly responseType: typeof platform_pb.GetShieldedNullifiersResponse; +}; + export class Platform { static readonly serviceName: string; static readonly broadcastStateTransition: PlatformbroadcastStateTransition; @@ -536,6 +572,10 @@ export class Platform { static readonly getAddressesBranchState: PlatformgetAddressesBranchState; static readonly getRecentAddressBalanceChanges: PlatformgetRecentAddressBalanceChanges; static readonly getRecentCompactedAddressBalanceChanges: PlatformgetRecentCompactedAddressBalanceChanges; + static readonly getShieldedEncryptedNotes: PlatformgetShieldedEncryptedNotes; + static readonly getShieldedAnchors: PlatformgetShieldedAnchors; + static readonly getShieldedPoolState: PlatformgetShieldedPoolState; + static readonly getShieldedNullifiers: PlatformgetShieldedNullifiers; } export type ServiceError = { message: string, code: number; metadata: grpc.Metadata } @@ -1047,5 +1087,41 @@ export class PlatformClient { requestMessage: platform_pb.GetRecentCompactedAddressBalanceChangesRequest, callback: (error: ServiceError|null, responseMessage: platform_pb.GetRecentCompactedAddressBalanceChangesResponse|null) => void ): UnaryResponse; + getShieldedEncryptedNotes( + requestMessage: platform_pb.GetShieldedEncryptedNotesRequest, + metadata: grpc.Metadata, + callback: (error: ServiceError|null, responseMessage: platform_pb.GetShieldedEncryptedNotesResponse|null) => void + ): UnaryResponse; + getShieldedEncryptedNotes( + requestMessage: platform_pb.GetShieldedEncryptedNotesRequest, + callback: (error: ServiceError|null, responseMessage: platform_pb.GetShieldedEncryptedNotesResponse|null) => void + ): UnaryResponse; + getShieldedAnchors( + requestMessage: platform_pb.GetShieldedAnchorsRequest, + metadata: grpc.Metadata, + callback: (error: ServiceError|null, responseMessage: platform_pb.GetShieldedAnchorsResponse|null) => void + ): UnaryResponse; + getShieldedAnchors( + requestMessage: platform_pb.GetShieldedAnchorsRequest, + callback: (error: ServiceError|null, responseMessage: platform_pb.GetShieldedAnchorsResponse|null) => void + ): UnaryResponse; + getShieldedPoolState( + requestMessage: platform_pb.GetShieldedPoolStateRequest, + metadata: grpc.Metadata, + callback: (error: ServiceError|null, responseMessage: platform_pb.GetShieldedPoolStateResponse|null) => void + ): UnaryResponse; + getShieldedPoolState( + requestMessage: platform_pb.GetShieldedPoolStateRequest, + callback: (error: ServiceError|null, responseMessage: platform_pb.GetShieldedPoolStateResponse|null) => void + ): UnaryResponse; + getShieldedNullifiers( + requestMessage: platform_pb.GetShieldedNullifiersRequest, + metadata: grpc.Metadata, + callback: (error: ServiceError|null, responseMessage: platform_pb.GetShieldedNullifiersResponse|null) => void + ): UnaryResponse; + getShieldedNullifiers( + requestMessage: platform_pb.GetShieldedNullifiersRequest, + callback: (error: ServiceError|null, responseMessage: platform_pb.GetShieldedNullifiersResponse|null) => void + ): UnaryResponse; } diff --git a/packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.js b/packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.js index 3bb9564e220..6b53127c4d0 100644 --- a/packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.js +++ b/packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.js @@ -487,6 +487,42 @@ Platform.getRecentCompactedAddressBalanceChanges = { responseType: platform_pb.GetRecentCompactedAddressBalanceChangesResponse }; +Platform.getShieldedEncryptedNotes = { + methodName: "getShieldedEncryptedNotes", + service: Platform, + requestStream: false, + responseStream: false, + requestType: platform_pb.GetShieldedEncryptedNotesRequest, + responseType: platform_pb.GetShieldedEncryptedNotesResponse +}; + +Platform.getShieldedAnchors = { + methodName: "getShieldedAnchors", + service: Platform, + requestStream: false, + responseStream: false, + requestType: platform_pb.GetShieldedAnchorsRequest, + responseType: platform_pb.GetShieldedAnchorsResponse +}; + +Platform.getShieldedPoolState = { + methodName: "getShieldedPoolState", + service: Platform, + requestStream: false, + responseStream: false, + requestType: platform_pb.GetShieldedPoolStateRequest, + responseType: platform_pb.GetShieldedPoolStateResponse +}; + +Platform.getShieldedNullifiers = { + methodName: "getShieldedNullifiers", + service: Platform, + requestStream: false, + responseStream: false, + requestType: platform_pb.GetShieldedNullifiersRequest, + responseType: platform_pb.GetShieldedNullifiersResponse +}; + exports.Platform = Platform; function PlatformClient(serviceHost, options) { @@ -2137,5 +2173,129 @@ PlatformClient.prototype.getRecentCompactedAddressBalanceChanges = function getR }; }; +PlatformClient.prototype.getShieldedEncryptedNotes = function getShieldedEncryptedNotes(requestMessage, metadata, callback) { + if (arguments.length === 2) { + callback = arguments[1]; + } + var client = grpc.unary(Platform.getShieldedEncryptedNotes, { + request: requestMessage, + host: this.serviceHost, + metadata: metadata, + transport: this.options.transport, + debug: this.options.debug, + onEnd: function (response) { + if (callback) { + if (response.status !== grpc.Code.OK) { + var err = new Error(response.statusMessage); + err.code = response.status; + err.metadata = response.trailers; + callback(err, null); + } else { + callback(null, response.message); + } + } + } + }); + return { + cancel: function () { + callback = null; + client.close(); + } + }; +}; + +PlatformClient.prototype.getShieldedAnchors = function getShieldedAnchors(requestMessage, metadata, callback) { + if (arguments.length === 2) { + callback = arguments[1]; + } + var client = grpc.unary(Platform.getShieldedAnchors, { + request: requestMessage, + host: this.serviceHost, + metadata: metadata, + transport: this.options.transport, + debug: this.options.debug, + onEnd: function (response) { + if (callback) { + if (response.status !== grpc.Code.OK) { + var err = new Error(response.statusMessage); + err.code = response.status; + err.metadata = response.trailers; + callback(err, null); + } else { + callback(null, response.message); + } + } + } + }); + return { + cancel: function () { + callback = null; + client.close(); + } + }; +}; + +PlatformClient.prototype.getShieldedPoolState = function getShieldedPoolState(requestMessage, metadata, callback) { + if (arguments.length === 2) { + callback = arguments[1]; + } + var client = grpc.unary(Platform.getShieldedPoolState, { + request: requestMessage, + host: this.serviceHost, + metadata: metadata, + transport: this.options.transport, + debug: this.options.debug, + onEnd: function (response) { + if (callback) { + if (response.status !== grpc.Code.OK) { + var err = new Error(response.statusMessage); + err.code = response.status; + err.metadata = response.trailers; + callback(err, null); + } else { + callback(null, response.message); + } + } + } + }); + return { + cancel: function () { + callback = null; + client.close(); + } + }; +}; + +PlatformClient.prototype.getShieldedNullifiers = function getShieldedNullifiers(requestMessage, metadata, callback) { + if (arguments.length === 2) { + callback = arguments[1]; + } + var client = grpc.unary(Platform.getShieldedNullifiers, { + request: requestMessage, + host: this.serviceHost, + metadata: metadata, + transport: this.options.transport, + debug: this.options.debug, + onEnd: function (response) { + if (callback) { + if (response.status !== grpc.Code.OK) { + var err = new Error(response.statusMessage); + err.code = response.status; + err.metadata = response.trailers; + callback(err, null); + } else { + callback(null, response.message); + } + } + } + }); + return { + cancel: function () { + callback = null; + client.close(); + } + }; +}; + exports.PlatformClient = PlatformClient; diff --git a/packages/rs-dapi/src/services/platform_service/mod.rs b/packages/rs-dapi/src/services/platform_service/mod.rs index 5c3f6b8a535..14df3c3a525 100644 --- a/packages/rs-dapi/src/services/platform_service/mod.rs +++ b/packages/rs-dapi/src/services/platform_service/mod.rs @@ -555,4 +555,29 @@ impl Platform for PlatformServiceImpl { dapi_grpc::platform::v0::GetRecentCompactedAddressBalanceChangesRequest, dapi_grpc::platform::v0::GetRecentCompactedAddressBalanceChangesResponse ); + + // Shielded pool methods + drive_method!( + get_shielded_encrypted_notes, + dapi_grpc::platform::v0::GetShieldedEncryptedNotesRequest, + dapi_grpc::platform::v0::GetShieldedEncryptedNotesResponse + ); + + drive_method!( + get_shielded_anchors, + dapi_grpc::platform::v0::GetShieldedAnchorsRequest, + dapi_grpc::platform::v0::GetShieldedAnchorsResponse + ); + + drive_method!( + get_shielded_pool_state, + dapi_grpc::platform::v0::GetShieldedPoolStateRequest, + dapi_grpc::platform::v0::GetShieldedPoolStateResponse + ); + + drive_method!( + get_shielded_nullifiers, + dapi_grpc::platform::v0::GetShieldedNullifiersRequest, + dapi_grpc::platform::v0::GetShieldedNullifiersResponse + ); } diff --git a/packages/rs-dpp/src/shielded/mod.rs b/packages/rs-dpp/src/shielded/mod.rs index 79802ea709e..4b4119c1c50 100644 --- a/packages/rs-dpp/src/shielded/mod.rs +++ b/packages/rs-dpp/src/shielded/mod.rs @@ -1,6 +1,31 @@ use bincode::{Decode, Encode}; #[cfg(feature = "state-transition-serde-conversion")] use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; + +/// Domain separator for Platform sighash computation. +const SIGHASH_DOMAIN: &[u8] = b"DashPlatformSighash"; + +/// Computes the platform sighash from an Orchard bundle commitment and optional +/// transparent field data. +/// +/// The sighash is computed as: +/// `SHA-256(SIGHASH_DOMAIN || bundle_commitment || extra_data)` +/// +/// This binds transparent state transition fields (like `output_address` and `amount` +/// in unshield transitions) to the Orchard signatures, preventing replay attacks +/// where an attacker substitutes transparent fields while reusing a valid Orchard bundle. +/// +/// The same computation must be used on both the signing (client) and verification +/// (platform) sides. For transitions without transparent fields (shield and +/// shielded_transfer), `extra_data` is empty. +pub fn compute_platform_sighash(bundle_commitment: &[u8; 32], extra_data: &[u8]) -> [u8; 32] { + let mut hasher = Sha256::new(); + hasher.update(SIGHASH_DOMAIN); + hasher.update(bundle_commitment); + hasher.update(extra_data); + hasher.finalize().into() +} /// Serde helper for `[u8; 64]` fields (serde only supports arrays up to 32). #[cfg(feature = "state-transition-serde-conversion")] diff --git a/packages/rs-dpp/src/state_transition/proof_result.rs b/packages/rs-dpp/src/state_transition/proof_result.rs index 9500e824e7b..d84d7802493 100644 --- a/packages/rs-dpp/src/state_transition/proof_result.rs +++ b/packages/rs-dpp/src/state_transition/proof_result.rs @@ -55,4 +55,5 @@ pub enum StateTransitionProofResult { PartialIdentity, BTreeMap>, ), + VerifiedShieldedPoolState(Option), } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/methods/mod.rs new file mode 100644 index 00000000000..6297af5de23 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/methods/mod.rs @@ -0,0 +1,60 @@ +mod v0; + +pub use v0::*; + +#[cfg(feature = "state-transition-signing")] +use crate::prelude::AssetLockProof; +#[cfg(feature = "state-transition-signing")] +use crate::shielded::SerializedAction; +use crate::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; +#[cfg(feature = "state-transition-signing")] +use crate::{ + prelude::UserFeeIncrease, + state_transition::{ + shield_from_asset_lock_transition::v0::ShieldFromAssetLockTransitionV0, StateTransition, + }, + ProtocolError, +}; +#[cfg(feature = "state-transition-signing")] +use platform_version::version::PlatformVersion; + +impl ShieldFromAssetLockTransitionMethodsV0 for ShieldFromAssetLockTransition { + #[cfg(feature = "state-transition-signing")] + fn try_from_asset_lock_with_bundle( + asset_lock_proof: AssetLockProof, + asset_lock_proof_private_key: &[u8], + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + user_fee_increase: UserFeeIncrease, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .dpp + .state_transition_serialization_versions + .shield_from_asset_lock_state_transition + .default_current_version + { + 0 => ShieldFromAssetLockTransitionV0::try_from_asset_lock_with_bundle( + asset_lock_proof, + asset_lock_proof_private_key, + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + user_fee_increase, + platform_version, + ), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "ShieldFromAssetLockTransition::try_from_asset_lock_with_bundle".to_string(), + known_versions: vec![0], + received: version, + }), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/methods/v0/mod.rs new file mode 100644 index 00000000000..7d02ce85d2a --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/methods/v0/mod.rs @@ -0,0 +1,35 @@ +#[cfg(feature = "state-transition-signing")] +use crate::prelude::AssetLockProof; +#[cfg(feature = "state-transition-signing")] +use crate::shielded::SerializedAction; +use crate::state_transition::StateTransitionType; +#[cfg(feature = "state-transition-signing")] +use crate::{ + prelude::UserFeeIncrease, + state_transition::StateTransition, + ProtocolError, +}; +#[cfg(feature = "state-transition-signing")] +use platform_version::version::PlatformVersion; + +pub trait ShieldFromAssetLockTransitionMethodsV0 { + #[cfg(feature = "state-transition-signing")] + #[allow(clippy::too_many_arguments)] + fn try_from_asset_lock_with_bundle( + asset_lock_proof: AssetLockProof, + asset_lock_proof_private_key: &[u8], + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + user_fee_increase: UserFeeIncrease, + platform_version: &PlatformVersion, + ) -> Result; + + /// Get State Transition Type + fn get_type() -> StateTransitionType { + StateTransitionType::ShieldFromAssetLock + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/mod.rs index 02a37644b0c..1e87529f11a 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/mod.rs @@ -1,3 +1,4 @@ +pub mod methods; mod proved; mod state_transition_estimated_fee_validation; mod state_transition_like; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs index 5aab3cac355..8cf2999274e 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs @@ -3,6 +3,7 @@ mod state_transition_like; mod state_transition_validation; mod types; mod version; +mod v0_methods; use crate::identity::state_transition::asset_lock_proof::AssetLockProof; use crate::prelude::UserFeeIncrease; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/v0_methods.rs new file mode 100644 index 00000000000..793206ce0af --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/v0_methods.rs @@ -0,0 +1,57 @@ +#[cfg(feature = "state-transition-signing")] +use crate::prelude::AssetLockProof; +#[cfg(feature = "state-transition-signing")] +use crate::serialization::Signable; +#[cfg(feature = "state-transition-signing")] +use crate::shielded::SerializedAction; +use crate::state_transition::shield_from_asset_lock_transition::methods::ShieldFromAssetLockTransitionMethodsV0; +use crate::state_transition::shield_from_asset_lock_transition::v0::ShieldFromAssetLockTransitionV0; +#[cfg(feature = "state-transition-signing")] +use crate::{ + prelude::UserFeeIncrease, + state_transition::StateTransition, + ProtocolError, +}; +#[cfg(feature = "state-transition-signing")] +use dashcore::signer; +#[cfg(feature = "state-transition-signing")] +use platform_version::version::PlatformVersion; + +impl ShieldFromAssetLockTransitionMethodsV0 for ShieldFromAssetLockTransitionV0 { + #[cfg(feature = "state-transition-signing")] + fn try_from_asset_lock_with_bundle( + asset_lock_proof: AssetLockProof, + asset_lock_proof_private_key: &[u8], + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + user_fee_increase: UserFeeIncrease, + _platform_version: &PlatformVersion, + ) -> Result { + // Create the unsigned transition + let mut transition = ShieldFromAssetLockTransitionV0 { + asset_lock_proof, + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + user_fee_increase, + signature: Default::default(), + }; + + // Compute signable bytes (signature field is excluded from sig hash) + let state_transition: StateTransition = transition.clone().into(); + let signable_bytes = state_transition.signable_bytes()?; + + // Sign with the asset lock private key (ECDSA) + let signature = signer::sign(&signable_bytes, asset_lock_proof_private_key)?; + transition.signature = signature.to_vec().into(); + + Ok(transition.into()) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/methods/mod.rs new file mode 100644 index 00000000000..fa612ecbeb2 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/methods/mod.rs @@ -0,0 +1,66 @@ +mod v0; + +#[cfg(feature = "state-transition-signing")] +use std::collections::BTreeMap; +pub use v0::*; + +#[cfg(feature = "state-transition-signing")] +use crate::address_funds::{AddressFundsFeeStrategy, PlatformAddress}; +#[cfg(feature = "state-transition-signing")] +use crate::fee::Credits; +#[cfg(feature = "state-transition-signing")] +use crate::identity::signer::Signer; +#[cfg(feature = "state-transition-signing")] +use crate::shielded::SerializedAction; +use crate::state_transition::shield_transition::ShieldTransition; +#[cfg(feature = "state-transition-signing")] +use crate::{ + prelude::{AddressNonce, UserFeeIncrease}, + state_transition::{shield_transition::v0::ShieldTransitionV0, StateTransition}, + ProtocolError, +}; +#[cfg(feature = "state-transition-signing")] +use platform_version::version::PlatformVersion; + +impl ShieldTransitionMethodsV0 for ShieldTransition { + #[cfg(feature = "state-transition-signing")] + fn try_from_bundle_with_signer>( + inputs: BTreeMap, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + fee_strategy: AddressFundsFeeStrategy, + signer: &S, + user_fee_increase: UserFeeIncrease, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .dpp + .state_transition_serialization_versions + .shield_state_transition + .default_current_version + { + 0 => ShieldTransitionV0::try_from_bundle_with_signer( + inputs, + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + fee_strategy, + signer, + user_fee_increase, + platform_version, + ), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "ShieldTransition::try_from_bundle_with_signer".to_string(), + known_versions: vec![0], + received: version, + }), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/methods/v0/mod.rs new file mode 100644 index 00000000000..8ddca9d82a3 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/methods/v0/mod.rs @@ -0,0 +1,42 @@ +#[cfg(feature = "state-transition-signing")] +use std::collections::BTreeMap; + +#[cfg(feature = "state-transition-signing")] +use crate::address_funds::{AddressFundsFeeStrategy, PlatformAddress}; +#[cfg(feature = "state-transition-signing")] +use crate::fee::Credits; +#[cfg(feature = "state-transition-signing")] +use crate::identity::signer::Signer; +#[cfg(feature = "state-transition-signing")] +use crate::shielded::SerializedAction; +use crate::state_transition::StateTransitionType; +#[cfg(feature = "state-transition-signing")] +use crate::{ + prelude::{AddressNonce, UserFeeIncrease}, + state_transition::StateTransition, + ProtocolError, +}; +#[cfg(feature = "state-transition-signing")] +use platform_version::version::PlatformVersion; + +pub trait ShieldTransitionMethodsV0 { + #[cfg(feature = "state-transition-signing")] + fn try_from_bundle_with_signer>( + inputs: BTreeMap, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + fee_strategy: AddressFundsFeeStrategy, + signer: &S, + user_fee_increase: UserFeeIncrease, + platform_version: &PlatformVersion, + ) -> Result; + + /// Get State Transition Type + fn get_type() -> StateTransitionType { + StateTransitionType::Shield + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/mod.rs index 4e4d20d66e5..1aaccded5ea 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/mod.rs @@ -1,3 +1,4 @@ +pub mod methods; mod state_transition_estimated_fee_validation; mod state_transition_like; mod state_transition_validation; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs index 78237843aa4..1a8df6e526e 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs @@ -1,6 +1,8 @@ mod state_transition_like; mod state_transition_validation; mod types; +#[cfg(feature = "state-transition-signing")] +mod v0_methods; mod version; use std::collections::BTreeMap; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/v0_methods.rs new file mode 100644 index 00000000000..953d5002a26 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/v0_methods.rs @@ -0,0 +1,66 @@ +#[cfg(feature = "state-transition-signing")] +use std::collections::BTreeMap; + +#[cfg(feature = "state-transition-signing")] +use crate::address_funds::{AddressFundsFeeStrategy, AddressWitness, PlatformAddress}; +#[cfg(feature = "state-transition-signing")] +use crate::fee::Credits; +#[cfg(feature = "state-transition-signing")] +use crate::identity::signer::Signer; +#[cfg(feature = "state-transition-signing")] +use crate::serialization::Signable; +#[cfg(feature = "state-transition-signing")] +use crate::shielded::SerializedAction; +use crate::state_transition::shield_transition::methods::ShieldTransitionMethodsV0; +use crate::state_transition::shield_transition::v0::ShieldTransitionV0; +#[cfg(feature = "state-transition-signing")] +use crate::{ + prelude::{AddressNonce, UserFeeIncrease}, + state_transition::StateTransition, + ProtocolError, +}; +#[cfg(feature = "state-transition-signing")] +use platform_version::version::PlatformVersion; + +impl ShieldTransitionMethodsV0 for ShieldTransitionV0 { + #[cfg(feature = "state-transition-signing")] + fn try_from_bundle_with_signer>( + inputs: BTreeMap, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + fee_strategy: AddressFundsFeeStrategy, + signer: &S, + user_fee_increase: UserFeeIncrease, + _platform_version: &PlatformVersion, + ) -> Result { + // Create the unsigned transition (empty witnesses) + let mut shield_transition = ShieldTransitionV0 { + inputs: inputs.clone(), + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + fee_strategy, + user_fee_increase, + input_witnesses: Vec::new(), + }; + + // Compute signable bytes (excludes input_witnesses which are marked exclude_from_sig_hash) + let state_transition: StateTransition = shield_transition.clone().into(); + let signable_bytes = state_transition.signable_bytes()?; + + // Sign each input address + shield_transition.input_witnesses = inputs + .keys() + .map(|address| signer.sign_create_witness(address, &signable_bytes)) + .collect::, ProtocolError>>()?; + + Ok(shield_transition.into()) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/mod.rs new file mode 100644 index 00000000000..7b48e98ba1e --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/mod.rs @@ -0,0 +1,50 @@ +mod v0; + +pub use v0::*; + +use crate::shielded::SerializedAction; +use crate::state_transition::shielded_transfer_transition::ShieldedTransferTransition; +use crate::{ + prelude::UserFeeIncrease, + state_transition::{ + shielded_transfer_transition::v0::ShieldedTransferTransitionV0, StateTransition, + }, + ProtocolError, +}; +use platform_version::version::PlatformVersion; + +impl ShieldedTransferTransitionMethodsV0 for ShieldedTransferTransition { + fn try_from_bundle( + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + user_fee_increase: UserFeeIncrease, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .dpp + .state_transition_serialization_versions + .shielded_transfer_state_transition + .default_current_version + { + 0 => ShieldedTransferTransitionV0::try_from_bundle( + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + user_fee_increase, + platform_version, + ), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "ShieldedTransferTransition::try_from_bundle".to_string(), + known_versions: vec![0], + received: version, + }), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/v0/mod.rs new file mode 100644 index 00000000000..439fe8ba746 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/v0/mod.rs @@ -0,0 +1,26 @@ +use crate::shielded::SerializedAction; +use crate::state_transition::StateTransitionType; +use crate::{ + prelude::UserFeeIncrease, + state_transition::StateTransition, + ProtocolError, +}; +use platform_version::version::PlatformVersion; + +pub trait ShieldedTransferTransitionMethodsV0 { + fn try_from_bundle( + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + user_fee_increase: UserFeeIncrease, + platform_version: &PlatformVersion, + ) -> Result; + + /// Get State Transition Type + fn get_type() -> StateTransitionType { + StateTransitionType::ShieldedTransfer + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/mod.rs index 1d9b49c383e..9026cbd655d 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/mod.rs @@ -1,3 +1,4 @@ +pub mod methods; mod state_transition_estimated_fee_validation; mod state_transition_like; mod state_transition_validation; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs index d8deefa0bea..4d92237f8ed 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs @@ -1,6 +1,7 @@ mod state_transition_like; mod state_transition_validation; mod types; +mod v0_methods; mod version; use crate::prelude::UserFeeIncrease; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/v0_methods.rs new file mode 100644 index 00000000000..e75a32b79d1 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/v0_methods.rs @@ -0,0 +1,33 @@ +use crate::shielded::SerializedAction; +use crate::state_transition::shielded_transfer_transition::methods::ShieldedTransferTransitionMethodsV0; +use crate::state_transition::shielded_transfer_transition::v0::ShieldedTransferTransitionV0; +use crate::{ + prelude::UserFeeIncrease, + state_transition::StateTransition, + ProtocolError, +}; +use platform_version::version::PlatformVersion; + +impl ShieldedTransferTransitionMethodsV0 for ShieldedTransferTransitionV0 { + fn try_from_bundle( + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + user_fee_increase: UserFeeIncrease, + _platform_version: &PlatformVersion, + ) -> Result { + let transition = ShieldedTransferTransitionV0 { + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + user_fee_increase, + }; + Ok(transition.into()) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/mod.rs new file mode 100644 index 00000000000..50215bfbf45 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/mod.rs @@ -0,0 +1,60 @@ +mod v0; + +pub use v0::*; + +use crate::identity::core_script::CoreScript; +use crate::shielded::SerializedAction; +use crate::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; +use crate::withdrawal::Pooling; +use crate::{ + prelude::UserFeeIncrease, + state_transition::{ + shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0, StateTransition, + }, + ProtocolError, +}; +use platform_version::version::PlatformVersion; + +impl ShieldedWithdrawalTransitionMethodsV0 for ShieldedWithdrawalTransition { + fn try_from_bundle( + amount: u64, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + core_fee_per_byte: u32, + pooling: Pooling, + output_script: CoreScript, + user_fee_increase: UserFeeIncrease, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .dpp + .state_transition_serialization_versions + .shielded_withdrawal_state_transition + .default_current_version + { + 0 => ShieldedWithdrawalTransitionV0::try_from_bundle( + amount, + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + core_fee_per_byte, + pooling, + output_script, + user_fee_increase, + platform_version, + ), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "ShieldedWithdrawalTransition::try_from_bundle".to_string(), + known_versions: vec![0], + received: version, + }), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/v0/mod.rs new file mode 100644 index 00000000000..bd47247fa33 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/v0/mod.rs @@ -0,0 +1,33 @@ +use crate::identity::core_script::CoreScript; +use crate::shielded::SerializedAction; +use crate::state_transition::StateTransitionType; +use crate::withdrawal::Pooling; +use crate::{ + prelude::UserFeeIncrease, + state_transition::StateTransition, + ProtocolError, +}; +use platform_version::version::PlatformVersion; + +pub trait ShieldedWithdrawalTransitionMethodsV0 { + #[allow(clippy::too_many_arguments)] + fn try_from_bundle( + amount: u64, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + core_fee_per_byte: u32, + pooling: Pooling, + output_script: CoreScript, + user_fee_increase: UserFeeIncrease, + platform_version: &PlatformVersion, + ) -> Result; + + /// Get State Transition Type + fn get_type() -> StateTransitionType { + StateTransitionType::ShieldedWithdrawal + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/mod.rs index 89dfa8fab98..089f5cb389d 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/mod.rs @@ -1,3 +1,4 @@ +pub mod methods; mod state_transition_estimated_fee_validation; mod state_transition_like; mod state_transition_validation; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs index 31502f0785a..beb6225ee1e 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs @@ -1,6 +1,7 @@ mod state_transition_like; mod state_transition_validation; mod types; +mod v0_methods; mod version; use crate::identity::core_script::CoreScript; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/v0_methods.rs new file mode 100644 index 00000000000..b0871cb1154 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/v0_methods.rs @@ -0,0 +1,43 @@ +use crate::identity::core_script::CoreScript; +use crate::shielded::SerializedAction; +use crate::state_transition::shielded_withdrawal_transition::methods::ShieldedWithdrawalTransitionMethodsV0; +use crate::state_transition::shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0; +use crate::withdrawal::Pooling; +use crate::{ + prelude::UserFeeIncrease, + state_transition::StateTransition, + ProtocolError, +}; +use platform_version::version::PlatformVersion; + +impl ShieldedWithdrawalTransitionMethodsV0 for ShieldedWithdrawalTransitionV0 { + fn try_from_bundle( + amount: u64, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + core_fee_per_byte: u32, + pooling: Pooling, + output_script: CoreScript, + user_fee_increase: UserFeeIncrease, + _platform_version: &PlatformVersion, + ) -> Result { + let transition = ShieldedWithdrawalTransitionV0 { + amount, + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + core_fee_per_byte, + pooling, + output_script, + user_fee_increase, + }; + Ok(transition.into()) + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/mod.rs new file mode 100644 index 00000000000..5182b08cf91 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/mod.rs @@ -0,0 +1,55 @@ +mod v0; + +pub use v0::*; + +use crate::address_funds::PlatformAddress; +use crate::shielded::SerializedAction; +use crate::state_transition::unshield_transition::UnshieldTransition; +use crate::{ + prelude::UserFeeIncrease, + state_transition::{ + unshield_transition::v0::UnshieldTransitionV0, StateTransition, + }, + ProtocolError, +}; +use platform_version::version::PlatformVersion; + +impl UnshieldTransitionMethodsV0 for UnshieldTransition { + fn try_from_bundle( + output_address: PlatformAddress, + amount: u64, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + user_fee_increase: UserFeeIncrease, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .dpp + .state_transition_serialization_versions + .unshield_state_transition + .default_current_version + { + 0 => UnshieldTransitionV0::try_from_bundle( + output_address, + amount, + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + user_fee_increase, + platform_version, + ), + version => Err(ProtocolError::UnknownVersionMismatch { + method: "UnshieldTransition::try_from_bundle".to_string(), + known_versions: vec![0], + received: version, + }), + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/v0/mod.rs new file mode 100644 index 00000000000..5639a46fe0c --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/v0/mod.rs @@ -0,0 +1,29 @@ +use crate::address_funds::PlatformAddress; +use crate::shielded::SerializedAction; +use crate::state_transition::StateTransitionType; +use crate::{ + prelude::UserFeeIncrease, + state_transition::StateTransition, + ProtocolError, +}; +use platform_version::version::PlatformVersion; + +pub trait UnshieldTransitionMethodsV0 { + fn try_from_bundle( + output_address: PlatformAddress, + amount: u64, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + user_fee_increase: UserFeeIncrease, + platform_version: &PlatformVersion, + ) -> Result; + + /// Get State Transition Type + fn get_type() -> StateTransitionType { + StateTransitionType::Unshield + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/mod.rs index d584db46972..668f007e757 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/mod.rs @@ -1,3 +1,4 @@ +pub mod methods; mod state_transition_estimated_fee_validation; mod state_transition_like; mod state_transition_validation; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs index 0dad877d726..99710b08c7c 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs @@ -1,6 +1,7 @@ mod state_transition_like; mod state_transition_validation; mod types; +mod v0_methods; mod version; use crate::address_funds::PlatformAddress; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/v0_methods.rs new file mode 100644 index 00000000000..cbdb15af589 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/v0_methods.rs @@ -0,0 +1,38 @@ +use crate::address_funds::PlatformAddress; +use crate::shielded::SerializedAction; +use crate::state_transition::unshield_transition::methods::UnshieldTransitionMethodsV0; +use crate::state_transition::unshield_transition::v0::UnshieldTransitionV0; +use crate::{ + prelude::UserFeeIncrease, + state_transition::StateTransition, + ProtocolError, +}; +use platform_version::version::PlatformVersion; + +impl UnshieldTransitionMethodsV0 for UnshieldTransitionV0 { + fn try_from_bundle( + output_address: PlatformAddress, + amount: u64, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + user_fee_increase: UserFeeIncrease, + _platform_version: &PlatformVersion, + ) -> Result { + let transition = UnshieldTransitionV0 { + output_address, + amount, + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + user_fee_increase, + }; + Ok(transition.into()) + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/mod.rs index 3745057e8db..a1b47eef5ef 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/mod.rs @@ -1,5 +1,8 @@ mod transform_into_action; +#[cfg(test)] +mod tests; + use dpp::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; use crate::error::execution::ExecutionError; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs new file mode 100644 index 00000000000..2853ecb52f8 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs @@ -0,0 +1,794 @@ +#[cfg(test)] +mod tests { + use crate::config::{PlatformConfig, PlatformTestConfig}; + use crate::execution::validation::state_transition::state_transitions::shielded_common::compute_platform_sighash; + use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; + use crate::test::helpers::setup::TestPlatformBuilder; + use assert_matches::assert_matches; + use dpp::block::block_info::BlockInfo; + use dpp::consensus::basic::BasicError; + use dpp::consensus::signature::SignatureError; + use dpp::consensus::state::state_error::StateError; + use dpp::consensus::ConsensusError; + use dpp::dash_to_credits; + use dpp::dashcore::{Network, PrivateKey}; + use dpp::identity::KeyType::ECDSA_SECP256K1; + use dpp::platform_value::BinaryData; + use dpp::serialization::{PlatformSerializable, Signable}; + use dpp::shielded::SerializedAction; + use dpp::state_transition::shield_from_asset_lock_transition::v0::ShieldFromAssetLockTransitionV0; + use dpp::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; + use dpp::state_transition::StateTransition; + use dpp::tests::fixtures::instant_asset_lock_proof_fixture; + use grovedb_commitment_tree::{ + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + Flags as OrchardFlags, FullViewingKey, NoteValue, ProvingKey, Scope, SpendingKey, + }; + use platform_version::version::PlatformVersion; + use rand::prelude::StdRng; + use rand::rngs::OsRng; + use rand::SeedableRng; + use std::sync::OnceLock; + + // ========================================== + // Helper Functions + // ========================================== + + /// Create a `SerializedAction` with syntactically valid sizes but meaningless crypto data. + /// Passes structure validation (correct field sizes) but will fail ZK proof verification. + fn create_dummy_serialized_action() -> SerializedAction { + SerializedAction { + nullifier: [1u8; 32], + rk: [2u8; 32], + cmx: [3u8; 32], + encrypted_note: vec![4u8; 692], // epk(32) + enc(580) + out(80) + cv_net: [5u8; 32], + spend_auth_sig: [6u8; 64], + } + } + + /// Creates an asset lock proof and returns it with the private key bytes for ECDSA signing. + fn create_asset_lock_proof_with_key( + rng: &mut StdRng, + ) -> ( + dpp::identity::state_transition::asset_lock_proof::AssetLockProof, + Vec, + ) { + let platform_version = PlatformVersion::latest(); + let (_, pk) = ECDSA_SECP256K1 + .random_public_and_private_key_data(rng, platform_version) + .unwrap(); + + let asset_lock_proof = instant_asset_lock_proof_fixture( + Some(PrivateKey::from_byte_array(&pk, Network::Testnet).unwrap()), + None, + ); + + (asset_lock_proof, pk.to_vec()) + } + + /// Build a ShieldFromAssetLock StateTransition with the given fields and ECDSA signature. + /// The `signature` field is computed over the signable bytes using `dashcore::signer::sign`. + fn create_signed_shield_from_asset_lock_transition( + asset_lock_proof: dpp::identity::state_transition::asset_lock_proof::AssetLockProof, + asset_lock_private_key: &[u8], + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + user_fee_increase: u16, + ) -> StateTransition { + // Create unsigned transition to compute signable bytes + let unsigned = ShieldFromAssetLockTransitionV0 { + asset_lock_proof: asset_lock_proof.clone(), + actions: actions.clone(), + flags, + value_balance, + anchor, + proof: proof.clone(), + binding_signature, + user_fee_increase, + signature: Default::default(), + }; + + let state_transition: StateTransition = unsigned.into(); + let signable_bytes = state_transition + .signable_bytes() + .expect("should compute signable bytes"); + + // Sign with the asset lock private key (ECDSA) + let signature = + dpp::dashcore::signer::sign(&signable_bytes, asset_lock_private_key).unwrap(); + + StateTransition::ShieldFromAssetLock(ShieldFromAssetLockTransition::V0( + ShieldFromAssetLockTransitionV0 { + asset_lock_proof, + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + user_fee_increase, + signature: BinaryData::new(signature.to_vec()), + }, + )) + } + + /// Build a ShieldFromAssetLock StateTransition with dummy (invalid) signature. + /// Used for structure validation tests where the error is caught before signature check. + fn create_unsigned_shield_from_asset_lock_transition( + asset_lock_proof: dpp::identity::state_transition::asset_lock_proof::AssetLockProof, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + ) -> StateTransition { + StateTransition::ShieldFromAssetLock(ShieldFromAssetLockTransition::V0( + ShieldFromAssetLockTransitionV0 { + asset_lock_proof, + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + user_fee_increase: 0, + signature: BinaryData::new(vec![0u8; 65]), // dummy signature + }, + )) + } + + /// Standard platform setup for tests with instant lock signature verification disabled. + fn setup_platform( + ) -> crate::test::helpers::setup::TempPlatform { + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + TestPlatformBuilder::new() + .with_config(platform_config) + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state() + } + + /// Execute a state transition through the full processing pipeline and return the result. + fn process_transition( + platform: &crate::test::helpers::setup::TempPlatform, + transition: StateTransition, + platform_version: &PlatformVersion, + ) -> crate::platform_types::state_transitions_processing_result::StateTransitionsProcessingResult + { + let transition_bytes = transition + .serialize_to_bytes() + .expect("should serialize transition"); + let platform_state = platform.state.load(); + let transaction = platform.drive.grove.start_transaction(); + + platform + .platform + .process_raw_state_transitions( + &vec![transition_bytes], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition") + } + + // ========================================== + // Orchard Proving Key (cached, ~30s to build) + // ========================================== + + static TEST_PROVING_KEY: OnceLock = OnceLock::new(); + fn get_proving_key() -> &'static ProvingKey { + TEST_PROVING_KEY.get_or_init(ProvingKey::build) + } + + /// Extract serialized fields from an authorized Orchard bundle into the + /// platform-compatible format: (actions, flags, value_balance, anchor, proof, binding_sig). + fn serialize_authorized_bundle( + bundle: &Bundle, + ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { + let actions: Vec = bundle + .actions() + .iter() + .map(|action| { + let enc = action.encrypted_note(); + let mut encrypted_note = Vec::with_capacity(692); + encrypted_note.extend_from_slice(&enc.epk_bytes); + encrypted_note.extend_from_slice(&enc.enc_ciphertext); + encrypted_note.extend_from_slice(&enc.out_ciphertext); + + SerializedAction { + nullifier: action.nullifier().to_bytes(), + rk: <[u8; 32]>::from(action.rk()), + cmx: action.cmx().to_bytes(), + encrypted_note, + cv_net: action.cv_net().to_bytes(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()), + } + }) + .collect(); + + let flags = bundle.flags().to_byte(); + let value_balance = *bundle.value_balance(); + let anchor = bundle.anchor().to_bytes(); + let proof = bundle.authorization().proof().as_ref().to_vec(); + let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); + + (actions, flags, value_balance, anchor, proof, binding_sig) + } + + // ========================================== + // STRUCTURE VALIDATION TESTS (BasicError) + // ========================================== + + mod structure_validation { + use super::*; + + #[test] + fn test_empty_actions_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let mut rng = StdRng::seed_from_u64(567); + let (asset_lock_proof, _pk) = create_asset_lock_proof_with_key(&mut rng); + + let transition = create_unsigned_shield_from_asset_lock_transition( + asset_lock_proof, + vec![], // Empty actions -- invalid + 0x03, + -1000, + [0u8; 32], + vec![0u8; 100], + [0u8; 64], + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::ShieldedNoActionsError(_)) + )] + ); + } + + #[test] + fn test_positive_value_balance_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let mut rng = StdRng::seed_from_u64(568); + let (asset_lock_proof, _pk) = create_asset_lock_proof_with_key(&mut rng); + + let transition = create_unsigned_shield_from_asset_lock_transition( + asset_lock_proof, + vec![create_dummy_serialized_action()], + 0x03, + 1000, // Positive -- invalid for shielding (must be negative) + [0u8; 32], + vec![0u8; 100], + [0u8; 64], + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::ShieldedInvalidValueBalanceError(_)) + )] + ); + } + + #[test] + fn test_zero_value_balance_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let mut rng = StdRng::seed_from_u64(569); + let (asset_lock_proof, _pk) = create_asset_lock_proof_with_key(&mut rng); + + let transition = create_unsigned_shield_from_asset_lock_transition( + asset_lock_proof, + vec![create_dummy_serialized_action()], + 0x03, + 0, // Zero -- invalid for shielding (must be negative) + [0u8; 32], + vec![0u8; 100], + [0u8; 64], + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::ShieldedInvalidValueBalanceError(_)) + )] + ); + } + + #[test] + fn test_empty_proof_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let mut rng = StdRng::seed_from_u64(570); + let (asset_lock_proof, _pk) = create_asset_lock_proof_with_key(&mut rng); + + let transition = create_unsigned_shield_from_asset_lock_transition( + asset_lock_proof, + vec![create_dummy_serialized_action()], + 0x03, + -1000, + [0u8; 32], + vec![], // Empty proof -- invalid + [0u8; 64], + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::ShieldedEmptyProofError(_)) + )] + ); + } + } + + // ========================================== + // ASSET LOCK VALIDATION TESTS + // ========================================== + + mod asset_lock_validation { + use super::*; + + /// Happy path for asset lock validation: valid instant asset lock with properly signed + /// ECDSA signature, but dummy ZK proof data. The transition should pass structure + /// validation, asset lock validation, and ECDSA signature verification, then fail + /// at ZK proof verification (producing a PaidConsensusError with penalty action). + #[test] + fn test_valid_instant_asset_lock_creates_action() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let mut rng = StdRng::seed_from_u64(567); + let (asset_lock_proof, asset_lock_pk) = create_asset_lock_proof_with_key(&mut rng); + + // Use a shield amount much smaller than the asset lock value (1 Dash = 100_000_000 duffs) + let shield_amount = 5000u64; + let value_balance = -(shield_amount as i64); + + let transition = create_signed_shield_from_asset_lock_transition( + asset_lock_proof, + &asset_lock_pk, + vec![create_dummy_serialized_action()], + 0x03, // spends_enabled | outputs_enabled + value_balance, + [0u8; 32], // dummy anchor + vec![0u8; 100], // dummy proof bytes + [0u8; 64], // dummy binding signature + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // Asset lock validation + ECDSA sig passed, but ZK proof failed. + // This produces a PaidConsensusError (the asset lock is partially consumed as penalty). + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::PaidConsensusError { + error: ConsensusError::StateError(StateError::InvalidShieldedProofError(_)), + .. + }] + ); + } + } + + // ========================================== + // SIGNATURE VALIDATION TESTS (SignatureError) + // ========================================== + + mod signature_validation { + use super::*; + + #[test] + fn test_wrong_ecdsa_signature_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let mut rng = StdRng::seed_from_u64(567); + let (asset_lock_proof, _asset_lock_pk) = create_asset_lock_proof_with_key(&mut rng); + + // Build transition with a completely zeroed (invalid) signature + let transition = StateTransition::ShieldFromAssetLock( + ShieldFromAssetLockTransition::V0(ShieldFromAssetLockTransitionV0 { + asset_lock_proof, + actions: vec![create_dummy_serialized_action()], + flags: 0x03, + value_balance: -5000, + anchor: [0u8; 32], + proof: vec![0u8; 100], + binding_signature: [0u8; 64], + user_fee_increase: 0, + signature: BinaryData::new(vec![0u8; 65]), // zeroed invalid signature + }), + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // ECDSA verification fails because the signature does not match the public key + // derived from the asset lock output. This is caught after asset lock validation + // but before ZK proof verification. + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::SignatureError(SignatureError::BasicECDSAError(_)) + )] + ); + } + + #[test] + fn test_signature_from_different_key_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let mut rng = StdRng::seed_from_u64(567); + let (asset_lock_proof, _correct_pk) = create_asset_lock_proof_with_key(&mut rng); + + // Generate a different key pair to sign with (wrong key) + let wrong_private_key = PrivateKey::from_byte_array( + &[42u8; 32], // arbitrary seed that is different + Network::Testnet, + ) + .unwrap(); + + let transition = create_signed_shield_from_asset_lock_transition( + asset_lock_proof, + &wrong_private_key.inner.secret_bytes(), // Wrong key + vec![create_dummy_serialized_action()], + 0x03, + -5000, + [0u8; 32], + vec![0u8; 100], + [0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::SignatureError(SignatureError::BasicECDSAError(_)) + )] + ); + } + } + + // ========================================== + // ZK PROOF VERIFICATION TESTS + // ========================================== + + mod proof_verification { + use super::*; + + /// End-to-end test: valid instant asset lock + valid Orchard bundle = success. + /// + /// This test builds a real Orchard bundle with ProvingKey (~30s on first run, + /// cached via OnceLock for subsequent tests). + #[test] + fn test_valid_proof_succeeds() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let mut rng = StdRng::seed_from_u64(567); + let (asset_lock_proof, asset_lock_pk) = create_asset_lock_proof_with_key(&mut rng); + + // Build a valid Orchard bundle (shield = outputs only) + let mut orchard_rng = OsRng; + let pk = get_proving_key(); + + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + + let anchor = Anchor::empty_tree(); + let mut builder = Builder::new( + BundleType::Transactional { + flags: OrchardFlags::SPENDS_DISABLED, + bundle_required: false, + }, + anchor, + ); + + let shield_value = 5000u64; + builder + .add_output( + None, + recipient, + NoteValue::from_raw(shield_value), + [0u8; 512], + ) + .unwrap(); + + let (unauthorized, _) = builder.build::(&mut orchard_rng).unwrap().unwrap(); + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + // No extra_sighash_data for shield_from_asset_lock (empty, like shield) + let sighash = compute_platform_sighash(&bundle_commitment, &[]); + let proven = unauthorized.create_proof(pk, &mut orchard_rng).unwrap(); + let bundle = proven.apply_signatures(orchard_rng, sighash, &[]).unwrap(); + + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + + // value_balance should be negative for shield (money going into pool) + assert!(value_balance < 0); + + let transition = create_signed_shield_from_asset_lock_transition( + asset_lock_proof, + &asset_lock_pk, + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution { .. }] + ); + } + + /// Test that a structurally valid transition with dummy ZK proof data is rejected + /// with a PaidConsensusError (penalty applied via PartiallyUseAssetLockAction). + #[test] + fn test_invalid_proof_returns_shielded_proof_error_with_penalty() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let mut rng = StdRng::seed_from_u64(567); + let (asset_lock_proof, asset_lock_pk) = create_asset_lock_proof_with_key(&mut rng); + + let transition = create_signed_shield_from_asset_lock_transition( + asset_lock_proof, + &asset_lock_pk, + vec![create_dummy_serialized_action()], + 0x03, + -5000, + [0u8; 32], + vec![0u8; 100], // random proof data + [0u8; 64], + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // Passes structure + asset lock + ECDSA, fails at ZK proof verification. + // The asset lock is partially consumed as penalty. + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::PaidConsensusError { + error: ConsensusError::StateError(StateError::InvalidShieldedProofError(_)), + .. + }] + ); + } + } + + // ========================================== + // SECURITY AUDIT TESTS + // ========================================== + + mod security_audit { + use super::*; + + /// AUDIT FIX VERIFICATION: `value_balance = i64::MIN` no longer panics. + /// + /// Previously, `(-v0.value_balance) as u64` with i64::MIN caused an + /// overflow panic. The transform_into_action code now uses `checked_neg()` + /// which returns a consensus error instead of panicking. + #[test] + fn test_i64_min_value_balance_handled() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let mut rng = StdRng::seed_from_u64(567); + let (asset_lock_proof, asset_lock_pk) = create_asset_lock_proof_with_key(&mut rng); + + // i64::MIN is negative, so it passes the structure validation (value_balance < 0), + // but checked_neg() on i64::MIN returns None, triggering the overflow guard in + // transform_into_action. Since this error occurs after the asset lock proof + // validation, it is a paid error (PartiallyUseAssetLockAction). + let transition = create_signed_shield_from_asset_lock_transition( + asset_lock_proof, + &asset_lock_pk, + vec![create_dummy_serialized_action()], + 0x03, + i64::MIN, // -9223372036854775808 -- would overflow on negation + [0u8; 32], + vec![0u8; 100], + [0u8; 64], + 0, + ); + + // Should return a consensus error, not panic + let processing_result = process_transition(&platform, transition, platform_version); + + // The checked_neg overflow is caught in transform_into_action as an + // InvalidShieldedProofError. Since it happens after asset lock validation, + // we expect it to be reported as an UnpaidConsensusError (the overflow check + // is done before consuming the asset lock value, so no penalty is applied). + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + + /// AUDIT FIX VERIFICATION: Mutated value_balance is rejected by BatchValidator. + /// + /// This test builds a valid Orchard bundle with value_balance = -5000, then + /// mutates value_balance to -100000 in the transition. The binding signature + /// no longer matches, causing proof verification to fail. + #[test] + fn test_valid_proof_with_mutated_value_balance_is_rejected() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let mut rng = StdRng::seed_from_u64(567); + let (asset_lock_proof, asset_lock_pk) = create_asset_lock_proof_with_key(&mut rng); + + // Build a valid Orchard bundle + let mut orchard_rng = OsRng; + let pk = get_proving_key(); + + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + + let anchor = Anchor::empty_tree(); + let mut builder = Builder::new( + BundleType::Transactional { + flags: OrchardFlags::SPENDS_DISABLED, + bundle_required: false, + }, + anchor, + ); + + builder + .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 512]) + .unwrap(); + + let (unauthorized, _) = builder.build::(&mut orchard_rng).unwrap().unwrap(); + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &[]); + let proven = unauthorized.create_proof(pk, &mut orchard_rng).unwrap(); + let bundle = proven.apply_signatures(orchard_rng, sighash, &[]).unwrap(); + + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + + assert!(value_balance < 0); + let honest_shield_amount = (-value_balance) as u64; + assert_eq!(honest_shield_amount, 5_000); + + // ATTACK: Mutate value_balance to claim shielding 100,000 instead of 5,000 + let mutated_value_balance = -100_000i64; + + let transition = create_signed_shield_from_asset_lock_transition( + asset_lock_proof, + &asset_lock_pk, + actions, + flags, + mutated_value_balance, // MUTATED + anchor_bytes, + proof_bytes, + binding_sig, + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // BatchValidator now verifies binding signature. Mutated value_balance + // changes the bundle commitment / sighash, causing verification to fail. + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::PaidConsensusError { + error: ConsensusError::StateError(StateError::InvalidShieldedProofError(_)), + .. + }] + ); + } + + /// Verify that zeroed spend_auth_sig values (all zeros) in actions are rejected. + #[test] + fn test_zeroed_signatures_in_actions_rejected() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let mut rng = StdRng::seed_from_u64(567); + let (asset_lock_proof, asset_lock_pk) = create_asset_lock_proof_with_key(&mut rng); + + // Build a valid Orchard bundle first, then zero out the spend_auth_sig + let mut orchard_rng = OsRng; + let pk = get_proving_key(); + + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + + let anchor = Anchor::empty_tree(); + let mut builder = Builder::new( + BundleType::Transactional { + flags: OrchardFlags::SPENDS_DISABLED, + bundle_required: false, + }, + anchor, + ); + + builder + .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 512]) + .unwrap(); + + let (unauthorized, _) = builder.build::(&mut orchard_rng).unwrap().unwrap(); + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &[]); + let proven = unauthorized.create_proof(pk, &mut orchard_rng).unwrap(); + let bundle = proven.apply_signatures(orchard_rng, sighash, &[]).unwrap(); + + let (mut actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + + // Zero out all spend_auth_sig values + for action in actions.iter_mut() { + action.spend_auth_sig = [0u8; 64]; + } + + let transition = create_signed_shield_from_asset_lock_transition( + asset_lock_proof, + &asset_lock_pk, + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // Zeroed spend_auth_sig causes BatchValidator to reject the bundle + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::PaidConsensusError { + error: ConsensusError::StateError(StateError::InvalidShieldedProofError(_)), + .. + }] + ); + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs index a6fe7bf6d52..865a46c6198 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs @@ -1,4 +1,5 @@ use dpp::consensus::state::shielded::invalid_shielded_proof_error::InvalidShieldedProofError; +pub use dpp::shielded::compute_platform_sighash; use dpp::shielded::SerializedAction; use grovedb_commitment_tree::{ Action, Anchor, Authorized, BatchValidator, Bundle, ExtractedNoteCommitment, Flags, Nullifier, @@ -7,7 +8,6 @@ use grovedb_commitment_tree::{ use orchard::note::TransmittedNoteCiphertext; use orchard::primitives::redpallas; use orchard::value::ValueCommitment; -use sha2::{Digest, Sha256}; use std::sync::OnceLock; /// Cached verifying key for shielded proof verification. @@ -25,30 +25,6 @@ const ENC_CIPHERTEXT_SIZE: usize = 580; const OUT_CIPHERTEXT_SIZE: usize = 80; const ENCRYPTED_NOTE_SIZE: usize = EPK_SIZE + ENC_CIPHERTEXT_SIZE + OUT_CIPHERTEXT_SIZE; // 692 -/// Domain separator for Platform sighash computation. -const SIGHASH_DOMAIN: &[u8] = b"DashPlatformSighash"; - -/// Computes the platform sighash from an Orchard bundle commitment and optional -/// transparent field data. -/// -/// The sighash is computed as: -/// `SHA-256(SIGHASH_DOMAIN || bundle_commitment || extra_data)` -/// -/// This binds transparent state transition fields (like `output_address` and `amount` -/// in unshield transitions) to the Orchard signatures, preventing replay attacks -/// where an attacker substitutes transparent fields while reusing a valid Orchard bundle. -/// -/// The same computation must be used on both the signing (client) and verification -/// (platform) sides. For transitions without transparent fields (shield and -/// shielded_transfer), `extra_data` is empty. -pub fn compute_platform_sighash(bundle_commitment: &[u8; 32], extra_data: &[u8]) -> [u8; 32] { - let mut hasher = Sha256::new(); - hasher.update(SIGHASH_DOMAIN); - hasher.update(bundle_commitment); - hasher.update(extra_data); - hasher.finalize().into() -} - /// Reconstructs an orchard `Bundle` from the serialized fields /// of a shielded state transition and verifies the Halo 2 ZK proof along with /// all RedPallas signatures (spend auth + binding). diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs index 6f470160ff8..ef3479fb872 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs @@ -794,17 +794,8 @@ mod tests { ); } - /// AUDIT FINDING: No intra-bundle duplicate nullifier check. - /// - /// The nullifier validation loop only checks the state database for - /// each nullifier. It does not check for duplicates within the same - /// bundle's action list. This is mitigated by the ZK proof (which - /// can't produce duplicate nullifiers from a valid circuit), and by - /// GroveDB's insert_only_op (which would fail on the second insert). - /// - /// Severity: LOW (defense-in-depth gap) - /// For a fabricated bundle with duplicate nullifiers, the proof - /// verification catches the invalid data. + /// Duplicate nullifiers within the same bundle are caught by the + /// intra-bundle dedup check before reaching proof verification. #[test] fn test_duplicate_nullifiers_in_same_bundle() { let platform_version = PlatformVersion::latest(); @@ -830,14 +821,11 @@ mod tests { let processing_result = process_transition(&platform, transition, platform_version); - // The duplicate nullifiers are NOT caught by the application-level - // nullifier check (which only checks state). They are caught by - // proof verification (the fabricated data produces an invalid proof). - // Ideally, intra-bundle nullifier dedup should be added as defense-in-depth. + // Intra-bundle duplicate nullifier check catches this before proof verification assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + ConsensusError::StateError(StateError::NullifierAlreadySpentError(_)) )] ); } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs index 4685af3f7d5..859a28f9f8e 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs @@ -91,7 +91,20 @@ impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 for Shielded )); } - // Check that no nullifier has already been spent + // Defense-in-depth: reject duplicate nullifiers within the same bundle + let mut seen_nullifiers = std::collections::HashSet::new(); + for nullifier in &nullifiers { + if !seen_nullifiers.insert(nullifier) { + return Ok(ConsensusValidationResult::new_with_error( + StateError::NullifierAlreadySpentError(NullifierAlreadySpentError::new( + *nullifier, + )) + .into(), + )); + } + } + + // Check that no nullifier has already been spent in the state let nullifiers_path = shielded_credit_pool_nullifiers_path(); for nullifier in &nullifiers { let exists = drive.grove_has_raw( diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/mod.rs index e9b56726a49..58f70bcd1dd 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/mod.rs @@ -1,3 +1,4 @@ +mod tests; mod transform_into_action; use dpp::block::block_info::BlockInfo; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs new file mode 100644 index 00000000000..00f8cac5755 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs @@ -0,0 +1,1114 @@ +#[cfg(test)] +mod tests { + use crate::config::{PlatformConfig, PlatformTestConfig}; + use crate::execution::validation::state_transition::state_transitions::shielded_common::compute_platform_sighash; + use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; + use crate::test::helpers::setup::TestPlatformBuilder; + use assert_matches::assert_matches; + use dpp::block::block_info::BlockInfo; + use dpp::consensus::basic::BasicError; + use dpp::consensus::state::state_error::StateError; + use dpp::consensus::ConsensusError; + use dpp::identity::core_script::CoreScript; + use dpp::serialization::PlatformSerializable; + use dpp::shielded::SerializedAction; + use dpp::state_transition::shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0; + use dpp::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; + use dpp::state_transition::StateTransition; + use dpp::withdrawal::Pooling; + use drive::drive::shielded::paths::{ + shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, + shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY, + }; + use drive::grovedb::Element; + use platform_version::version::PlatformVersion; + + // ========================================== + // Helper Functions + // ========================================== + + /// Create a `SerializedAction` with syntactically valid sizes but meaningless crypto data. + /// Passes structure validation (correct field sizes) but will fail ZK proof verification. + fn create_dummy_serialized_action() -> SerializedAction { + SerializedAction { + nullifier: [1u8; 32], + rk: [2u8; 32], + cmx: [3u8; 32], + encrypted_note: vec![4u8; 692], // epk(32) + enc(580) + out(80) + cv_net: [5u8; 32], + spend_auth_sig: [6u8; 64], + } + } + + /// Create a dummy CoreScript (P2PKH) for the withdrawal output. + fn create_output_script() -> CoreScript { + CoreScript::new_p2pkh([7u8; 20]) + } + + /// Builds a `ShieldedWithdrawalTransition` state transition. + /// No signing needed since shielded withdrawal transitions have no ECDSA witnesses + /// (authenticated purely via Orchard ZK proof + signatures). + fn create_shielded_withdrawal_transition( + amount: u64, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + core_fee_per_byte: u32, + pooling: Pooling, + output_script: CoreScript, + user_fee_increase: u16, + ) -> StateTransition { + StateTransition::ShieldedWithdrawal(ShieldedWithdrawalTransition::V0( + ShieldedWithdrawalTransitionV0 { + amount, + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + core_fee_per_byte, + pooling, + output_script, + user_fee_increase, + }, + )) + } + + /// Shorthand for creating a structurally valid (but cryptographically invalid) shielded + /// withdrawal transition. Has a non-zero anchor, valid field sizes, positive amount and + /// value_balance. + fn create_default_shielded_withdrawal_transition() -> StateTransition { + create_shielded_withdrawal_transition( + 1000, // amount in credits + vec![create_dummy_serialized_action()], + 0x03, // spends_enabled | outputs_enabled + 1000, // value_balance = amount (no fee for simplicity) + [42u8; 32], // non-zero anchor + vec![0u8; 100], // dummy proof bytes + [0u8; 64], // dummy binding signature + 1, // core_fee_per_byte + Pooling::Never, // pooling strategy + create_output_script(), // P2PKH output script + 0, // user_fee_increase + ) + } + + /// Insert a fake anchor into the shielded anchors tree via GroveDB. + fn insert_anchor_into_state( + platform: &crate::test::helpers::setup::TempPlatform, + anchor: &[u8; 32], + ) { + let platform_version = PlatformVersion::latest(); + let grove_version = &platform_version.drive.grove_version; + let transaction = platform.drive.grove.start_transaction(); + let anchors_path = shielded_anchors_credit_pool_path(); + + platform + .drive + .grove + .insert( + &anchors_path, + anchor, + Element::Item(vec![], None), + None, + Some(&transaction), + grove_version, + ) + .unwrap() + .expect("should insert anchor"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("should commit transaction"); + } + + /// Insert a nullifier into the nullifiers tree via GroveDB. + fn insert_nullifier_into_state( + platform: &crate::test::helpers::setup::TempPlatform, + nullifier: &[u8; 32], + ) { + let platform_version = PlatformVersion::latest(); + let grove_version = &platform_version.drive.grove_version; + let transaction = platform.drive.grove.start_transaction(); + let nullifiers_path = shielded_credit_pool_nullifiers_path(); + + platform + .drive + .grove + .insert( + &nullifiers_path, + nullifier, + Element::Item(vec![], None), + None, + Some(&transaction), + grove_version, + ) + .unwrap() + .expect("should insert nullifier"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("should commit transaction"); + } + + /// Set the shielded pool total balance in GroveDB. + fn set_pool_total_balance( + platform: &crate::test::helpers::setup::TempPlatform, + balance: u64, + ) { + let platform_version = PlatformVersion::latest(); + let grove_version = &platform_version.drive.grove_version; + let transaction = platform.drive.grove.start_transaction(); + let pool_path = shielded_credit_pool_path(); + + platform + .drive + .grove + .insert( + &pool_path, + &[SHIELDED_TOTAL_BALANCE_KEY], + Element::new_sum_item(balance as i64), + None, + Some(&transaction), + grove_version, + ) + .unwrap() + .expect("should set total balance"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("should commit transaction"); + } + + /// Standard platform setup for tests. + fn setup_platform( + ) -> crate::test::helpers::setup::TempPlatform { + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + TestPlatformBuilder::new() + .with_config(platform_config) + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state() + } + + /// Execute a state transition through the full processing pipeline and return the result. + fn process_transition( + platform: &crate::test::helpers::setup::TempPlatform, + transition: StateTransition, + platform_version: &PlatformVersion, + ) -> crate::platform_types::state_transitions_processing_result::StateTransitionsProcessingResult + { + let transition_bytes = transition + .serialize_to_bytes() + .expect("should serialize transition"); + let platform_state = platform.state.load(); + let transaction = platform.drive.grove.start_transaction(); + + platform + .platform + .process_raw_state_transitions( + &vec![transition_bytes], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition") + } + + // ========================================== + // STRUCTURE VALIDATION TESTS (BasicError) + // ========================================== + + mod structure_validation { + use super::*; + + #[test] + fn test_empty_actions_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_shielded_withdrawal_transition( + 1000, + vec![], // Empty actions — invalid + 0x03, + 1000, + [42u8; 32], + vec![0u8; 100], + [0u8; 64], + 1, + Pooling::Never, + create_output_script(), + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::ShieldedNoActionsError(_)) + )] + ); + } + + #[test] + fn test_zero_amount_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_shielded_withdrawal_transition( + 0, // Zero amount — invalid + vec![create_dummy_serialized_action()], + 0x03, + 1000, + [42u8; 32], + vec![0u8; 100], + [0u8; 64], + 1, + Pooling::Never, + create_output_script(), + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::UnshieldAmountZeroError(_)) + )] + ); + } + + #[test] + fn test_zero_value_balance_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_shielded_withdrawal_transition( + 1000, + vec![create_dummy_serialized_action()], + 0x03, + 0, // Zero value_balance — invalid (must be positive for withdrawal) + [42u8; 32], + vec![0u8; 100], + [0u8; 64], + 1, + Pooling::Never, + create_output_script(), + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::ShieldedInvalidValueBalanceError(_)) + )] + ); + } + + #[test] + fn test_negative_value_balance_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_shielded_withdrawal_transition( + 1000, + vec![create_dummy_serialized_action()], + 0x03, + -1000, // Negative value_balance — invalid (must be positive for withdrawal) + [42u8; 32], + vec![0u8; 100], + [0u8; 64], + 1, + Pooling::Never, + create_output_script(), + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::ShieldedInvalidValueBalanceError(_)) + )] + ); + } + + #[test] + fn test_value_balance_less_than_amount_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_shielded_withdrawal_transition( + 2000, // amount = 2000 + vec![create_dummy_serialized_action()], + 0x03, + 1000, // value_balance = 1000 < amount — invalid + [42u8; 32], + vec![0u8; 100], + [0u8; 64], + 1, + Pooling::Never, + create_output_script(), + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::UnshieldValueBalanceBelowAmountError(_)) + )] + ); + } + + #[test] + fn test_empty_proof_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_shielded_withdrawal_transition( + 1000, + vec![create_dummy_serialized_action()], + 0x03, + 1000, + [42u8; 32], + vec![], // Empty proof — invalid + [0u8; 64], + 1, + Pooling::Never, + create_output_script(), + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::ShieldedEmptyProofError(_)) + )] + ); + } + + #[test] + fn test_zero_anchor_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_shielded_withdrawal_transition( + 1000, + vec![create_dummy_serialized_action()], + 0x03, + 1000, + [0u8; 32], // All zeros — invalid + vec![0u8; 100], + [0u8; 64], + 1, + Pooling::Never, + create_output_script(), + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::ShieldedZeroAnchorError(_)) + )] + ); + } + } + + // ========================================== + // ANCHOR VALIDATION TESTS (StateError) + // ========================================== + + mod anchor_validation { + use super::*; + + #[test] + fn test_anchor_not_in_tree_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + // Non-zero anchor that doesn't exist in state + let transition = create_default_shielded_withdrawal_transition(); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidAnchorError(_)) + )] + ); + } + } + + // ========================================== + // NULLIFIER DOUBLE-SPEND TESTS (StateError) + // ========================================== + + mod nullifier_validation { + use super::*; + + #[test] + fn test_already_spent_nullifier_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let anchor = [42u8; 32]; + let nullifier = [1u8; 32]; // Same as create_dummy_serialized_action().nullifier + + // Insert the anchor so anchor validation passes + insert_anchor_into_state(&platform, &anchor); + + // Set pool balance so the pool balance check passes + set_pool_total_balance(&platform, 10_000); + + // Insert the nullifier so it appears already spent + insert_nullifier_into_state(&platform, &nullifier); + + let transition = create_default_shielded_withdrawal_transition(); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::NullifierAlreadySpentError(_)) + )] + ); + } + } + + // ========================================== + // ZK PROOF VERIFICATION TESTS (InvalidShieldedProofError) + // ========================================== + + mod proof_verification { + use super::*; + use grovedb_commitment_tree::{ + new_memory_store, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + CommitmentTree, ExtractedNoteCommitment, FullViewingKey, Note, NoteValue, Position, + ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, + }; + use orchard::note::RandomSeed; + use rand::rngs::OsRng; + use std::sync::OnceLock; + + static TEST_PROVING_KEY: OnceLock = OnceLock::new(); + fn get_proving_key() -> &'static ProvingKey { + TEST_PROVING_KEY.get_or_init(ProvingKey::build) + } + + fn serialize_authorized_bundle( + bundle: &Bundle, + ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { + let actions: Vec = bundle + .actions() + .iter() + .map(|action| { + let enc = action.encrypted_note(); + let mut encrypted_note = Vec::with_capacity(692); + encrypted_note.extend_from_slice(&enc.epk_bytes); + encrypted_note.extend_from_slice(&enc.enc_ciphertext); + encrypted_note.extend_from_slice(&enc.out_ciphertext); + SerializedAction { + nullifier: action.nullifier().to_bytes(), + rk: <[u8; 32]>::from(action.rk()), + cmx: action.cmx().to_bytes(), + encrypted_note, + cv_net: action.cv_net().to_bytes(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()), + } + }) + .collect(); + let flags = bundle.flags().to_byte(); + let value_balance = *bundle.value_balance(); + let anchor = bundle.anchor().to_bytes(); + let proof = bundle.authorization().proof().as_ref().to_vec(); + let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); + (actions, flags, value_balance, anchor, proof, binding_sig) + } + + #[test] + fn test_invalid_proof_returns_shielded_proof_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let anchor = [42u8; 32]; + + // Insert the anchor so anchor validation passes + insert_anchor_into_state(&platform, &anchor); + + // Set pool balance so the pool balance check passes + set_pool_total_balance(&platform, 10_000); + + // This transition is structurally valid and has a valid anchor, + // but has random ZK proof data. It should pass structure validation + // and anchor validation but fail at proof verification. + let transition = create_default_shielded_withdrawal_transition(); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + + #[test] + fn test_valid_shielded_withdrawal_proof_succeeds() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + let mut rng = OsRng; + let pk = get_proving_key(); + + // --- Create keys --- + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + let ask = SpendAuthorizingKey::from(&sk); + + // --- Create a spendable note with value 10,000 --- + let rho_bytes: [u8; 32] = { + let mut b = [0u8; 32]; + b[0] = 1; + b + }; + let rho = Rho::from_bytes(&rho_bytes).unwrap(); + let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); + let note = + Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); + + // --- Build commitment tree and get anchor + merkle path --- + let cmx = ExtractedNoteCommitment::from(note.commitment()); + let mut tree = CommitmentTree::new(new_memory_store(), 100); + tree.append(cmx, Retention::Marked).unwrap(); + tree.checkpoint(0u32).unwrap(); + let anchor = tree.anchor().unwrap(); + let merkle_path = tree.orchard_witness(Position::from(0u64)).unwrap().unwrap(); + + // --- Build bundle: spend 10,000 -> output 5,000 (value_balance = 5,000) --- + let mut builder = Builder::new(BundleType::DEFAULT, anchor); + builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); + builder + .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 512]) + .unwrap(); + + let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); + + // Compute platform sighash binding transparent fields (output_script, amount) + let output_script = create_output_script(); + let amount = 5_000u64; // = value_balance (no fee difference) + let mut extra_sighash_data = output_script.as_bytes().to_vec(); + extra_sighash_data.extend_from_slice(&amount.to_le_bytes()); + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &extra_sighash_data); + + let proven = unauthorized.create_proof(pk, &mut rng).unwrap(); + let bundle = proven.apply_signatures(rng, sighash, &[ask]).unwrap(); + + // --- Extract serialized fields --- + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + + // value_balance should be 5000 (10,000 spent - 5,000 output) + assert_eq!(value_balance, 5_000); + + // --- Set up platform state --- + // Insert anchor so anchor validation passes + insert_anchor_into_state(&platform, &anchor_bytes); + + // Set pool total balance so the withdrawal has sufficient funds + set_pool_total_balance(&platform, 10_000); + + // --- Create and process transition --- + let transition = create_shielded_withdrawal_transition( + amount, // amount = 5000 credits + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + 1, // core_fee_per_byte + Pooling::Never, // pooling strategy + output_script, + 0, // user_fee_increase + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution { .. }] + ); + } + + #[test] + fn test_wrong_encrypted_note_size_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let anchor = [42u8; 32]; + + // Insert the anchor so anchor validation passes + insert_anchor_into_state(&platform, &anchor); + + // Set pool balance so the pool balance check passes + set_pool_total_balance(&platform, 10_000); + + // Create action with wrong encrypted_note size + let mut bad_action = create_dummy_serialized_action(); + bad_action.encrypted_note = vec![0u8; 100]; // 100 bytes instead of 692 + + let transition = create_shielded_withdrawal_transition( + 1000, + vec![bad_action], + 0x03, + 1000, + anchor, + vec![0u8; 100], + [0u8; 64], + 1, + Pooling::Never, + create_output_script(), + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + } + + // ========================================== + // SECURITY AUDIT TESTS + // ========================================== + // + // These tests verify vulnerabilities and edge cases discovered + // during a security audit of the shielded transaction system. + // Tests that demonstrate actual vulnerabilities are marked with + // "AUDIT FINDING" / "AUDIT REGRESSION" comments. + + mod security_audit { + use super::*; + use grovedb_commitment_tree::{ + new_memory_store, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + CommitmentTree, ExtractedNoteCommitment, FullViewingKey, Note, NoteValue, Position, + ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, + }; + use orchard::note::RandomSeed; + use rand::rngs::OsRng; + use std::sync::OnceLock; + + static TEST_PROVING_KEY: OnceLock = OnceLock::new(); + fn get_proving_key() -> &'static ProvingKey { + TEST_PROVING_KEY.get_or_init(ProvingKey::build) + } + + fn serialize_authorized_bundle( + bundle: &Bundle, + ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { + let actions: Vec = bundle + .actions() + .iter() + .map(|action| { + let enc = action.encrypted_note(); + let mut encrypted_note = Vec::with_capacity(692); + encrypted_note.extend_from_slice(&enc.epk_bytes); + encrypted_note.extend_from_slice(&enc.enc_ciphertext); + encrypted_note.extend_from_slice(&enc.out_ciphertext); + SerializedAction { + nullifier: action.nullifier().to_bytes(), + rk: <[u8; 32]>::from(action.rk()), + cmx: action.cmx().to_bytes(), + encrypted_note, + cv_net: action.cv_net().to_bytes(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()), + } + }) + .collect(); + let flags = bundle.flags().to_byte(); + let value_balance = *bundle.value_balance(); + let anchor = bundle.anchor().to_bytes(); + let proof = bundle.authorization().proof().as_ref().to_vec(); + let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); + (actions, flags, value_balance, anchor, proof, binding_sig) + } + + /// Build a valid Orchard bundle for shielded withdrawal tests (spend > output). + /// The `output_script` and `amount` are bound to the sighash so that + /// the resulting bundle can only be used with those specific transparent fields. + /// Returns (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig). + fn build_valid_shielded_withdrawal_bundle( + output_script: &CoreScript, + amount: u64, + ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { + let mut rng = OsRng; + let pk = get_proving_key(); + + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + let ask = SpendAuthorizingKey::from(&sk); + + let rho_bytes: [u8; 32] = { + let mut b = [0u8; 32]; + b[0] = 1; + b + }; + let rho = Rho::from_bytes(&rho_bytes).unwrap(); + let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); + let note = + Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); + + let cmx = ExtractedNoteCommitment::from(note.commitment()); + let mut tree = CommitmentTree::new(new_memory_store(), 100); + tree.append(cmx, Retention::Marked).unwrap(); + tree.checkpoint(0u32).unwrap(); + let anchor = tree.anchor().unwrap(); + let merkle_path = tree.orchard_witness(Position::from(0u64)).unwrap().unwrap(); + + // Spend 10,000 -> output 5,000 -> value_balance = 5,000 + let mut builder = Builder::new(BundleType::DEFAULT, anchor); + builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); + builder + .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 512]) + .unwrap(); + + let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); + + // Bind transparent fields (output_script, amount) to the sighash + let mut extra_sighash_data = output_script.as_bytes().to_vec(); + extra_sighash_data.extend_from_slice(&amount.to_le_bytes()); + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &extra_sighash_data); + + let proven = unauthorized.create_proof(pk, &mut rng).unwrap(); + let bundle = proven.apply_signatures(rng, sighash, &[ask]).unwrap(); + + serialize_authorized_bundle(&bundle) + } + + /// Edge case: i64::MIN value_balance should be caught by structure validation + /// (value_balance must be positive). This ensures no integer overflow or + /// underflow issues occur when handling the most extreme negative i64 value. + #[test] + fn test_i64_min_value_balance_handled() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let transition = create_shielded_withdrawal_transition( + 1000, + vec![create_dummy_serialized_action()], + 0x03, + i64::MIN, // Most extreme negative value — must be rejected + [42u8; 32], + vec![0u8; 100], + [0u8; 64], + 1, + Pooling::Never, + create_output_script(), + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // i64::MIN is negative, so structure validation rejects it as + // "shielded withdrawal value_balance must be positive" + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::BasicError(BasicError::ShieldedInvalidValueBalanceError(_)) + )] + ); + } + + /// AUDIT REGRESSION: Zeroed binding signature is caught by BatchValidator. + /// + /// The binding signature cryptographically binds value_balance to the value + /// commitments. Zeroing it out should cause signature verification to fail, + /// preventing an attacker from stripping authentication from a valid bundle. + /// + /// Original severity: CRITICAL — now FIXED. + #[test] + fn test_valid_proof_with_zeroed_binding_sig_is_rejected() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let output_script = create_output_script(); + let amount = 5_000u64; + let (actions, flags, value_balance, anchor_bytes, proof_bytes, _binding_sig) = + build_valid_shielded_withdrawal_bundle(&output_script, amount); + + set_pool_total_balance(&platform, 20_000); + insert_anchor_into_state(&platform, &anchor_bytes); + + let transition = create_shielded_withdrawal_transition( + amount, + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + [0u8; 64], // ZEROED binding signature + 1, + Pooling::Never, + output_script, + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // FIXED: BatchValidator detects the invalid binding signature. + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + + /// AUDIT REGRESSION: Mutating value_balance is caught by BatchValidator. + /// + /// Previously, the code only called `bundle.verify_proof(vk)` which did not + /// check the binding signature. Now `BatchValidator` verifies the Halo 2 proof + /// AND the binding signature, which cryptographically binds value_balance to + /// the value commitments (cv_net). Mutating value_balance changes the bundle + /// commitment (sighash), causing signature verification to fail. + /// + /// Original severity: CRITICAL — now FIXED. + #[test] + fn test_valid_proof_with_mutated_value_balance_is_rejected() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + // Bundle is signed for create_output_script() with amount = 5000 + let output_script = create_output_script(); + let signed_amount = 5_000u64; + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + build_valid_shielded_withdrawal_bundle(&output_script, signed_amount); + assert_eq!(value_balance, 5_000); + + // ATTACK: Inflate value_balance from 5000 to 9000 + let mutated_value_balance = 9_000i64; + + // Set pool balance high enough for the inflated amount + set_pool_total_balance(&platform, 20_000); + insert_anchor_into_state(&platform, &anchor_bytes); + + let transition = create_shielded_withdrawal_transition( + mutated_value_balance as u64, // amount = 9000 (inflated) + actions, + flags, + mutated_value_balance, // MUTATED: was 5000, now 9000 + anchor_bytes, + proof_bytes, + binding_sig, + 1, + Pooling::Never, + output_script, + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // FIXED: BatchValidator detects the binding signature mismatch. + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + + /// AUDIT REGRESSION: Different output_script is caught by platform sighash. + /// + /// The output_script is bound to the Orchard bundle via sighash. Changing + /// the script after signing causes the sighash to differ from the one used + /// during signing, and signature verification fails. This prevents an + /// attacker from redirecting withdrawal funds to a different L1 address. + /// + /// Original severity: HIGH — now FIXED. + #[test] + fn test_different_output_script_with_same_valid_bundle_is_rejected() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + // Bundle is signed for the ORIGINAL output_script with amount = 5000 + let original_script = create_output_script(); + let amount = 5_000u64; + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + build_valid_shielded_withdrawal_bundle(&original_script, amount); + assert_eq!(value_balance, 5_000); + + set_pool_total_balance(&platform, 20_000); + insert_anchor_into_state(&platform, &anchor_bytes); + + // ATTACK: Use a completely different output script (attacker's address) + let attacker_script = CoreScript::new_p2pkh([0xAA; 20]); + + let transition = create_shielded_withdrawal_transition( + amount, + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + 1, + Pooling::Never, + attacker_script, // ATTACKER's script, not the original + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // FIXED: Platform sighash includes output_script, so changing it + // causes the sighash to differ from the one used during signing, + // and signature verification fails. + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + + /// AUDIT REGRESSION: Different amount is caught by platform sighash. + /// + /// The amount is bound to the Orchard bundle via sighash. Changing the + /// withdrawal amount after signing causes the sighash to differ, and + /// signature verification fails. This prevents an attacker from inflating + /// the credited withdrawal amount while keeping a valid value_balance. + #[test] + fn test_different_amount_with_same_valid_bundle_is_rejected() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let output_script = create_output_script(); + let signed_amount = 5_000u64; + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + build_valid_shielded_withdrawal_bundle(&output_script, signed_amount); + assert_eq!(value_balance, 5_000); + + set_pool_total_balance(&platform, 20_000); + insert_anchor_into_state(&platform, &anchor_bytes); + + // ATTACK: Use a smaller amount (4000) but same value_balance (5000) + // to pocket the difference as "fee" that goes nowhere + let manipulated_amount = 4_000u64; + + let transition = create_shielded_withdrawal_transition( + manipulated_amount, // MANIPULATED: was 5000, now 4000 + actions, + flags, + value_balance, // still 5000 — passes value_balance >= amount check + anchor_bytes, + proof_bytes, + binding_sig, + 1, + Pooling::Never, + output_script, + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // Platform sighash includes amount, so changing it causes + // signature verification to fail. + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + + /// AUDIT FINDING: No intra-bundle duplicate nullifier check. + /// + /// Same as the shielded_transfer and unshield findings. The nullifier + /// check only queries state, not checking for duplicates within the + /// bundle itself. Mitigated by ZK proof verification (fabricated data + /// with duplicate nullifiers produces an invalid proof). + /// + /// Severity: LOW (defense-in-depth gap, caught by ZK proof verification) + #[test] + fn test_duplicate_nullifiers_in_same_bundle() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let anchor = [42u8; 32]; + insert_anchor_into_state(&platform, &anchor); + set_pool_total_balance(&platform, 10_000); + + let action1 = create_dummy_serialized_action(); + let mut action2 = create_dummy_serialized_action(); + action2.cmx = [99u8; 32]; // Different commitment but same nullifier + + let transition = create_shielded_withdrawal_transition( + 1000, + vec![action1, action2], // Both have nullifier [1u8; 32] + 0x03, + 1000, + anchor, + vec![0u8; 100], + [0u8; 64], + 1, + Pooling::Never, + create_output_script(), + 0, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + // Caught by proof verification, not by application-level dedup + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] + ); + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs index f757662685d..c060058d03d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs @@ -114,7 +114,20 @@ impl ShieldedWithdrawalStateTransitionTransformIntoActionValidationV0 )); } - // Check that no nullifier has already been spent + // Defense-in-depth: reject duplicate nullifiers within the same bundle + let mut seen_nullifiers = std::collections::HashSet::new(); + for nullifier in &nullifiers { + if !seen_nullifiers.insert(nullifier) { + return Ok(ConsensusValidationResult::new_with_error( + StateError::NullifierAlreadySpentError(NullifierAlreadySpentError::new( + *nullifier, + )) + .into(), + )); + } + } + + // Check that no nullifier has already been spent in the state let nullifiers_path = shielded_credit_pool_nullifiers_path(); for nullifier in &nullifiers { let exists = drive.grove_has_raw( diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs index 642f0c447ec..cc3d6ef7031 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs @@ -894,12 +894,8 @@ mod tests { ); } - /// AUDIT FINDING: No intra-bundle duplicate nullifier check. - /// - /// Same as the shielded_transfer finding. The nullifier check only - /// queries state, not checking for duplicates within the bundle itself. - /// - /// Severity: LOW (defense-in-depth gap, caught by ZK proof verification) + /// Duplicate nullifiers within the same bundle are caught by the + /// intra-bundle dedup check before reaching proof verification. #[test] fn test_duplicate_nullifiers_in_same_bundle() { let platform_version = PlatformVersion::latest(); @@ -927,11 +923,11 @@ mod tests { let processing_result = process_transition(&platform, transition, platform_version); - // Caught by proof verification, not by application-level dedup + // Intra-bundle duplicate nullifier check catches this before proof verification assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + ConsensusError::StateError(StateError::NullifierAlreadySpentError(_)) )] ); } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs index f86275c7dc2..3b0c9f1d233 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs @@ -85,7 +85,20 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti )); } - // Check that no nullifier has already been spent + // Defense-in-depth: reject duplicate nullifiers within the same bundle + let mut seen_nullifiers = std::collections::HashSet::new(); + for nullifier in &nullifiers { + if !seen_nullifiers.insert(nullifier) { + return Ok(ConsensusValidationResult::new_with_error( + StateError::NullifierAlreadySpentError(NullifierAlreadySpentError::new( + *nullifier, + )) + .into(), + )); + } + } + + // Check that no nullifier has already been spent in the state let nullifiers_path = shielded_credit_pool_nullifiers_path(); for nullifier in &nullifiers { let exists = drive.grove_has_raw( diff --git a/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs b/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs index ca2f6cf6943..d894e6ec1cf 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs @@ -1445,6 +1445,13 @@ pub(crate) fn verify_state_transitions_were_or_were_not_executed( } } StateTransitionAction::BumpAddressInputNoncesAction(_) => {} + StateTransitionAction::ShieldAction(_) + | StateTransitionAction::ShieldedTransferAction(_) + | StateTransitionAction::UnshieldAction(_) + | StateTransitionAction::ShieldFromAssetLockAction(_) + | StateTransitionAction::ShieldedWithdrawalAction(_) => { + // Shielded transitions don't support proof verification yet + } } } else { // if we don't have an action this means there was a problem in the validation of the state transition diff --git a/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs b/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs index 044cd9854e4..a4129376001 100644 --- a/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs +++ b/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs @@ -46,7 +46,7 @@ use dpp::state_transition::batch_transition::token_transfer_transition::v0::v0_m use dpp::state_transition::batch_transition::token_unfreeze_transition::v0::v0_methods::TokenUnfreezeTransitionV0Methods; use dpp::state_transition::masternode_vote_transition::accessors::MasternodeVoteTransitionAccessorsV0; use dpp::state_transition::proof_result::StateTransitionProofResult; -use dpp::state_transition::proof_result::StateTransitionProofResult::{VerifiedAddressInfos, VerifiedBalanceTransfer, VerifiedDataContract, VerifiedDocuments, VerifiedIdentity, VerifiedIdentityFullWithAddressInfos, VerifiedIdentityWithAddressInfos, VerifiedMasternodeVote, VerifiedPartialIdentity, VerifiedTokenActionWithDocument, VerifiedTokenBalance, VerifiedTokenGroupActionWithDocument, VerifiedTokenGroupActionWithTokenBalance, VerifiedTokenGroupActionWithTokenIdentityInfo, VerifiedTokenGroupActionWithTokenPricingSchedule, VerifiedTokenIdentitiesBalances, VerifiedTokenIdentityInfo, VerifiedTokenPricingSchedule}; +use dpp::state_transition::proof_result::StateTransitionProofResult::{VerifiedAddressInfos, VerifiedBalanceTransfer, VerifiedDataContract, VerifiedDocuments, VerifiedIdentity, VerifiedIdentityFullWithAddressInfos, VerifiedIdentityWithAddressInfos, VerifiedMasternodeVote, VerifiedPartialIdentity, VerifiedShieldedPoolState, VerifiedTokenActionWithDocument, VerifiedTokenBalance, VerifiedTokenGroupActionWithDocument, VerifiedTokenGroupActionWithTokenBalance, VerifiedTokenGroupActionWithTokenIdentityInfo, VerifiedTokenGroupActionWithTokenPricingSchedule, VerifiedTokenIdentitiesBalances, VerifiedTokenIdentityInfo, VerifiedTokenPricingSchedule}; use dpp::system_data_contracts::{load_system_data_contract, SystemDataContract}; use dpp::tokens::info::v0::IdentityTokenInfoV0Accessors; use dpp::voting::vote_polls::VotePoll; @@ -1115,14 +1115,43 @@ impl Drive { Ok((root_hash, VerifiedAddressInfos(balances))) } - StateTransition::Shield(_) - | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) + StateTransition::Shield(st) => { + use dpp::state_transition::StateTransitionWitnessSigned; + let (root_hash, balances): ( + RootHash, + BTreeMap>, + ) = Drive::verify_addresses_infos( + proof, + st.inputs().keys(), + false, + platform_version, + )?; + Ok((root_hash, VerifiedAddressInfos(balances))) + } + StateTransition::Unshield(st) => { + use dpp::state_transition::unshield_transition::UnshieldTransition; + let output_address = match st { + UnshieldTransition::V0(v0) => &v0.output_address, + }; + let (root_hash, balances): ( + RootHash, + BTreeMap>, + ) = Drive::verify_addresses_infos( + proof, + std::iter::once(output_address), + false, + platform_version, + )?; + Ok((root_hash, VerifiedAddressInfos(balances))) + } + StateTransition::ShieldedTransfer(_) | StateTransition::ShieldFromAssetLock(_) | StateTransition::ShieldedWithdrawal(_) => { - Err(Error::Proof(ProofError::InvalidTransition( - "shielded state transitions do not support proof verification yet".to_string(), - ))) + let (root_hash, pool_balance) = Drive::verify_shielded_pool_state( + proof, + platform_version, + )?; + Ok((root_hash, VerifiedShieldedPoolState(pool_balance))) } } } diff --git a/packages/rs-sdk-ffi/src/system/queries/path_elements.rs b/packages/rs-sdk-ffi/src/system/queries/path_elements.rs index 47e1399c210..bb17b06c9c1 100644 --- a/packages/rs-sdk-ffi/src/system/queries/path_elements.rs +++ b/packages/rs-sdk-ffi/src/system/queries/path_elements.rs @@ -156,6 +156,7 @@ fn get_path_elements( Element::ProvableCountSumTree(_, count, sum, _) => { format!("provable_count_sum_tree:{}:{}", count, sum) } + Element::CommitmentTree(_, _) => "commitment_tree".to_string(), }; format!( @@ -176,6 +177,7 @@ fn get_path_elements( Element::ProvableCountSumTree(_, _, _, _) => { "provable_count_sum_tree" } + Element::CommitmentTree(_, _) => "commitment_tree", } ) }) diff --git a/packages/rs-sdk/src/platform/transition.rs b/packages/rs-sdk/src/platform/transition.rs index e477750f5eb..10196dac0fa 100644 --- a/packages/rs-sdk/src/platform/transition.rs +++ b/packages/rs-sdk/src/platform/transition.rs @@ -9,6 +9,10 @@ pub mod put_contract; pub mod put_document; pub mod put_identity; pub mod put_settings; +pub mod shield; +pub mod shield_from_asset_lock; +pub mod shielded_transfer; +pub mod shielded_withdrawal; pub mod top_up_address; pub mod top_up_identity; pub mod top_up_identity_from_addresses; @@ -16,6 +20,7 @@ pub mod transfer; pub mod transfer_address_funds; pub mod transfer_document; pub mod transfer_to_addresses; +pub mod unshield; mod txid; pub mod update_price_of_document; pub(crate) mod validation; diff --git a/packages/rs-sdk/src/platform/transition/shield.rs b/packages/rs-sdk/src/platform/transition/shield.rs new file mode 100644 index 00000000000..91b05d2cdb0 --- /dev/null +++ b/packages/rs-sdk/src/platform/transition/shield.rs @@ -0,0 +1,120 @@ +use std::collections::BTreeMap; + +use super::address_inputs::{fetch_inputs_with_nonce, nonce_inc}; +use super::broadcast::BroadcastStateTransition; +use super::put_settings::PutSettings; +use super::validation::ensure_valid_state_transition_structure; +use crate::{Error, Sdk}; +use dpp::address_funds::{AddressFundsFeeStrategy, PlatformAddress}; +use dpp::fee::Credits; +use dpp::identity::signer::Signer; +use dpp::prelude::AddressNonce; +use dpp::shielded::SerializedAction; +use dpp::state_transition::shield_transition::methods::ShieldTransitionMethodsV0; +use dpp::state_transition::shield_transition::ShieldTransition; + +/// Helper trait to shield platform credits into the shielded pool. +#[async_trait::async_trait] +pub trait ShieldFunds> { + /// Shield funds from platform addresses into the shielded pool. + /// Address nonces are fetched automatically. + #[allow(clippy::too_many_arguments)] + async fn shield_funds( + &self, + inputs: BTreeMap, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + fee_strategy: AddressFundsFeeStrategy, + signer: &S, + settings: Option, + ) -> Result<(), Error>; + + /// Shield funds with explicitly provided address nonces. + #[allow(clippy::too_many_arguments)] + async fn shield_funds_with_nonce( + &self, + inputs: BTreeMap, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + fee_strategy: AddressFundsFeeStrategy, + signer: &S, + settings: Option, + ) -> Result<(), Error>; +} + +#[async_trait::async_trait] +impl> ShieldFunds for Sdk { + async fn shield_funds( + &self, + inputs: BTreeMap, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + fee_strategy: AddressFundsFeeStrategy, + signer: &S, + settings: Option, + ) -> Result<(), Error> { + let inputs_with_nonce = nonce_inc(fetch_inputs_with_nonce(self, &inputs).await?); + self.shield_funds_with_nonce( + inputs_with_nonce, + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + fee_strategy, + signer, + settings, + ) + .await + } + + async fn shield_funds_with_nonce( + &self, + inputs: BTreeMap, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + fee_strategy: AddressFundsFeeStrategy, + signer: &S, + settings: Option, + ) -> Result<(), Error> { + let user_fee_increase = settings + .as_ref() + .and_then(|s| s.user_fee_increase) + .unwrap_or_default(); + + let state_transition = ShieldTransition::try_from_bundle_with_signer( + inputs, + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + fee_strategy, + signer, + user_fee_increase, + self.version(), + )?; + ensure_valid_state_transition_structure(&state_transition, self.version())?; + + state_transition.broadcast(self, settings).await?; + Ok(()) + } +} diff --git a/packages/rs-sdk/src/platform/transition/shield_from_asset_lock.rs b/packages/rs-sdk/src/platform/transition/shield_from_asset_lock.rs new file mode 100644 index 00000000000..fbc1f6953c2 --- /dev/null +++ b/packages/rs-sdk/src/platform/transition/shield_from_asset_lock.rs @@ -0,0 +1,68 @@ +use super::broadcast::BroadcastStateTransition; +use super::put_settings::PutSettings; +use super::validation::ensure_valid_state_transition_structure; +use crate::{Error, Sdk}; +use dpp::prelude::AssetLockProof; +use dpp::shielded::SerializedAction; +use dpp::state_transition::shield_from_asset_lock_transition::methods::ShieldFromAssetLockTransitionMethodsV0; +use dpp::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; + +/// Helper trait to shield funds from an L1 asset lock into the shielded pool. +#[async_trait::async_trait] +pub trait ShieldFromAssetLock { + /// Shield funds from an L1 asset lock into the shielded pool. + /// The asset lock proof proves ownership of L1 funds, and the ECDSA signature + /// binds those funds to this specific Orchard bundle. + #[allow(clippy::too_many_arguments)] + async fn shield_from_asset_lock( + &self, + asset_lock_proof: AssetLockProof, + asset_lock_proof_private_key: &[u8], + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + settings: Option, + ) -> Result<(), Error>; +} + +#[async_trait::async_trait] +impl ShieldFromAssetLock for Sdk { + async fn shield_from_asset_lock( + &self, + asset_lock_proof: AssetLockProof, + asset_lock_proof_private_key: &[u8], + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + settings: Option, + ) -> Result<(), Error> { + let user_fee_increase = settings + .as_ref() + .and_then(|s| s.user_fee_increase) + .unwrap_or_default(); + + let state_transition = + ShieldFromAssetLockTransition::try_from_asset_lock_with_bundle( + asset_lock_proof, + asset_lock_proof_private_key, + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + user_fee_increase, + self.version(), + )?; + ensure_valid_state_transition_structure(&state_transition, self.version())?; + + state_transition.broadcast(self, settings).await?; + Ok(()) + } +} diff --git a/packages/rs-sdk/src/platform/transition/shielded_transfer.rs b/packages/rs-sdk/src/platform/transition/shielded_transfer.rs new file mode 100644 index 00000000000..4c46c480f54 --- /dev/null +++ b/packages/rs-sdk/src/platform/transition/shielded_transfer.rs @@ -0,0 +1,59 @@ +use super::broadcast::BroadcastStateTransition; +use super::put_settings::PutSettings; +use super::validation::ensure_valid_state_transition_structure; +use crate::{Error, Sdk}; +use dpp::shielded::SerializedAction; +use dpp::state_transition::shielded_transfer_transition::methods::ShieldedTransferTransitionMethodsV0; +use dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition; + +/// Helper trait to transfer funds within the shielded pool. +#[async_trait::async_trait] +pub trait TransferShielded { + /// Transfer funds within the shielded pool. + /// Authentication is via Orchard spend authorization signatures in the bundle actions. + #[allow(clippy::too_many_arguments)] + async fn transfer_shielded( + &self, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + settings: Option, + ) -> Result<(), Error>; +} + +#[async_trait::async_trait] +impl TransferShielded for Sdk { + async fn transfer_shielded( + &self, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + settings: Option, + ) -> Result<(), Error> { + let user_fee_increase = settings + .as_ref() + .and_then(|s| s.user_fee_increase) + .unwrap_or_default(); + + let state_transition = ShieldedTransferTransition::try_from_bundle( + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + user_fee_increase, + self.version(), + )?; + ensure_valid_state_transition_structure(&state_transition, self.version())?; + + state_transition.broadcast(self, settings).await?; + Ok(()) + } +} diff --git a/packages/rs-sdk/src/platform/transition/shielded_withdrawal.rs b/packages/rs-sdk/src/platform/transition/shielded_withdrawal.rs new file mode 100644 index 00000000000..063bcabaa2f --- /dev/null +++ b/packages/rs-sdk/src/platform/transition/shielded_withdrawal.rs @@ -0,0 +1,73 @@ +use super::broadcast::BroadcastStateTransition; +use super::put_settings::PutSettings; +use super::validation::ensure_valid_state_transition_structure; +use crate::{Error, Sdk}; +use dpp::identity::core_script::CoreScript; +use dpp::shielded::SerializedAction; +use dpp::state_transition::shielded_withdrawal_transition::methods::ShieldedWithdrawalTransitionMethodsV0; +use dpp::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; +use dpp::withdrawal::Pooling; + +/// Helper trait to withdraw funds from the shielded pool to L1. +#[async_trait::async_trait] +pub trait WithdrawShielded { + /// Withdraw funds from the shielded pool to a Core address. + /// Authentication is via Orchard spend authorization signatures in the bundle actions. + #[allow(clippy::too_many_arguments)] + async fn withdraw_shielded( + &self, + amount: u64, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + core_fee_per_byte: u32, + pooling: Pooling, + output_script: CoreScript, + settings: Option, + ) -> Result<(), Error>; +} + +#[async_trait::async_trait] +impl WithdrawShielded for Sdk { + async fn withdraw_shielded( + &self, + amount: u64, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + core_fee_per_byte: u32, + pooling: Pooling, + output_script: CoreScript, + settings: Option, + ) -> Result<(), Error> { + let user_fee_increase = settings + .as_ref() + .and_then(|s| s.user_fee_increase) + .unwrap_or_default(); + + let state_transition = ShieldedWithdrawalTransition::try_from_bundle( + amount, + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + core_fee_per_byte, + pooling, + output_script, + user_fee_increase, + self.version(), + )?; + ensure_valid_state_transition_structure(&state_transition, self.version())?; + + state_transition.broadcast(self, settings).await?; + Ok(()) + } +} diff --git a/packages/rs-sdk/src/platform/transition/unshield.rs b/packages/rs-sdk/src/platform/transition/unshield.rs new file mode 100644 index 00000000000..07cc28a025d --- /dev/null +++ b/packages/rs-sdk/src/platform/transition/unshield.rs @@ -0,0 +1,66 @@ +use super::broadcast::BroadcastStateTransition; +use super::put_settings::PutSettings; +use super::validation::ensure_valid_state_transition_structure; +use crate::{Error, Sdk}; +use dpp::address_funds::PlatformAddress; +use dpp::shielded::SerializedAction; +use dpp::state_transition::unshield_transition::methods::UnshieldTransitionMethodsV0; +use dpp::state_transition::unshield_transition::UnshieldTransition; + +/// Helper trait to unshield funds from the shielded pool to a platform address. +#[async_trait::async_trait] +pub trait UnshieldFunds { + /// Unshield funds from the shielded pool to a platform address. + /// Authentication is via Orchard spend authorization signatures in the bundle actions. + #[allow(clippy::too_many_arguments)] + async fn unshield_funds( + &self, + output_address: PlatformAddress, + amount: u64, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + settings: Option, + ) -> Result<(), Error>; +} + +#[async_trait::async_trait] +impl UnshieldFunds for Sdk { + async fn unshield_funds( + &self, + output_address: PlatformAddress, + amount: u64, + actions: Vec, + flags: u8, + value_balance: i64, + anchor: [u8; 32], + proof: Vec, + binding_signature: [u8; 64], + settings: Option, + ) -> Result<(), Error> { + let user_fee_increase = settings + .as_ref() + .and_then(|s| s.user_fee_increase) + .unwrap_or_default(); + + let state_transition = UnshieldTransition::try_from_bundle( + output_address, + amount, + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + user_fee_increase, + self.version(), + )?; + ensure_valid_state_transition_structure(&state_transition, self.version())?; + + state_transition.broadcast(self, settings).await?; + Ok(()) + } +} diff --git a/packages/strategy-tests/src/lib.rs b/packages/strategy-tests/src/lib.rs index 3a66119b895..88547b34c3d 100644 --- a/packages/strategy-tests/src/lib.rs +++ b/packages/strategy-tests/src/lib.rs @@ -2615,6 +2615,20 @@ impl Strategy { } } + OperationType::Shield(_amount_range) => { + // TODO: Shielded transitions require client-side Orchard bundle building + // (ProvingKey ~30s, commitment tree tracking). Not yet implemented in + // strategy tests. Individual validation tests in drive-abci provide coverage. + } + OperationType::ShieldedTransfer(_amount_range) => { + // TODO: Requires Orchard bundle building — not yet implemented in + // strategy tests. + } + OperationType::Unshield(_amount_range) => { + // TODO: Requires Orchard bundle building — not yet implemented in + // strategy tests. + } + _ => {} } } diff --git a/packages/strategy-tests/src/operations.rs b/packages/strategy-tests/src/operations.rs index b4b89bfd872..42d6c40dc3a 100644 --- a/packages/strategy-tests/src/operations.rs +++ b/packages/strategy-tests/src/operations.rs @@ -852,6 +852,15 @@ pub enum OperationType { KeyCount, ExtraKeys, ), + + /// Shield funds into the shielded pool (requires Orchard bundle). + Shield(AmountRange), + + /// Transfer within the shielded pool (requires Orchard bundle). + ShieldedTransfer(AmountRange), + + /// Unshield from the shielded pool to a platform address (requires Orchard bundle). + Unshield(AmountRange), } #[allow(clippy::large_enum_variant)] @@ -892,6 +901,9 @@ enum OperationTypeInSerializationFormat { KeyCount, ExtraKeys, ), + Shield(AmountRange), + ShieldedTransfer(AmountRange), + Unshield(AmountRange), } impl PlatformSerializableWithPlatformVersion for OperationType { @@ -997,6 +1009,15 @@ impl PlatformSerializableWithPlatformVersion for OperationType { key_count, extra_keys, ), + OperationType::Shield(range) => { + OperationTypeInSerializationFormat::Shield(range) + } + OperationType::ShieldedTransfer(range) => { + OperationTypeInSerializationFormat::ShieldedTransfer(range) + } + OperationType::Unshield(range) => { + OperationTypeInSerializationFormat::Unshield(range) + } }; let config = bincode::config::standard() .with_big_endian() @@ -1115,6 +1136,15 @@ impl PlatformDeserializableWithPotentialValidationFromVersionedStructure for Ope key_count, extra_keys, ), + OperationTypeInSerializationFormat::Shield(range) => { + OperationType::Shield(range) + } + OperationTypeInSerializationFormat::ShieldedTransfer(range) => { + OperationType::ShieldedTransfer(range) + } + OperationTypeInSerializationFormat::Unshield(range) => { + OperationType::Unshield(range) + } }) } } diff --git a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs index 429a94b1a4f..fe3714fbdc2 100644 --- a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs +++ b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs @@ -88,7 +88,8 @@ use dpp::consensus::state::prefunded_specialized_balances::prefunded_specialized use dpp::consensus::state::prefunded_specialized_balances::prefunded_specialized_balance_not_found_error::PrefundedSpecializedBalanceNotFoundError; use dpp::consensus::state::token::{IdentityDoesNotHaveEnoughTokenBalanceError, IdentityTokenAccountNotFrozenError, IdentityTokenAccountFrozenError, TokenIsPausedError, IdentityTokenAccountAlreadyFrozenError, UnauthorizedTokenActionError, TokenSettingMaxSupplyToLessThanCurrentSupplyError, TokenMintPastMaxSupplyError, NewTokensDestinationIdentityDoesNotExistError, NewAuthorizedActionTakerIdentityDoesNotExistError, NewAuthorizedActionTakerGroupDoesNotExistError, NewAuthorizedActionTakerMainGroupNotSetError, InvalidGroupPositionError, TokenAlreadyPausedError, TokenNotPausedError, InvalidTokenClaimPropertyMismatch, InvalidTokenClaimNoCurrentRewards, InvalidTokenClaimWrongClaimant, TokenTransferRecipientIdentityNotExistError, PreProgrammedDistributionTimestampInPastError, IdentityHasNotAgreedToPayRequiredTokenAmountError, RequiredTokenPaymentInfoNotSetError, IdentityTryingToPayWithWrongTokenError, TokenDirectPurchaseUserPriceTooLow, TokenAmountUnderMinimumSaleAmount, TokenNotForDirectSale, InvalidTokenPositionStateError}; use dpp::consensus::state::address_funds::{AddressDoesNotExistError, AddressInvalidNonceError, AddressNotEnoughFundsError, AddressesNotEnoughFundsError}; -use dpp::consensus::basic::state_transition::{StateTransitionNotActiveError, TransitionOverMaxInputsError, TransitionOverMaxOutputsError, InputWitnessCountMismatchError, TransitionNoInputsError, TransitionNoOutputsError, FeeStrategyEmptyError, FeeStrategyDuplicateError, FeeStrategyIndexOutOfBoundsError, FeeStrategyTooManyStepsError, InputBelowMinimumError, OutputBelowMinimumError, InputOutputBalanceMismatchError, OutputsNotGreaterThanInputsError, WithdrawalBalanceMismatchError, InsufficientFundingAmountError, InputsNotLessThanOutputsError, OutputAddressAlsoInputError, InvalidRemainderOutputCountError, WithdrawalBelowMinAmountError}; +use dpp::consensus::state::shielded::{InvalidAnchorError, InvalidShieldedProofError, NullifierAlreadySpentError}; +use dpp::consensus::basic::state_transition::{StateTransitionNotActiveError, TransitionOverMaxInputsError, TransitionOverMaxOutputsError, InputWitnessCountMismatchError, TransitionNoInputsError, TransitionNoOutputsError, FeeStrategyEmptyError, FeeStrategyDuplicateError, FeeStrategyIndexOutOfBoundsError, FeeStrategyTooManyStepsError, InputBelowMinimumError, OutputBelowMinimumError, InputOutputBalanceMismatchError, OutputsNotGreaterThanInputsError, WithdrawalBalanceMismatchError, InsufficientFundingAmountError, InputsNotLessThanOutputsError, OutputAddressAlsoInputError, InvalidRemainderOutputCountError, WithdrawalBelowMinAmountError, ShieldedNoActionsError, ShieldedEmptyProofError, ShieldedZeroAnchorError, ShieldedInvalidValueBalanceError, UnshieldAmountZeroError, UnshieldValueBalanceBelowAmountError}; use dpp::consensus::state::voting::masternode_incorrect_voter_identity_id_error::MasternodeIncorrectVoterIdentityIdError; use dpp::consensus::state::voting::masternode_incorrect_voting_address_error::MasternodeIncorrectVotingAddressError; use dpp::consensus::state::voting::masternode_not_found_error::MasternodeNotFoundError; @@ -443,6 +444,15 @@ pub fn from_state_error(state_error: &StateError) -> JsValue { StateError::AddressInvalidNonceError(e) => { generic_consensus_error!(AddressInvalidNonceError, e).into() } + StateError::InvalidAnchorError(e) => { + generic_consensus_error!(InvalidAnchorError, e).into() + } + StateError::NullifierAlreadySpentError(e) => { + generic_consensus_error!(NullifierAlreadySpentError, e).into() + } + StateError::InvalidShieldedProofError(e) => { + generic_consensus_error!(InvalidShieldedProofError, e).into() + } } } @@ -923,6 +933,24 @@ fn from_basic_error(basic_error: &BasicError) -> JsValue { BasicError::WithdrawalBelowMinAmountError(e) => { generic_consensus_error!(WithdrawalBelowMinAmountError, e).into() } + BasicError::ShieldedNoActionsError(e) => { + generic_consensus_error!(ShieldedNoActionsError, e).into() + } + BasicError::ShieldedEmptyProofError(e) => { + generic_consensus_error!(ShieldedEmptyProofError, e).into() + } + BasicError::ShieldedZeroAnchorError(e) => { + generic_consensus_error!(ShieldedZeroAnchorError, e).into() + } + BasicError::ShieldedInvalidValueBalanceError(e) => { + generic_consensus_error!(ShieldedInvalidValueBalanceError, e).into() + } + BasicError::UnshieldAmountZeroError(e) => { + generic_consensus_error!(UnshieldAmountZeroError, e).into() + } + BasicError::UnshieldValueBalanceBelowAmountError(e) => { + generic_consensus_error!(UnshieldValueBalanceBelowAmountError, e).into() + } } } diff --git a/packages/wasm-dpp/src/identity/state_transition/transition_types.rs b/packages/wasm-dpp/src/identity/state_transition/transition_types.rs index 37fe3d2626f..632a2f5a143 100644 --- a/packages/wasm-dpp/src/identity/state_transition/transition_types.rs +++ b/packages/wasm-dpp/src/identity/state_transition/transition_types.rs @@ -19,6 +19,11 @@ pub enum StateTransitionTypeWasm { AddressFundsTransfer = 12, AddressFundingFromAssetLock = 13, AddressCreditWithdrawal = 14, + Shield = 15, + ShieldedTransfer = 16, + Unshield = 17, + ShieldFromAssetLock = 18, + ShieldedWithdrawal = 19, } impl From for StateTransitionTypeWasm { @@ -55,6 +60,11 @@ impl From for StateTransitionTypeWasm { StateTransitionType::AddressCreditWithdrawal => { StateTransitionTypeWasm::AddressCreditWithdrawal } + StateTransitionType::Shield => StateTransitionTypeWasm::Shield, + StateTransitionType::ShieldedTransfer => StateTransitionTypeWasm::ShieldedTransfer, + StateTransitionType::Unshield => StateTransitionTypeWasm::Unshield, + StateTransitionType::ShieldFromAssetLock => StateTransitionTypeWasm::ShieldFromAssetLock, + StateTransitionType::ShieldedWithdrawal => StateTransitionTypeWasm::ShieldedWithdrawal, } } } diff --git a/packages/wasm-dpp/src/state_transition/state_transition_factory.rs b/packages/wasm-dpp/src/state_transition/state_transition_factory.rs index c140f0e7ea6..689b3d3501d 100644 --- a/packages/wasm-dpp/src/state_transition/state_transition_factory.rs +++ b/packages/wasm-dpp/src/state_transition/state_transition_factory.rs @@ -79,6 +79,21 @@ impl StateTransitionFactoryWasm { StateTransition::AddressCreditWithdrawal(st) => { serde_wasm_bindgen::to_value(&st).map_err(|e| JsValue::from(e.to_string())) } + StateTransition::Shield(st) => { + serde_wasm_bindgen::to_value(&st).map_err(|e| JsValue::from(e.to_string())) + } + StateTransition::ShieldedTransfer(st) => { + serde_wasm_bindgen::to_value(&st).map_err(|e| JsValue::from(e.to_string())) + } + StateTransition::Unshield(st) => { + serde_wasm_bindgen::to_value(&st).map_err(|e| JsValue::from(e.to_string())) + } + StateTransition::ShieldFromAssetLock(st) => { + serde_wasm_bindgen::to_value(&st).map_err(|e| JsValue::from(e.to_string())) + } + StateTransition::ShieldedWithdrawal(st) => { + serde_wasm_bindgen::to_value(&st).map_err(|e| JsValue::from(e.to_string())) + } }, Err(dpp::ProtocolError::StateTransitionError(e)) => match e { StateTransitionError::InvalidStateTransitionError { diff --git a/packages/wasm-dpp2/src/state_transitions/base/state_transition.rs b/packages/wasm-dpp2/src/state_transitions/base/state_transition.rs index 2cd140ac40c..c78cd77c8db 100644 --- a/packages/wasm-dpp2/src/state_transitions/base/state_transition.rs +++ b/packages/wasm-dpp2/src/state_transitions/base/state_transition.rs @@ -308,6 +308,11 @@ impl StateTransitionWasm { AddressFundsTransfer(_) => 12, AddressFundingFromAssetLock(_) => 13, AddressCreditWithdrawal(_) => 14, + Shield(_) => 15, + ShieldedTransfer(_) => 16, + Unshield(_) => 17, + ShieldFromAssetLock(_) => 18, + ShieldedWithdrawal(_) => 19, } } @@ -391,7 +396,12 @@ impl StateTransitionWasm { | IdentityTopUpFromAddresses(_) | AddressFundsTransfer(_) | AddressFundingFromAssetLock(_) - | AddressCreditWithdrawal(_) => None, + | AddressCreditWithdrawal(_) + | Shield(_) + | ShieldedTransfer(_) + | Unshield(_) + | ShieldFromAssetLock(_) + | ShieldedWithdrawal(_) => None, } } @@ -413,7 +423,12 @@ impl StateTransitionWasm { IdentityTopUpFromAddresses(_) => None, AddressFundsTransfer(_) | AddressFundingFromAssetLock(_) - | AddressCreditWithdrawal(_) => None, + | AddressCreditWithdrawal(_) + | Shield(_) + | ShieldedTransfer(_) + | Unshield(_) + | ShieldFromAssetLock(_) + | ShieldedWithdrawal(_) => None, } } @@ -551,6 +566,15 @@ impl StateTransitionWasm { "Cannot set owner for address funds transfer transition", )); } + Shield(_) + | ShieldedTransfer(_) + | Unshield(_) + | ShieldFromAssetLock(_) + | ShieldedWithdrawal(_) => { + return Err(WasmDppError::invalid_argument( + "Cannot set owner for shielded transition", + )); + } }; Ok(()) @@ -614,9 +638,14 @@ impl StateTransitionWasm { | IdentityTopUpFromAddresses(_) | AddressFundsTransfer(_) | AddressFundingFromAssetLock(_) - | AddressCreditWithdrawal(_) => { + | AddressCreditWithdrawal(_) + | Shield(_) + | ShieldedTransfer(_) + | Unshield(_) + | ShieldFromAssetLock(_) + | ShieldedWithdrawal(_) => { return Err(WasmDppError::invalid_argument( - "Cannot set identity contract nonce for address-related transition types", + "Cannot set identity contract nonce for this transition type", )); } }; @@ -702,9 +731,14 @@ impl StateTransitionWasm { } AddressFundsTransfer(_) | AddressFundingFromAssetLock(_) - | AddressCreditWithdrawal(_) => { + | AddressCreditWithdrawal(_) + | Shield(_) + | ShieldedTransfer(_) + | Unshield(_) + | ShieldFromAssetLock(_) + | ShieldedWithdrawal(_) => { return Err(WasmDppError::invalid_argument( - "Cannot set identity nonce for address-related transition types", + "Cannot set identity nonce for this transition type", )); } }; From fc3ef9bcd7256bea5e15264168823f7569905288 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 11 Feb 2026 20:56:37 +0000 Subject: [PATCH 11/40] more work --- .../src/SDK/Client/Platform/Platform.ts | 26 +++ .../Platform/methods/shielded/shield.ts | 38 ++++ .../methods/shielded/shieldFromAssetLock.ts | 39 ++++ .../methods/shielded/shieldedTransfer.ts | 41 ++++ .../methods/shielded/shieldedWithdrawal.ts | 41 ++++ .../Platform/methods/shielded/unshield.ts | 41 ++++ .../methods/mod.rs | 3 +- .../methods/v0/mod.rs | 6 +- .../v0/mod.rs | 2 +- .../v0/v0_methods.rs | 6 +- .../methods/v0/mod.rs | 6 +- .../v0/v0_methods.rs | 6 +- .../methods/v0/mod.rs | 6 +- .../v0/v0_methods.rs | 6 +- .../unshield_transition/methods/mod.rs | 4 +- .../unshield_transition/methods/v0/mod.rs | 6 +- .../unshield_transition/v0/v0_methods.rs | 6 +- .../shield_from_asset_lock/tests.rs | 6 +- .../shielded_withdrawal/tests.rs | 22 +-- .../v0/mod.rs | 6 +- packages/rs-sdk/src/platform/transition.rs | 2 +- .../transition/shield_from_asset_lock.rs | 25 ++- packages/strategy-tests/src/lib.rs | 25 +-- packages/strategy-tests/src/operations.rs | 32 +++- .../src/errors/consensus/consensus_error.rs | 4 +- .../state_transition/transition_types.rs | 4 +- packages/wasm-dpp/src/lib.rs | 2 + packages/wasm-dpp/src/shielded/mod.rs | 42 +++++ .../shield_from_asset_lock_transition.rs | 162 ++++++++++++++++ .../src/shielded/shield_transition.rs | 171 +++++++++++++++++ .../shielded/shielded_transfer_transition.rs | 144 ++++++++++++++ .../shielded_withdrawal_transition.rs | 177 ++++++++++++++++++ .../src/shielded/unshield_transition.rs | 160 ++++++++++++++++ .../state_transition_factory.rs | 18 +- 34 files changed, 1173 insertions(+), 112 deletions(-) create mode 100644 packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shield.ts create mode 100644 packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shieldFromAssetLock.ts create mode 100644 packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shieldedTransfer.ts create mode 100644 packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shieldedWithdrawal.ts create mode 100644 packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/unshield.ts create mode 100644 packages/wasm-dpp/src/shielded/mod.rs create mode 100644 packages/wasm-dpp/src/shielded/shield_from_asset_lock_transition.rs create mode 100644 packages/wasm-dpp/src/shielded/shield_transition.rs create mode 100644 packages/wasm-dpp/src/shielded/shielded_transfer_transition.rs create mode 100644 packages/wasm-dpp/src/shielded/shielded_withdrawal_transition.rs create mode 100644 packages/wasm-dpp/src/shielded/unshield_transition.rs diff --git a/packages/js-dash-sdk/src/SDK/Client/Platform/Platform.ts b/packages/js-dash-sdk/src/SDK/Client/Platform/Platform.ts index 873fe62c53d..0539c8365f8 100644 --- a/packages/js-dash-sdk/src/SDK/Client/Platform/Platform.ts +++ b/packages/js-dash-sdk/src/SDK/Client/Platform/Platform.ts @@ -34,6 +34,12 @@ import resolveNameByRecord from './methods/names/resolveByRecord'; import searchName from './methods/names/search'; import broadcastStateTransition from './broadcastStateTransition'; +import shieldMethod from './methods/shielded/shield'; +import shieldedTransferMethod from './methods/shielded/shieldedTransfer'; +import unshieldMethod from './methods/shielded/unshield'; +import shieldFromAssetLockMethod from './methods/shielded/shieldFromAssetLock'; +import shieldedWithdrawalMethod from './methods/shielded/shieldedWithdrawal'; + import logger, { ConfigurableLogger } from '../../../logger'; import Fetcher from './Fetcher'; import NonceManager from './NonceManager/NonceManager'; @@ -98,6 +104,14 @@ interface DataContracts { history: Function, } +interface Shielded { + shield: Function, + shieldedTransfer: Function, + unshield: Function, + shieldFromAssetLock: Function, + shieldedWithdrawal: Function, +} + /** * Class for Dash Platform * @@ -117,6 +131,11 @@ export class Platform { public documents: Records; + /** + * Shielded pool operations (shield, transfer, unshield) + */ + public shielded: Shielded; + /** * @param {Function} get - get identities from the platform * @param {Function} register - register identities on the platform @@ -180,6 +199,13 @@ export class Platform { resolveByRecord: resolveNameByRecord.bind(this), search: searchName.bind(this), }; + this.shielded = { + shield: shieldMethod.bind(this), + shieldedTransfer: shieldedTransferMethod.bind(this), + unshield: unshieldMethod.bind(this), + shieldFromAssetLock: shieldFromAssetLockMethod.bind(this), + shieldedWithdrawal: shieldedWithdrawalMethod.bind(this), + }; this.identities = { register: registerIdentity.bind(this), get: getIdentity.bind(this), diff --git a/packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shield.ts b/packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shield.ts new file mode 100644 index 00000000000..5391cb205e8 --- /dev/null +++ b/packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shield.ts @@ -0,0 +1,38 @@ +import broadcastStateTransition from '../../broadcastStateTransition'; +import { Platform } from '../../Platform'; +import { IStateTransitionResult } from '../../IStateTransitionResult'; + +/** + * Broadcast a shield transition (transparent platform addresses -> shielded pool). + * + * The Orchard bundle, platform address witnesses, and full state transition + * must be built externally (e.g., via rs-sdk's `shield_funds()` or a native + * wallet library) and serialized to platform binary format. + * + * @param serializedTransition - Platform-serialized ShieldTransition bytes + * @returns Broadcast result + */ +export async function shield( + this: Platform, + serializedTransition: Uint8Array, +): Promise { + this.logger.debug('[Shielded#shield] Broadcasting shield transition'); + await this.initialize(); + + const { dpp } = this; + + const transition = dpp.stateTransition.createFromBuffer( + serializedTransition, + {}, + ); + + const result = await broadcastStateTransition(this, await transition, { + skipValidation: true, + }); + + this.logger.silly('[Shielded#shield] Broadcasted ShieldTransition'); + + return result; +} + +export default shield; diff --git a/packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shieldFromAssetLock.ts b/packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shieldFromAssetLock.ts new file mode 100644 index 00000000000..95e4b1cd1a8 --- /dev/null +++ b/packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shieldFromAssetLock.ts @@ -0,0 +1,39 @@ +import broadcastStateTransition from '../../broadcastStateTransition'; +import { Platform } from '../../Platform'; +import { IStateTransitionResult } from '../../IStateTransitionResult'; + +/** + * Broadcast a shield-from-asset-lock transition (core asset lock -> shielded pool). + * + * The Orchard bundle, asset lock proof, ECDSA signature, and full state + * transition must be built externally (e.g., via rs-sdk's + * `shield_from_asset_lock()` or a native wallet library) and serialized + * to platform binary format. + * + * @param serializedTransition - Platform-serialized ShieldFromAssetLockTransition bytes + * @returns Broadcast result + */ +export async function shieldFromAssetLock( + this: Platform, + serializedTransition: Uint8Array, +): Promise { + this.logger.debug('[Shielded#shieldFromAssetLock] Broadcasting shield from asset lock'); + await this.initialize(); + + const { dpp } = this; + + const transition = dpp.stateTransition.createFromBuffer( + serializedTransition, + {}, + ); + + const result = await broadcastStateTransition(this, await transition, { + skipValidation: true, + }); + + this.logger.silly('[Shielded#shieldFromAssetLock] Broadcasted ShieldFromAssetLockTransition'); + + return result; +} + +export default shieldFromAssetLock; diff --git a/packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shieldedTransfer.ts b/packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shieldedTransfer.ts new file mode 100644 index 00000000000..81f68a4aaff --- /dev/null +++ b/packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shieldedTransfer.ts @@ -0,0 +1,41 @@ +import broadcastStateTransition from '../../broadcastStateTransition'; +import { Platform } from '../../Platform'; +import { IStateTransitionResult } from '../../IStateTransitionResult'; + +/** + * Broadcast a shielded transfer (shielded-to-shielded) transition. + * + * The Orchard bundle and full state transition must be built externally + * (e.g., via rs-sdk's `transfer_shielded()` or a native wallet library) + * and serialized to platform binary format before passing here. + * + * Authentication is provided entirely by Orchard spend authorization + * signatures within the bundle — no identity signing needed. + * + * @param serializedTransition - Platform-serialized ShieldedTransferTransition bytes + * @returns Broadcast result + */ +export async function shieldedTransfer( + this: Platform, + serializedTransition: Uint8Array, +): Promise { + this.logger.debug('[Shielded#shieldedTransfer] Broadcasting shielded transfer'); + await this.initialize(); + + const { dpp } = this; + + const transition = dpp.stateTransition.createFromBuffer( + serializedTransition, + {}, + ); + + const result = await broadcastStateTransition(this, await transition, { + skipValidation: true, + }); + + this.logger.silly('[Shielded#shieldedTransfer] Broadcasted ShieldedTransferTransition'); + + return result; +} + +export default shieldedTransfer; diff --git a/packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shieldedWithdrawal.ts b/packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shieldedWithdrawal.ts new file mode 100644 index 00000000000..fb6e47b63bf --- /dev/null +++ b/packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/shieldedWithdrawal.ts @@ -0,0 +1,41 @@ +import broadcastStateTransition from '../../broadcastStateTransition'; +import { Platform } from '../../Platform'; +import { IStateTransitionResult } from '../../IStateTransitionResult'; + +/** + * Broadcast a shielded withdrawal transition (shielded pool -> core L1 address). + * + * The Orchard bundle and full state transition must be built externally + * (e.g., via rs-sdk's `withdraw_shielded()` or a native wallet library) + * and serialized to platform binary format. + * + * The platform sighash binds `outputScript || amount` to prevent + * an attacker from substituting a different L1 destination or amount. + * + * @param serializedTransition - Platform-serialized ShieldedWithdrawalTransition bytes + * @returns Broadcast result + */ +export async function shieldedWithdrawal( + this: Platform, + serializedTransition: Uint8Array, +): Promise { + this.logger.debug('[Shielded#shieldedWithdrawal] Broadcasting shielded withdrawal'); + await this.initialize(); + + const { dpp } = this; + + const transition = dpp.stateTransition.createFromBuffer( + serializedTransition, + {}, + ); + + const result = await broadcastStateTransition(this, await transition, { + skipValidation: true, + }); + + this.logger.silly('[Shielded#shieldedWithdrawal] Broadcasted ShieldedWithdrawalTransition'); + + return result; +} + +export default shieldedWithdrawal; diff --git a/packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/unshield.ts b/packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/unshield.ts new file mode 100644 index 00000000000..95eb4636601 --- /dev/null +++ b/packages/js-dash-sdk/src/SDK/Client/Platform/methods/shielded/unshield.ts @@ -0,0 +1,41 @@ +import broadcastStateTransition from '../../broadcastStateTransition'; +import { Platform } from '../../Platform'; +import { IStateTransitionResult } from '../../IStateTransitionResult'; + +/** + * Broadcast an unshield transition (shielded pool -> platform address). + * + * The Orchard bundle and full state transition must be built externally + * (e.g., via rs-sdk's `unshield_funds()` or a native wallet library) + * and serialized to platform binary format. + * + * The platform sighash binds `outputAddress || amount` to prevent + * an attacker from substituting a different destination or amount. + * + * @param serializedTransition - Platform-serialized UnshieldTransition bytes + * @returns Broadcast result + */ +export async function unshield( + this: Platform, + serializedTransition: Uint8Array, +): Promise { + this.logger.debug('[Shielded#unshield] Broadcasting unshield transition'); + await this.initialize(); + + const { dpp } = this; + + const transition = dpp.stateTransition.createFromBuffer( + serializedTransition, + {}, + ); + + const result = await broadcastStateTransition(this, await transition, { + skipValidation: true, + }); + + this.logger.silly('[Shielded#unshield] Broadcasted UnshieldTransition'); + + return result; +} + +export default unshield; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/methods/mod.rs index 6297af5de23..5b5288351aa 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/methods/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/methods/mod.rs @@ -51,7 +51,8 @@ impl ShieldFromAssetLockTransitionMethodsV0 for ShieldFromAssetLockTransition { platform_version, ), version => Err(ProtocolError::UnknownVersionMismatch { - method: "ShieldFromAssetLockTransition::try_from_asset_lock_with_bundle".to_string(), + method: "ShieldFromAssetLockTransition::try_from_asset_lock_with_bundle" + .to_string(), known_versions: vec![0], received: version, }), diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/methods/v0/mod.rs index 7d02ce85d2a..49fbb3f59d4 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/methods/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/methods/v0/mod.rs @@ -4,11 +4,7 @@ use crate::prelude::AssetLockProof; use crate::shielded::SerializedAction; use crate::state_transition::StateTransitionType; #[cfg(feature = "state-transition-signing")] -use crate::{ - prelude::UserFeeIncrease, - state_transition::StateTransition, - ProtocolError, -}; +use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; #[cfg(feature = "state-transition-signing")] use platform_version::version::PlatformVersion; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs index 8cf2999274e..f2faf935a67 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs @@ -2,8 +2,8 @@ mod proved; mod state_transition_like; mod state_transition_validation; mod types; -mod version; mod v0_methods; +mod version; use crate::identity::state_transition::asset_lock_proof::AssetLockProof; use crate::prelude::UserFeeIncrease; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/v0_methods.rs index 793206ce0af..baafa61a098 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/v0_methods.rs @@ -7,11 +7,7 @@ use crate::shielded::SerializedAction; use crate::state_transition::shield_from_asset_lock_transition::methods::ShieldFromAssetLockTransitionMethodsV0; use crate::state_transition::shield_from_asset_lock_transition::v0::ShieldFromAssetLockTransitionV0; #[cfg(feature = "state-transition-signing")] -use crate::{ - prelude::UserFeeIncrease, - state_transition::StateTransition, - ProtocolError, -}; +use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; #[cfg(feature = "state-transition-signing")] use dashcore::signer; #[cfg(feature = "state-transition-signing")] diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/v0/mod.rs index 439fe8ba746..a72f656d871 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/v0/mod.rs @@ -1,10 +1,6 @@ use crate::shielded::SerializedAction; use crate::state_transition::StateTransitionType; -use crate::{ - prelude::UserFeeIncrease, - state_transition::StateTransition, - ProtocolError, -}; +use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; use platform_version::version::PlatformVersion; pub trait ShieldedTransferTransitionMethodsV0 { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/v0_methods.rs index e75a32b79d1..006bbe015f0 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/v0_methods.rs @@ -1,11 +1,7 @@ use crate::shielded::SerializedAction; use crate::state_transition::shielded_transfer_transition::methods::ShieldedTransferTransitionMethodsV0; use crate::state_transition::shielded_transfer_transition::v0::ShieldedTransferTransitionV0; -use crate::{ - prelude::UserFeeIncrease, - state_transition::StateTransition, - ProtocolError, -}; +use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; use platform_version::version::PlatformVersion; impl ShieldedTransferTransitionMethodsV0 for ShieldedTransferTransitionV0 { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/v0/mod.rs index bd47247fa33..8781b68ff8a 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/v0/mod.rs @@ -2,11 +2,7 @@ use crate::identity::core_script::CoreScript; use crate::shielded::SerializedAction; use crate::state_transition::StateTransitionType; use crate::withdrawal::Pooling; -use crate::{ - prelude::UserFeeIncrease, - state_transition::StateTransition, - ProtocolError, -}; +use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; use platform_version::version::PlatformVersion; pub trait ShieldedWithdrawalTransitionMethodsV0 { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/v0_methods.rs index b0871cb1154..60ff12e632c 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/v0_methods.rs @@ -3,11 +3,7 @@ use crate::shielded::SerializedAction; use crate::state_transition::shielded_withdrawal_transition::methods::ShieldedWithdrawalTransitionMethodsV0; use crate::state_transition::shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0; use crate::withdrawal::Pooling; -use crate::{ - prelude::UserFeeIncrease, - state_transition::StateTransition, - ProtocolError, -}; +use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; use platform_version::version::PlatformVersion; impl ShieldedWithdrawalTransitionMethodsV0 for ShieldedWithdrawalTransitionV0 { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/mod.rs index 5182b08cf91..8ba9d1040c8 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/mod.rs @@ -7,9 +7,7 @@ use crate::shielded::SerializedAction; use crate::state_transition::unshield_transition::UnshieldTransition; use crate::{ prelude::UserFeeIncrease, - state_transition::{ - unshield_transition::v0::UnshieldTransitionV0, StateTransition, - }, + state_transition::{unshield_transition::v0::UnshieldTransitionV0, StateTransition}, ProtocolError, }; use platform_version::version::PlatformVersion; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/v0/mod.rs index 5639a46fe0c..2765518cb79 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/v0/mod.rs @@ -1,11 +1,7 @@ use crate::address_funds::PlatformAddress; use crate::shielded::SerializedAction; use crate::state_transition::StateTransitionType; -use crate::{ - prelude::UserFeeIncrease, - state_transition::StateTransition, - ProtocolError, -}; +use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; use platform_version::version::PlatformVersion; pub trait UnshieldTransitionMethodsV0 { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/v0_methods.rs index cbdb15af589..95b1f1231c9 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/v0_methods.rs @@ -2,11 +2,7 @@ use crate::address_funds::PlatformAddress; use crate::shielded::SerializedAction; use crate::state_transition::unshield_transition::methods::UnshieldTransitionMethodsV0; use crate::state_transition::unshield_transition::v0::UnshieldTransitionV0; -use crate::{ - prelude::UserFeeIncrease, - state_transition::StateTransition, - ProtocolError, -}; +use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; use platform_version::version::PlatformVersion; impl UnshieldTransitionMethodsV0 for UnshieldTransitionV0 { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs index 2853ecb52f8..bd15d5f3076 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs @@ -381,9 +381,9 @@ mod tests { vec![create_dummy_serialized_action()], 0x03, // spends_enabled | outputs_enabled value_balance, - [0u8; 32], // dummy anchor - vec![0u8; 100], // dummy proof bytes - [0u8; 64], // dummy binding signature + [0u8; 32], // dummy anchor + vec![0u8; 100], // dummy proof bytes + [0u8; 64], // dummy binding signature 0, ); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs index 00f8cac5755..61e38554169 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs @@ -83,17 +83,17 @@ mod tests { /// value_balance. fn create_default_shielded_withdrawal_transition() -> StateTransition { create_shielded_withdrawal_transition( - 1000, // amount in credits + 1000, // amount in credits vec![create_dummy_serialized_action()], - 0x03, // spends_enabled | outputs_enabled - 1000, // value_balance = amount (no fee for simplicity) - [42u8; 32], // non-zero anchor - vec![0u8; 100], // dummy proof bytes - [0u8; 64], // dummy binding signature - 1, // core_fee_per_byte - Pooling::Never, // pooling strategy - create_output_script(), // P2PKH output script - 0, // user_fee_increase + 0x03, // spends_enabled | outputs_enabled + 1000, // value_balance = amount (no fee for simplicity) + [42u8; 32], // non-zero anchor + vec![0u8; 100], // dummy proof bytes + [0u8; 64], // dummy binding signature + 1, // core_fee_per_byte + Pooling::Never, // pooling strategy + create_output_script(), // P2PKH output script + 0, // user_fee_increase ) } @@ -668,7 +668,7 @@ mod tests { 1, // core_fee_per_byte Pooling::Never, // pooling strategy output_script, - 0, // user_fee_increase + 0, // user_fee_increase ); let processing_result = process_transition(&platform, transition, platform_version); diff --git a/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs b/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs index a4129376001..acca12740f9 100644 --- a/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs +++ b/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs @@ -1147,10 +1147,8 @@ impl Drive { StateTransition::ShieldedTransfer(_) | StateTransition::ShieldFromAssetLock(_) | StateTransition::ShieldedWithdrawal(_) => { - let (root_hash, pool_balance) = Drive::verify_shielded_pool_state( - proof, - platform_version, - )?; + let (root_hash, pool_balance) = + Drive::verify_shielded_pool_state(proof, platform_version)?; Ok((root_hash, VerifiedShieldedPoolState(pool_balance))) } } diff --git a/packages/rs-sdk/src/platform/transition.rs b/packages/rs-sdk/src/platform/transition.rs index 10196dac0fa..e7e8388fae5 100644 --- a/packages/rs-sdk/src/platform/transition.rs +++ b/packages/rs-sdk/src/platform/transition.rs @@ -20,8 +20,8 @@ pub mod transfer; pub mod transfer_address_funds; pub mod transfer_document; pub mod transfer_to_addresses; -pub mod unshield; mod txid; +pub mod unshield; pub mod update_price_of_document; pub(crate) mod validation; pub mod vote; diff --git a/packages/rs-sdk/src/platform/transition/shield_from_asset_lock.rs b/packages/rs-sdk/src/platform/transition/shield_from_asset_lock.rs index fbc1f6953c2..0629f3b3606 100644 --- a/packages/rs-sdk/src/platform/transition/shield_from_asset_lock.rs +++ b/packages/rs-sdk/src/platform/transition/shield_from_asset_lock.rs @@ -47,19 +47,18 @@ impl ShieldFromAssetLock for Sdk { .and_then(|s| s.user_fee_increase) .unwrap_or_default(); - let state_transition = - ShieldFromAssetLockTransition::try_from_asset_lock_with_bundle( - asset_lock_proof, - asset_lock_proof_private_key, - actions, - flags, - value_balance, - anchor, - proof, - binding_signature, - user_fee_increase, - self.version(), - )?; + let state_transition = ShieldFromAssetLockTransition::try_from_asset_lock_with_bundle( + asset_lock_proof, + asset_lock_proof_private_key, + actions, + flags, + value_balance, + anchor, + proof, + binding_signature, + user_fee_increase, + self.version(), + )?; ensure_valid_state_transition_structure(&state_transition, self.version())?; state_transition.broadcast(self, settings).await?; diff --git a/packages/strategy-tests/src/lib.rs b/packages/strategy-tests/src/lib.rs index 88547b34c3d..e760d8cd9cb 100644 --- a/packages/strategy-tests/src/lib.rs +++ b/packages/strategy-tests/src/lib.rs @@ -2615,18 +2615,19 @@ impl Strategy { } } - OperationType::Shield(_amount_range) => { - // TODO: Shielded transitions require client-side Orchard bundle building - // (ProvingKey ~30s, commitment tree tracking). Not yet implemented in - // strategy tests. Individual validation tests in drive-abci provide coverage. - } - OperationType::ShieldedTransfer(_amount_range) => { - // TODO: Requires Orchard bundle building — not yet implemented in - // strategy tests. - } - OperationType::Unshield(_amount_range) => { - // TODO: Requires Orchard bundle building — not yet implemented in - // strategy tests. + OperationType::Shield(_amount_range) + | OperationType::ShieldedTransfer(_amount_range) + | OperationType::Unshield(_amount_range) + | OperationType::ShieldFromAssetLock(_amount_range) + | OperationType::ShieldedWithdrawal(_amount_range) => { + // Shielded transitions require client-side Orchard bundle + // building which is not yet available in strategy tests: + // - Add orchard / grovedb-commitment-tree dependencies + // - Cache ProvingKey via OnceLock (~30s first build) + // - Track CommitmentTree across blocks for spend witnesses + // - Build bundles with Builder, create_proof, apply_signatures + // Individual validation tests in drive-abci provide full + // coverage of all 5 shielded transition types (84+ tests). } _ => {} diff --git a/packages/strategy-tests/src/operations.rs b/packages/strategy-tests/src/operations.rs index 42d6c40dc3a..688dcfb6137 100644 --- a/packages/strategy-tests/src/operations.rs +++ b/packages/strategy-tests/src/operations.rs @@ -861,6 +861,12 @@ pub enum OperationType { /// Unshield from the shielded pool to a platform address (requires Orchard bundle). Unshield(AmountRange), + + /// Shield funds from a core asset lock into the shielded pool (requires Orchard bundle). + ShieldFromAssetLock(AmountRange), + + /// Withdraw from the shielded pool to a core (L1) address (requires Orchard bundle). + ShieldedWithdrawal(AmountRange), } #[allow(clippy::large_enum_variant)] @@ -904,6 +910,8 @@ enum OperationTypeInSerializationFormat { Shield(AmountRange), ShieldedTransfer(AmountRange), Unshield(AmountRange), + ShieldFromAssetLock(AmountRange), + ShieldedWithdrawal(AmountRange), } impl PlatformSerializableWithPlatformVersion for OperationType { @@ -1009,14 +1017,16 @@ impl PlatformSerializableWithPlatformVersion for OperationType { key_count, extra_keys, ), - OperationType::Shield(range) => { - OperationTypeInSerializationFormat::Shield(range) - } + OperationType::Shield(range) => OperationTypeInSerializationFormat::Shield(range), OperationType::ShieldedTransfer(range) => { OperationTypeInSerializationFormat::ShieldedTransfer(range) } - OperationType::Unshield(range) => { - OperationTypeInSerializationFormat::Unshield(range) + OperationType::Unshield(range) => OperationTypeInSerializationFormat::Unshield(range), + OperationType::ShieldFromAssetLock(range) => { + OperationTypeInSerializationFormat::ShieldFromAssetLock(range) + } + OperationType::ShieldedWithdrawal(range) => { + OperationTypeInSerializationFormat::ShieldedWithdrawal(range) } }; let config = bincode::config::standard() @@ -1136,14 +1146,16 @@ impl PlatformDeserializableWithPotentialValidationFromVersionedStructure for Ope key_count, extra_keys, ), - OperationTypeInSerializationFormat::Shield(range) => { - OperationType::Shield(range) - } + OperationTypeInSerializationFormat::Shield(range) => OperationType::Shield(range), OperationTypeInSerializationFormat::ShieldedTransfer(range) => { OperationType::ShieldedTransfer(range) } - OperationTypeInSerializationFormat::Unshield(range) => { - OperationType::Unshield(range) + OperationTypeInSerializationFormat::Unshield(range) => OperationType::Unshield(range), + OperationTypeInSerializationFormat::ShieldFromAssetLock(range) => { + OperationType::ShieldFromAssetLock(range) + } + OperationTypeInSerializationFormat::ShieldedWithdrawal(range) => { + OperationType::ShieldedWithdrawal(range) } }) } diff --git a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs index fe3714fbdc2..672470cfdd7 100644 --- a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs +++ b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs @@ -444,9 +444,7 @@ pub fn from_state_error(state_error: &StateError) -> JsValue { StateError::AddressInvalidNonceError(e) => { generic_consensus_error!(AddressInvalidNonceError, e).into() } - StateError::InvalidAnchorError(e) => { - generic_consensus_error!(InvalidAnchorError, e).into() - } + StateError::InvalidAnchorError(e) => generic_consensus_error!(InvalidAnchorError, e).into(), StateError::NullifierAlreadySpentError(e) => { generic_consensus_error!(NullifierAlreadySpentError, e).into() } diff --git a/packages/wasm-dpp/src/identity/state_transition/transition_types.rs b/packages/wasm-dpp/src/identity/state_transition/transition_types.rs index 632a2f5a143..0e30aacee89 100644 --- a/packages/wasm-dpp/src/identity/state_transition/transition_types.rs +++ b/packages/wasm-dpp/src/identity/state_transition/transition_types.rs @@ -63,7 +63,9 @@ impl From for StateTransitionTypeWasm { StateTransitionType::Shield => StateTransitionTypeWasm::Shield, StateTransitionType::ShieldedTransfer => StateTransitionTypeWasm::ShieldedTransfer, StateTransitionType::Unshield => StateTransitionTypeWasm::Unshield, - StateTransitionType::ShieldFromAssetLock => StateTransitionTypeWasm::ShieldFromAssetLock, + StateTransitionType::ShieldFromAssetLock => { + StateTransitionTypeWasm::ShieldFromAssetLock + } StateTransitionType::ShieldedWithdrawal => StateTransitionTypeWasm::ShieldedWithdrawal, } } diff --git a/packages/wasm-dpp/src/lib.rs b/packages/wasm-dpp/src/lib.rs index 87fd30c55bd..40e275dc6c2 100644 --- a/packages/wasm-dpp/src/lib.rs +++ b/packages/wasm-dpp/src/lib.rs @@ -19,6 +19,8 @@ pub mod identifier; pub mod identity; mod metadata; // mod state_repository; +/// Shielded state transitions +pub mod shielded; /// State transitions pub mod state_transition; // mod version; diff --git a/packages/wasm-dpp/src/shielded/mod.rs b/packages/wasm-dpp/src/shielded/mod.rs new file mode 100644 index 00000000000..e04539129ce --- /dev/null +++ b/packages/wasm-dpp/src/shielded/mod.rs @@ -0,0 +1,42 @@ +use wasm_bindgen::prelude::*; + +use crate::buffer::Buffer; + +pub mod shield_from_asset_lock_transition; +pub mod shield_transition; +pub mod shielded_transfer_transition; +pub mod shielded_withdrawal_transition; +pub mod unshield_transition; + +pub use shield_from_asset_lock_transition::ShieldFromAssetLockTransitionWasm; +pub use shield_transition::ShieldTransitionWasm; +pub use shielded_transfer_transition::ShieldedTransferTransitionWasm; +pub use shielded_withdrawal_transition::ShieldedWithdrawalTransitionWasm; +pub use unshield_transition::UnshieldTransitionWasm; + +/// Compute the platform sighash from an Orchard bundle commitment and extra data. +/// +/// `sighash = SHA-256("DashPlatformSighash" || bundleCommitment || extraData)` +/// +/// - For shield and shielded_transfer transitions, `extraData` should be empty. +/// - For unshield transitions, `extraData` = `outputAddress || amount (LE u64)`. +/// - For shielded withdrawal transitions, `extraData` = `outputScript || amount (LE u64)`. +/// +/// @param {Buffer} bundleCommitment - 32-byte Orchard bundle commitment (BLAKE2b-256 per ZIP-244) +/// @param {Buffer} extraData - Transparent field binding (empty for shielded-only transitions) +/// @returns {Buffer} 32-byte SHA-256 sighash +#[wasm_bindgen(js_name = computePlatformSighash)] +pub fn compute_platform_sighash_wasm( + bundle_commitment: &[u8], + extra_data: &[u8], +) -> Result { + if bundle_commitment.len() != 32 { + return Err(JsValue::from_str(&format!( + "bundleCommitment must be exactly 32 bytes, got {}", + bundle_commitment.len() + ))); + } + let commitment: &[u8; 32] = bundle_commitment.try_into().unwrap(); + let result = dpp::shielded::compute_platform_sighash(commitment, extra_data); + Ok(Buffer::from_bytes(&result)) +} diff --git a/packages/wasm-dpp/src/shielded/shield_from_asset_lock_transition.rs b/packages/wasm-dpp/src/shielded/shield_from_asset_lock_transition.rs new file mode 100644 index 00000000000..b17025da105 --- /dev/null +++ b/packages/wasm-dpp/src/shielded/shield_from_asset_lock_transition.rs @@ -0,0 +1,162 @@ +use wasm_bindgen::prelude::*; + +use crate::buffer::Buffer; +use crate::utils::WithJsError; + +use dpp::serialization::PlatformSerializable; +use dpp::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; +use dpp::state_transition::{StateTransition, StateTransitionLike}; + +#[wasm_bindgen(js_name = ShieldFromAssetLockTransition)] +#[derive(Clone)] +pub struct ShieldFromAssetLockTransitionWasm(ShieldFromAssetLockTransition); + +impl From for ShieldFromAssetLockTransitionWasm { + fn from(v: ShieldFromAssetLockTransition) -> Self { + ShieldFromAssetLockTransitionWasm(v) + } +} + +impl From for ShieldFromAssetLockTransition { + fn from(v: ShieldFromAssetLockTransitionWasm) -> Self { + v.0 + } +} + +#[wasm_bindgen(js_class = ShieldFromAssetLockTransition)] +impl ShieldFromAssetLockTransitionWasm { + #[wasm_bindgen(js_name = getType)] + pub fn get_type(&self) -> u8 { + self.0.state_transition_type() as u8 + } + + /// Returns the asset lock proof as a JS value. + #[wasm_bindgen(js_name = getAssetLockProof)] + pub fn get_asset_lock_proof(&self) -> Result { + let proof = match &self.0 { + ShieldFromAssetLockTransition::V0(v0) => &v0.asset_lock_proof, + }; + serde_wasm_bindgen::to_value(proof).map_err(|e| JsValue::from(e.to_string())) + } + + /// Returns the serialized Orchard actions as a JS array. + #[wasm_bindgen(js_name = getActions)] + pub fn get_actions(&self) -> Result { + let inner = match &self.0 { + ShieldFromAssetLockTransition::V0(v0) => &v0.actions, + }; + serde_wasm_bindgen::to_value(inner).map_err(|e| JsValue::from(e.to_string())) + } + + /// Returns the bundle flags byte. + #[wasm_bindgen(js_name = getFlags)] + pub fn get_flags(&self) -> u8 { + match &self.0 { + ShieldFromAssetLockTransition::V0(v0) => v0.flags, + } + } + + /// Returns the net value balance. + #[wasm_bindgen(js_name = getValueBalance)] + pub fn get_value_balance(&self) -> i64 { + match &self.0 { + ShieldFromAssetLockTransition::V0(v0) => v0.value_balance, + } + } + + /// Returns the anchor (32-byte Merkle root) as a Buffer. + #[wasm_bindgen(js_name = getAnchor)] + pub fn get_anchor(&self) -> Buffer { + let anchor = match &self.0 { + ShieldFromAssetLockTransition::V0(v0) => &v0.anchor, + }; + Buffer::from_bytes(anchor) + } + + /// Returns the Halo2 proof bytes as a Buffer. + #[wasm_bindgen(js_name = getProof)] + pub fn get_proof(&self) -> Buffer { + let proof = match &self.0 { + ShieldFromAssetLockTransition::V0(v0) => &v0.proof, + }; + Buffer::from_bytes(proof) + } + + /// Returns the RedPallas binding signature (64 bytes) as a Buffer. + #[wasm_bindgen(js_name = getBindingSignature)] + pub fn get_binding_signature(&self) -> Buffer { + let sig = match &self.0 { + ShieldFromAssetLockTransition::V0(v0) => &v0.binding_signature, + }; + Buffer::from_bytes(sig) + } + + /// Returns the user fee increase multiplier. + #[wasm_bindgen(js_name = getUserFeeIncrease)] + pub fn get_user_fee_increase(&self) -> u16 { + match &self.0 { + ShieldFromAssetLockTransition::V0(v0) => v0.user_fee_increase, + } + } + + /// Returns the ECDSA signature as a Buffer. + #[wasm_bindgen(js_name = getSignature)] + pub fn get_signature(&self) -> Buffer { + let sig = match &self.0 { + ShieldFromAssetLockTransition::V0(v0) => &v0.signature, + }; + Buffer::from_bytes(sig.as_slice()) + } + + #[wasm_bindgen(js_name = toObject)] + pub fn to_object(&self) -> Result { + serde_wasm_bindgen::to_value(&self.0).map_err(|e| JsValue::from(e.to_string())) + } + + #[wasm_bindgen(js_name = toBuffer)] + pub fn to_buffer(&self) -> Result { + let bytes = PlatformSerializable::serialize_to_bytes( + &StateTransition::ShieldFromAssetLock(self.0.clone()), + ) + .with_js_error()?; + Ok(Buffer::from_bytes(&bytes)) + } + + #[wasm_bindgen(js_name = toJSON)] + pub fn to_json(&self) -> Result { + let json = serde_json::to_value(&self.0).map_err(|e| JsValue::from(e.to_string()))?; + serde_wasm_bindgen::to_value(&json).map_err(|e| JsValue::from(e.to_string())) + } + + #[wasm_bindgen(js_name = getModifiedDataIds)] + pub fn modified_data_ids(&self) -> Vec { + self.0 + .modified_data_ids() + .into_iter() + .map(|id| { + let wrapper = crate::identifier::IdentifierWrapper::from(id); + wrapper.into() + }) + .collect() + } + + #[wasm_bindgen(js_name = isDataContractStateTransition)] + pub fn is_data_contract_state_transition(&self) -> bool { + self.0.is_data_contract_state_transition() + } + + #[wasm_bindgen(js_name = isDocumentStateTransition)] + pub fn is_document_state_transition(&self) -> bool { + self.0.is_document_state_transition() + } + + #[wasm_bindgen(js_name = isIdentityStateTransition)] + pub fn is_identity_state_transition(&self) -> bool { + self.0.is_identity_state_transition() + } + + #[wasm_bindgen(js_name = isVotingStateTransition)] + pub fn is_voting_state_transition(&self) -> bool { + self.0.is_voting_state_transition() + } +} diff --git a/packages/wasm-dpp/src/shielded/shield_transition.rs b/packages/wasm-dpp/src/shielded/shield_transition.rs new file mode 100644 index 00000000000..6f4c1b7aee1 --- /dev/null +++ b/packages/wasm-dpp/src/shielded/shield_transition.rs @@ -0,0 +1,171 @@ +use wasm_bindgen::prelude::*; + +use crate::buffer::Buffer; +use crate::utils::WithJsError; + +use dpp::serialization::PlatformSerializable; +use dpp::state_transition::shield_transition::ShieldTransition; +use dpp::state_transition::{StateTransition, StateTransitionLike}; + +#[wasm_bindgen(js_name = ShieldTransition)] +#[derive(Clone)] +pub struct ShieldTransitionWasm(ShieldTransition); + +impl From for ShieldTransitionWasm { + fn from(v: ShieldTransition) -> Self { + ShieldTransitionWasm(v) + } +} + +impl From for ShieldTransition { + fn from(v: ShieldTransitionWasm) -> Self { + v.0 + } +} + +#[wasm_bindgen(js_class = ShieldTransition)] +impl ShieldTransitionWasm { + #[wasm_bindgen(js_name = getType)] + pub fn get_type(&self) -> u8 { + self.0.state_transition_type() as u8 + } + + /// Returns the inputs map as a JS object. + /// Keys are platform address strings, values are [nonce, credits] tuples. + #[wasm_bindgen(js_name = getInputs)] + pub fn get_inputs(&self) -> Result { + let inner = match &self.0 { + ShieldTransition::V0(v0) => &v0.inputs, + }; + serde_wasm_bindgen::to_value(inner).map_err(|e| JsValue::from(e.to_string())) + } + + /// Returns the serialized Orchard actions as a JS array. + #[wasm_bindgen(js_name = getActions)] + pub fn get_actions(&self) -> Result { + let inner = match &self.0 { + ShieldTransition::V0(v0) => &v0.actions, + }; + serde_wasm_bindgen::to_value(inner).map_err(|e| JsValue::from(e.to_string())) + } + + /// Returns the bundle flags byte. + #[wasm_bindgen(js_name = getFlags)] + pub fn get_flags(&self) -> u8 { + match &self.0 { + ShieldTransition::V0(v0) => v0.flags, + } + } + + /// Returns the net value balance. + #[wasm_bindgen(js_name = getValueBalance)] + pub fn get_value_balance(&self) -> i64 { + match &self.0 { + ShieldTransition::V0(v0) => v0.value_balance, + } + } + + /// Returns the anchor (32-byte Merkle root) as a Buffer. + #[wasm_bindgen(js_name = getAnchor)] + pub fn get_anchor(&self) -> Buffer { + let anchor = match &self.0 { + ShieldTransition::V0(v0) => &v0.anchor, + }; + Buffer::from_bytes(anchor) + } + + /// Returns the Halo2 proof bytes as a Buffer. + #[wasm_bindgen(js_name = getProof)] + pub fn get_proof(&self) -> Buffer { + let proof = match &self.0 { + ShieldTransition::V0(v0) => &v0.proof, + }; + Buffer::from_bytes(proof) + } + + /// Returns the RedPallas binding signature (64 bytes) as a Buffer. + #[wasm_bindgen(js_name = getBindingSignature)] + pub fn get_binding_signature(&self) -> Buffer { + let sig = match &self.0 { + ShieldTransition::V0(v0) => &v0.binding_signature, + }; + Buffer::from_bytes(sig) + } + + /// Returns the fee strategy as a JS value. + #[wasm_bindgen(js_name = getFeeStrategy)] + pub fn get_fee_strategy(&self) -> Result { + let strategy = match &self.0 { + ShieldTransition::V0(v0) => &v0.fee_strategy, + }; + serde_wasm_bindgen::to_value(strategy).map_err(|e| JsValue::from(e.to_string())) + } + + /// Returns the user fee increase multiplier. + #[wasm_bindgen(js_name = getUserFeeIncrease)] + pub fn get_user_fee_increase(&self) -> u16 { + match &self.0 { + ShieldTransition::V0(v0) => v0.user_fee_increase, + } + } + + /// Returns the input witnesses as a JS value. + #[wasm_bindgen(js_name = getInputWitnesses)] + pub fn get_input_witnesses(&self) -> Result { + let witnesses = match &self.0 { + ShieldTransition::V0(v0) => &v0.input_witnesses, + }; + serde_wasm_bindgen::to_value(witnesses).map_err(|e| JsValue::from(e.to_string())) + } + + #[wasm_bindgen(js_name = toObject)] + pub fn to_object(&self) -> Result { + serde_wasm_bindgen::to_value(&self.0).map_err(|e| JsValue::from(e.to_string())) + } + + #[wasm_bindgen(js_name = toBuffer)] + pub fn to_buffer(&self) -> Result { + let bytes = + PlatformSerializable::serialize_to_bytes(&StateTransition::Shield(self.0.clone())) + .with_js_error()?; + Ok(Buffer::from_bytes(&bytes)) + } + + #[wasm_bindgen(js_name = toJSON)] + pub fn to_json(&self) -> Result { + let json = serde_json::to_value(&self.0).map_err(|e| JsValue::from(e.to_string()))?; + serde_wasm_bindgen::to_value(&json).map_err(|e| JsValue::from(e.to_string())) + } + + #[wasm_bindgen(js_name = getModifiedDataIds)] + pub fn modified_data_ids(&self) -> Vec { + self.0 + .modified_data_ids() + .into_iter() + .map(|id| { + let wrapper = crate::identifier::IdentifierWrapper::from(id); + wrapper.into() + }) + .collect() + } + + #[wasm_bindgen(js_name = isDataContractStateTransition)] + pub fn is_data_contract_state_transition(&self) -> bool { + self.0.is_data_contract_state_transition() + } + + #[wasm_bindgen(js_name = isDocumentStateTransition)] + pub fn is_document_state_transition(&self) -> bool { + self.0.is_document_state_transition() + } + + #[wasm_bindgen(js_name = isIdentityStateTransition)] + pub fn is_identity_state_transition(&self) -> bool { + self.0.is_identity_state_transition() + } + + #[wasm_bindgen(js_name = isVotingStateTransition)] + pub fn is_voting_state_transition(&self) -> bool { + self.0.is_voting_state_transition() + } +} diff --git a/packages/wasm-dpp/src/shielded/shielded_transfer_transition.rs b/packages/wasm-dpp/src/shielded/shielded_transfer_transition.rs new file mode 100644 index 00000000000..ec155fced0f --- /dev/null +++ b/packages/wasm-dpp/src/shielded/shielded_transfer_transition.rs @@ -0,0 +1,144 @@ +use wasm_bindgen::prelude::*; + +use crate::buffer::Buffer; +use crate::utils::WithJsError; + +use dpp::serialization::PlatformSerializable; +use dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition; +use dpp::state_transition::{StateTransition, StateTransitionLike}; + +#[wasm_bindgen(js_name = ShieldedTransferTransition)] +#[derive(Clone)] +pub struct ShieldedTransferTransitionWasm(ShieldedTransferTransition); + +impl From for ShieldedTransferTransitionWasm { + fn from(v: ShieldedTransferTransition) -> Self { + ShieldedTransferTransitionWasm(v) + } +} + +impl From for ShieldedTransferTransition { + fn from(v: ShieldedTransferTransitionWasm) -> Self { + v.0 + } +} + +#[wasm_bindgen(js_class = ShieldedTransferTransition)] +impl ShieldedTransferTransitionWasm { + #[wasm_bindgen(js_name = getType)] + pub fn get_type(&self) -> u8 { + self.0.state_transition_type() as u8 + } + + /// Returns the serialized Orchard actions as a JS array. + #[wasm_bindgen(js_name = getActions)] + pub fn get_actions(&self) -> Result { + let inner = match &self.0 { + ShieldedTransferTransition::V0(v0) => &v0.actions, + }; + serde_wasm_bindgen::to_value(inner).map_err(|e| JsValue::from(e.to_string())) + } + + /// Returns the bundle flags byte. + #[wasm_bindgen(js_name = getFlags)] + pub fn get_flags(&self) -> u8 { + match &self.0 { + ShieldedTransferTransition::V0(v0) => v0.flags, + } + } + + /// Returns the net value balance. + #[wasm_bindgen(js_name = getValueBalance)] + pub fn get_value_balance(&self) -> i64 { + match &self.0 { + ShieldedTransferTransition::V0(v0) => v0.value_balance, + } + } + + /// Returns the anchor (32-byte Merkle root) as a Buffer. + #[wasm_bindgen(js_name = getAnchor)] + pub fn get_anchor(&self) -> Buffer { + let anchor = match &self.0 { + ShieldedTransferTransition::V0(v0) => &v0.anchor, + }; + Buffer::from_bytes(anchor) + } + + /// Returns the Halo2 proof bytes as a Buffer. + #[wasm_bindgen(js_name = getProof)] + pub fn get_proof(&self) -> Buffer { + let proof = match &self.0 { + ShieldedTransferTransition::V0(v0) => &v0.proof, + }; + Buffer::from_bytes(proof) + } + + /// Returns the RedPallas binding signature (64 bytes) as a Buffer. + #[wasm_bindgen(js_name = getBindingSignature)] + pub fn get_binding_signature(&self) -> Buffer { + let sig = match &self.0 { + ShieldedTransferTransition::V0(v0) => &v0.binding_signature, + }; + Buffer::from_bytes(sig) + } + + /// Returns the user fee increase multiplier. + #[wasm_bindgen(js_name = getUserFeeIncrease)] + pub fn get_user_fee_increase(&self) -> u16 { + match &self.0 { + ShieldedTransferTransition::V0(v0) => v0.user_fee_increase, + } + } + + #[wasm_bindgen(js_name = toObject)] + pub fn to_object(&self) -> Result { + serde_wasm_bindgen::to_value(&self.0).map_err(|e| JsValue::from(e.to_string())) + } + + #[wasm_bindgen(js_name = toBuffer)] + pub fn to_buffer(&self) -> Result { + let bytes = PlatformSerializable::serialize_to_bytes(&StateTransition::ShieldedTransfer( + self.0.clone(), + )) + .with_js_error()?; + Ok(Buffer::from_bytes(&bytes)) + } + + #[wasm_bindgen(js_name = toJSON)] + pub fn to_json(&self) -> Result { + let json = serde_json::to_value(&self.0).map_err(|e| JsValue::from(e.to_string()))?; + serde_wasm_bindgen::to_value(&json).map_err(|e| JsValue::from(e.to_string())) + } + + #[wasm_bindgen(js_name = getModifiedDataIds)] + pub fn modified_data_ids(&self) -> Vec { + self.0 + .modified_data_ids() + .into_iter() + .map(|id| { + let wrapper = crate::identifier::IdentifierWrapper::from(id); + wrapper.into() + }) + .collect() + } + + #[wasm_bindgen(js_name = isDataContractStateTransition)] + pub fn is_data_contract_state_transition(&self) -> bool { + self.0.is_data_contract_state_transition() + } + + #[wasm_bindgen(js_name = isDocumentStateTransition)] + pub fn is_document_state_transition(&self) -> bool { + self.0.is_document_state_transition() + } + + #[wasm_bindgen(js_name = isIdentityStateTransition)] + pub fn is_identity_state_transition(&self) -> bool { + self.0.is_identity_state_transition() + } + + #[wasm_bindgen(js_name = isVotingStateTransition)] + pub fn is_voting_state_transition(&self) -> bool { + self.0.is_voting_state_transition() + } +} diff --git a/packages/wasm-dpp/src/shielded/shielded_withdrawal_transition.rs b/packages/wasm-dpp/src/shielded/shielded_withdrawal_transition.rs new file mode 100644 index 00000000000..2b6821992a6 --- /dev/null +++ b/packages/wasm-dpp/src/shielded/shielded_withdrawal_transition.rs @@ -0,0 +1,177 @@ +use wasm_bindgen::prelude::*; + +use crate::buffer::Buffer; +use crate::utils::WithJsError; + +use dpp::serialization::PlatformSerializable; +use dpp::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; +use dpp::state_transition::{StateTransition, StateTransitionLike}; + +#[wasm_bindgen(js_name = ShieldedWithdrawalTransition)] +#[derive(Clone)] +pub struct ShieldedWithdrawalTransitionWasm(ShieldedWithdrawalTransition); + +impl From for ShieldedWithdrawalTransitionWasm { + fn from(v: ShieldedWithdrawalTransition) -> Self { + ShieldedWithdrawalTransitionWasm(v) + } +} + +impl From for ShieldedWithdrawalTransition { + fn from(v: ShieldedWithdrawalTransitionWasm) -> Self { + v.0 + } +} + +#[wasm_bindgen(js_class = ShieldedWithdrawalTransition)] +impl ShieldedWithdrawalTransitionWasm { + #[wasm_bindgen(js_name = getType)] + pub fn get_type(&self) -> u8 { + self.0.state_transition_type() as u8 + } + + /// Returns the withdrawal amount in credits. + #[wasm_bindgen(js_name = getAmount)] + pub fn get_amount(&self) -> u64 { + match &self.0 { + ShieldedWithdrawalTransition::V0(v0) => v0.amount, + } + } + + /// Returns the serialized Orchard actions as a JS array. + #[wasm_bindgen(js_name = getActions)] + pub fn get_actions(&self) -> Result { + let inner = match &self.0 { + ShieldedWithdrawalTransition::V0(v0) => &v0.actions, + }; + serde_wasm_bindgen::to_value(inner).map_err(|e| JsValue::from(e.to_string())) + } + + /// Returns the bundle flags byte. + #[wasm_bindgen(js_name = getFlags)] + pub fn get_flags(&self) -> u8 { + match &self.0 { + ShieldedWithdrawalTransition::V0(v0) => v0.flags, + } + } + + /// Returns the net value balance. + #[wasm_bindgen(js_name = getValueBalance)] + pub fn get_value_balance(&self) -> i64 { + match &self.0 { + ShieldedWithdrawalTransition::V0(v0) => v0.value_balance, + } + } + + /// Returns the anchor (32-byte Merkle root) as a Buffer. + #[wasm_bindgen(js_name = getAnchor)] + pub fn get_anchor(&self) -> Buffer { + let anchor = match &self.0 { + ShieldedWithdrawalTransition::V0(v0) => &v0.anchor, + }; + Buffer::from_bytes(anchor) + } + + /// Returns the Halo2 proof bytes as a Buffer. + #[wasm_bindgen(js_name = getProof)] + pub fn get_proof(&self) -> Buffer { + let proof = match &self.0 { + ShieldedWithdrawalTransition::V0(v0) => &v0.proof, + }; + Buffer::from_bytes(proof) + } + + /// Returns the RedPallas binding signature (64 bytes) as a Buffer. + #[wasm_bindgen(js_name = getBindingSignature)] + pub fn get_binding_signature(&self) -> Buffer { + let sig = match &self.0 { + ShieldedWithdrawalTransition::V0(v0) => &v0.binding_signature, + }; + Buffer::from_bytes(sig) + } + + /// Returns the core fee per byte. + #[wasm_bindgen(js_name = getCoreFeePerByte)] + pub fn get_core_fee_per_byte(&self) -> u32 { + match &self.0 { + ShieldedWithdrawalTransition::V0(v0) => v0.core_fee_per_byte, + } + } + + /// Returns the pooling strategy as a u8. + #[wasm_bindgen(js_name = getPooling)] + pub fn get_pooling(&self) -> u8 { + match &self.0 { + ShieldedWithdrawalTransition::V0(v0) => v0.pooling as u8, + } + } + + /// Returns the output script (core address) as a Buffer. + #[wasm_bindgen(js_name = getOutputScript)] + pub fn get_output_script(&self) -> Buffer { + let script = match &self.0 { + ShieldedWithdrawalTransition::V0(v0) => &v0.output_script, + }; + Buffer::from_bytes(script.as_bytes()) + } + + /// Returns the user fee increase multiplier. + #[wasm_bindgen(js_name = getUserFeeIncrease)] + pub fn get_user_fee_increase(&self) -> u16 { + match &self.0 { + ShieldedWithdrawalTransition::V0(v0) => v0.user_fee_increase, + } + } + + #[wasm_bindgen(js_name = toObject)] + pub fn to_object(&self) -> Result { + serde_wasm_bindgen::to_value(&self.0).map_err(|e| JsValue::from(e.to_string())) + } + + #[wasm_bindgen(js_name = toBuffer)] + pub fn to_buffer(&self) -> Result { + let bytes = PlatformSerializable::serialize_to_bytes(&StateTransition::ShieldedWithdrawal( + self.0.clone(), + )) + .with_js_error()?; + Ok(Buffer::from_bytes(&bytes)) + } + + #[wasm_bindgen(js_name = toJSON)] + pub fn to_json(&self) -> Result { + let json = serde_json::to_value(&self.0).map_err(|e| JsValue::from(e.to_string()))?; + serde_wasm_bindgen::to_value(&json).map_err(|e| JsValue::from(e.to_string())) + } + + #[wasm_bindgen(js_name = getModifiedDataIds)] + pub fn modified_data_ids(&self) -> Vec { + self.0 + .modified_data_ids() + .into_iter() + .map(|id| { + let wrapper = crate::identifier::IdentifierWrapper::from(id); + wrapper.into() + }) + .collect() + } + + #[wasm_bindgen(js_name = isDataContractStateTransition)] + pub fn is_data_contract_state_transition(&self) -> bool { + self.0.is_data_contract_state_transition() + } + + #[wasm_bindgen(js_name = isDocumentStateTransition)] + pub fn is_document_state_transition(&self) -> bool { + self.0.is_document_state_transition() + } + + #[wasm_bindgen(js_name = isIdentityStateTransition)] + pub fn is_identity_state_transition(&self) -> bool { + self.0.is_identity_state_transition() + } + + #[wasm_bindgen(js_name = isVotingStateTransition)] + pub fn is_voting_state_transition(&self) -> bool { + self.0.is_voting_state_transition() + } +} diff --git a/packages/wasm-dpp/src/shielded/unshield_transition.rs b/packages/wasm-dpp/src/shielded/unshield_transition.rs new file mode 100644 index 00000000000..12922e5cee0 --- /dev/null +++ b/packages/wasm-dpp/src/shielded/unshield_transition.rs @@ -0,0 +1,160 @@ +use wasm_bindgen::prelude::*; + +use crate::buffer::Buffer; +use crate::utils::WithJsError; + +use dpp::serialization::PlatformSerializable; +use dpp::state_transition::unshield_transition::UnshieldTransition; +use dpp::state_transition::{StateTransition, StateTransitionLike}; + +#[wasm_bindgen(js_name = UnshieldTransition)] +#[derive(Clone)] +pub struct UnshieldTransitionWasm(UnshieldTransition); + +impl From for UnshieldTransitionWasm { + fn from(v: UnshieldTransition) -> Self { + UnshieldTransitionWasm(v) + } +} + +impl From for UnshieldTransition { + fn from(v: UnshieldTransitionWasm) -> Self { + v.0 + } +} + +#[wasm_bindgen(js_class = UnshieldTransition)] +impl UnshieldTransitionWasm { + #[wasm_bindgen(js_name = getType)] + pub fn get_type(&self) -> u8 { + self.0.state_transition_type() as u8 + } + + /// Returns the output address as a JS value (serialized PlatformAddress). + #[wasm_bindgen(js_name = getOutputAddress)] + pub fn get_output_address(&self) -> Result { + let addr = match &self.0 { + UnshieldTransition::V0(v0) => &v0.output_address, + }; + serde_wasm_bindgen::to_value(addr).map_err(|e| JsValue::from(e.to_string())) + } + + /// Returns the amount being unshielded (in credits). + #[wasm_bindgen(js_name = getAmount)] + pub fn get_amount(&self) -> u64 { + match &self.0 { + UnshieldTransition::V0(v0) => v0.amount, + } + } + + /// Returns the serialized Orchard actions as a JS array. + #[wasm_bindgen(js_name = getActions)] + pub fn get_actions(&self) -> Result { + let inner = match &self.0 { + UnshieldTransition::V0(v0) => &v0.actions, + }; + serde_wasm_bindgen::to_value(inner).map_err(|e| JsValue::from(e.to_string())) + } + + /// Returns the bundle flags byte. + #[wasm_bindgen(js_name = getFlags)] + pub fn get_flags(&self) -> u8 { + match &self.0 { + UnshieldTransition::V0(v0) => v0.flags, + } + } + + /// Returns the net value balance. + #[wasm_bindgen(js_name = getValueBalance)] + pub fn get_value_balance(&self) -> i64 { + match &self.0 { + UnshieldTransition::V0(v0) => v0.value_balance, + } + } + + /// Returns the anchor (32-byte Merkle root) as a Buffer. + #[wasm_bindgen(js_name = getAnchor)] + pub fn get_anchor(&self) -> Buffer { + let anchor = match &self.0 { + UnshieldTransition::V0(v0) => &v0.anchor, + }; + Buffer::from_bytes(anchor) + } + + /// Returns the Halo2 proof bytes as a Buffer. + #[wasm_bindgen(js_name = getProof)] + pub fn get_proof(&self) -> Buffer { + let proof = match &self.0 { + UnshieldTransition::V0(v0) => &v0.proof, + }; + Buffer::from_bytes(proof) + } + + /// Returns the RedPallas binding signature (64 bytes) as a Buffer. + #[wasm_bindgen(js_name = getBindingSignature)] + pub fn get_binding_signature(&self) -> Buffer { + let sig = match &self.0 { + UnshieldTransition::V0(v0) => &v0.binding_signature, + }; + Buffer::from_bytes(sig) + } + + /// Returns the user fee increase multiplier. + #[wasm_bindgen(js_name = getUserFeeIncrease)] + pub fn get_user_fee_increase(&self) -> u16 { + match &self.0 { + UnshieldTransition::V0(v0) => v0.user_fee_increase, + } + } + + #[wasm_bindgen(js_name = toObject)] + pub fn to_object(&self) -> Result { + serde_wasm_bindgen::to_value(&self.0).map_err(|e| JsValue::from(e.to_string())) + } + + #[wasm_bindgen(js_name = toBuffer)] + pub fn to_buffer(&self) -> Result { + let bytes = + PlatformSerializable::serialize_to_bytes(&StateTransition::Unshield(self.0.clone())) + .with_js_error()?; + Ok(Buffer::from_bytes(&bytes)) + } + + #[wasm_bindgen(js_name = toJSON)] + pub fn to_json(&self) -> Result { + let json = serde_json::to_value(&self.0).map_err(|e| JsValue::from(e.to_string()))?; + serde_wasm_bindgen::to_value(&json).map_err(|e| JsValue::from(e.to_string())) + } + + #[wasm_bindgen(js_name = getModifiedDataIds)] + pub fn modified_data_ids(&self) -> Vec { + self.0 + .modified_data_ids() + .into_iter() + .map(|id| { + let wrapper = crate::identifier::IdentifierWrapper::from(id); + wrapper.into() + }) + .collect() + } + + #[wasm_bindgen(js_name = isDataContractStateTransition)] + pub fn is_data_contract_state_transition(&self) -> bool { + self.0.is_data_contract_state_transition() + } + + #[wasm_bindgen(js_name = isDocumentStateTransition)] + pub fn is_document_state_transition(&self) -> bool { + self.0.is_document_state_transition() + } + + #[wasm_bindgen(js_name = isIdentityStateTransition)] + pub fn is_identity_state_transition(&self) -> bool { + self.0.is_identity_state_transition() + } + + #[wasm_bindgen(js_name = isVotingStateTransition)] + pub fn is_voting_state_transition(&self) -> bool { + self.0.is_voting_state_transition() + } +} diff --git a/packages/wasm-dpp/src/state_transition/state_transition_factory.rs b/packages/wasm-dpp/src/state_transition/state_transition_factory.rs index 689b3d3501d..fb196c27f1a 100644 --- a/packages/wasm-dpp/src/state_transition/state_transition_factory.rs +++ b/packages/wasm-dpp/src/state_transition/state_transition_factory.rs @@ -6,6 +6,10 @@ use crate::identity::state_transition::{ IdentityCreditWithdrawalTransitionWasm, IdentityTopUpTransitionWasm, IdentityUpdateTransitionWasm, }; +use crate::shielded::{ + ShieldFromAssetLockTransitionWasm, ShieldTransitionWasm, ShieldedTransferTransitionWasm, + ShieldedWithdrawalTransitionWasm, UnshieldTransitionWasm, +}; use crate::state_transition::errors::invalid_state_transition_error::InvalidStateTransitionErrorWasm; use crate::state_transition::errors::state_transition_is_not_active_error::StateTransitionIsNotActiveErrorWasm; use crate::voting::state_transition::masternode_vote_transition::MasternodeVoteTransitionWasm; @@ -79,20 +83,16 @@ impl StateTransitionFactoryWasm { StateTransition::AddressCreditWithdrawal(st) => { serde_wasm_bindgen::to_value(&st).map_err(|e| JsValue::from(e.to_string())) } - StateTransition::Shield(st) => { - serde_wasm_bindgen::to_value(&st).map_err(|e| JsValue::from(e.to_string())) - } + StateTransition::Shield(st) => Ok(ShieldTransitionWasm::from(st).into()), StateTransition::ShieldedTransfer(st) => { - serde_wasm_bindgen::to_value(&st).map_err(|e| JsValue::from(e.to_string())) - } - StateTransition::Unshield(st) => { - serde_wasm_bindgen::to_value(&st).map_err(|e| JsValue::from(e.to_string())) + Ok(ShieldedTransferTransitionWasm::from(st).into()) } + StateTransition::Unshield(st) => Ok(UnshieldTransitionWasm::from(st).into()), StateTransition::ShieldFromAssetLock(st) => { - serde_wasm_bindgen::to_value(&st).map_err(|e| JsValue::from(e.to_string())) + Ok(ShieldFromAssetLockTransitionWasm::from(st).into()) } StateTransition::ShieldedWithdrawal(st) => { - serde_wasm_bindgen::to_value(&st).map_err(|e| JsValue::from(e.to_string())) + Ok(ShieldedWithdrawalTransitionWasm::from(st).into()) } }, Err(dpp::ProtocolError::StateTransitionError(e)) => match e { From 048c3aaee448fac6b33a2fc4706b2f859ae26c94 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 11 Feb 2026 22:56:51 +0000 Subject: [PATCH 12/40] more work --- packages/rs-dpp/src/errors/consensus/codes.rs | 1 + .../shielded/insufficient_pool_notes_error.rs | 46 ++++++ .../errors/consensus/state/shielded/mod.rs | 2 + .../src/errors/consensus/state/state_error.rs | 4 + .../shielded_withdrawal/tests.rs | 71 +++++++- .../transform_into_action/v0/mod.rs | 33 +++- .../state_transitions/unshield/tests.rs | 66 +++++++- .../unshield/transform_into_action/v0/mod.rs | 33 +++- .../tests/strategy_tests/strategy.rs | 152 ++++++++++++++++++ .../tests/strategy_tests/test_cases/mod.rs | 1 + .../test_cases/shielded_tests.rs | 125 ++++++++++++++ .../drive_abci_validation_versions/mod.rs | 4 + .../drive_abci_validation_versions/v1.rs | 1 + .../drive_abci_validation_versions/v2.rs | 1 + .../drive_abci_validation_versions/v3.rs | 1 + .../drive_abci_validation_versions/v4.rs | 1 + .../drive_abci_validation_versions/v5.rs | 1 + .../drive_abci_validation_versions/v6.rs | 1 + .../drive_abci_validation_versions/v7.rs | 1 + .../src/errors/consensus/consensus_error.rs | 5 +- 20 files changed, 545 insertions(+), 5 deletions(-) create mode 100644 packages/rs-dpp/src/errors/consensus/state/shielded/insufficient_pool_notes_error.rs create mode 100644 packages/rs-drive-abci/tests/strategy_tests/test_cases/shielded_tests.rs diff --git a/packages/rs-dpp/src/errors/consensus/codes.rs b/packages/rs-dpp/src/errors/consensus/codes.rs index 60e8086c1a8..7019611c4c5 100644 --- a/packages/rs-dpp/src/errors/consensus/codes.rs +++ b/packages/rs-dpp/src/errors/consensus/codes.rs @@ -381,6 +381,7 @@ impl ErrorWithCode for StateError { Self::InvalidAnchorError(_) => 40900, Self::NullifierAlreadySpentError(_) => 40901, Self::InvalidShieldedProofError(_) => 40902, + Self::InsufficientPoolNotesError(_) => 40903, } } } diff --git a/packages/rs-dpp/src/errors/consensus/state/shielded/insufficient_pool_notes_error.rs b/packages/rs-dpp/src/errors/consensus/state/shielded/insufficient_pool_notes_error.rs new file mode 100644 index 00000000000..6e193ef0f56 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/shielded/insufficient_pool_notes_error.rs @@ -0,0 +1,46 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[platform_serialize(unversioned)] +#[error( + "shielded pool has insufficient notes for outgoing transition: pool has {current_count} notes but minimum {minimum_required} required" +)] +pub struct InsufficientPoolNotesError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + current_count: u64, + minimum_required: u64, +} + +impl InsufficientPoolNotesError { + pub fn new(current_count: u64, minimum_required: u64) -> Self { + Self { + current_count, + minimum_required, + } + } + + pub fn current_count(&self) -> u64 { + self.current_count + } + + pub fn minimum_required(&self) -> u64 { + self.minimum_required + } +} + +impl From for ConsensusError { + fn from(err: InsufficientPoolNotesError) -> Self { + Self::StateError(StateError::InsufficientPoolNotesError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/state/shielded/mod.rs b/packages/rs-dpp/src/errors/consensus/state/shielded/mod.rs index d3361548fc5..5382da893ad 100644 --- a/packages/rs-dpp/src/errors/consensus/state/shielded/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/state/shielded/mod.rs @@ -1,7 +1,9 @@ +pub mod insufficient_pool_notes_error; pub mod invalid_anchor_error; pub mod invalid_shielded_proof_error; pub mod nullifier_already_spent_error; +pub use insufficient_pool_notes_error::*; pub use invalid_anchor_error::*; pub use invalid_shielded_proof_error::*; pub use nullifier_already_spent_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/state/state_error.rs b/packages/rs-dpp/src/errors/consensus/state/state_error.rs index cb7a7278657..89a5aa803f2 100644 --- a/packages/rs-dpp/src/errors/consensus/state/state_error.rs +++ b/packages/rs-dpp/src/errors/consensus/state/state_error.rs @@ -4,6 +4,7 @@ use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; use thiserror::Error; use crate::consensus::state::address_funds::{AddressDoesNotExistError, AddressInvalidNonceError, AddressNotEnoughFundsError, AddressesNotEnoughFundsError}; +use crate::consensus::state::shielded::insufficient_pool_notes_error::InsufficientPoolNotesError; use crate::consensus::state::shielded::invalid_anchor_error::InvalidAnchorError; use crate::consensus::state::shielded::invalid_shielded_proof_error::InvalidShieldedProofError; use crate::consensus::state::shielded::nullifier_already_spent_error::NullifierAlreadySpentError; @@ -346,6 +347,9 @@ pub enum StateError { #[error(transparent)] InvalidShieldedProofError(InvalidShieldedProofError), + + #[error(transparent)] + InsufficientPoolNotesError(InsufficientPoolNotesError), } impl From for ConsensusError { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs index 61e38554169..e5ce68f9756 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs @@ -18,7 +18,7 @@ mod tests { use dpp::withdrawal::Pooling; use drive::drive::shielded::paths::{ shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, - shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY, + shielded_credit_pool_path, shielded_credit_pool_encrypted_notes_path, SHIELDED_TOTAL_BALANCE_KEY, }; use drive::grovedb::Element; use platform_version::version::PlatformVersion; @@ -193,6 +193,41 @@ mod tests { .expect("should commit transaction"); } + /// Insert dummy encrypted notes into the shielded pool to meet the minimum + /// notes threshold for outgoing transitions. + fn insert_dummy_encrypted_notes( + platform: &crate::test::helpers::setup::TempPlatform, + count: u64, + ) { + let platform_version = PlatformVersion::latest(); + let grove_version = &platform_version.drive.grove_version; + let transaction = platform.drive.grove.start_transaction(); + let notes_path = shielded_credit_pool_encrypted_notes_path(); + + for i in 0..count { + platform + .drive + .grove + .insert( + ¬es_path, + &i.to_be_bytes(), + Element::Item(vec![0], None), + None, + Some(&transaction), + grove_version, + ) + .unwrap() + .expect("should insert dummy note"); + } + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("should commit transaction"); + } + /// Standard platform setup for tests. fn setup_platform( ) -> crate::test::helpers::setup::TempPlatform { @@ -456,10 +491,35 @@ mod tests { mod anchor_validation { use super::*; + #[test] + fn test_insufficient_pool_notes_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + // Set pool balance so the pool balance check would pass (if it got that far) + set_pool_total_balance(&platform, 10_000); + + // Non-zero anchor that exists in state, but no encrypted notes in pool + let anchor = [42u8; 32]; + insert_anchor_into_state(&platform, &anchor); + + let transition = create_default_shielded_withdrawal_transition(); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InsufficientPoolNotesError(_)) + )] + ); + } + #[test] fn test_anchor_not_in_tree_returns_error() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); // Non-zero anchor that doesn't exist in state let transition = create_default_shielded_withdrawal_transition(); @@ -486,6 +546,7 @@ mod tests { fn test_already_spent_nullifier_returns_error() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); let anchor = [42u8; 32]; let nullifier = [1u8; 32]; // Same as create_dummy_serialized_action().nullifier @@ -566,6 +627,7 @@ mod tests { fn test_invalid_proof_returns_shielded_proof_error() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); let anchor = [42u8; 32]; @@ -594,6 +656,7 @@ mod tests { fn test_valid_shielded_withdrawal_proof_succeeds() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); let mut rng = OsRng; let pk = get_proving_key(); @@ -683,6 +746,7 @@ mod tests { fn test_wrong_encrypted_note_size_returns_error() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); let anchor = [42u8; 32]; @@ -875,6 +939,7 @@ mod tests { fn test_valid_proof_with_zeroed_binding_sig_is_rejected() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); let output_script = create_output_script(); let amount = 5_000u64; @@ -922,6 +987,7 @@ mod tests { fn test_valid_proof_with_mutated_value_balance_is_rejected() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); // Bundle is signed for create_output_script() with amount = 5000 let output_script = create_output_script(); @@ -974,6 +1040,7 @@ mod tests { fn test_different_output_script_with_same_valid_bundle_is_rejected() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); // Bundle is signed for the ORIGINAL output_script with amount = 5000 let original_script = create_output_script(); @@ -1025,6 +1092,7 @@ mod tests { fn test_different_amount_with_same_valid_bundle_is_rejected() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); let output_script = create_output_script(); let signed_amount = 5_000u64; @@ -1077,6 +1145,7 @@ mod tests { fn test_duplicate_nullifiers_in_same_bundle() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); let anchor = [42u8; 32]; insert_anchor_into_state(&platform, &anchor); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs index c060058d03d..4ef408aa75c 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs @@ -1,6 +1,7 @@ use crate::error::Error; use crate::execution::validation::state_transition::state_transitions::shielded_common::reconstruct_and_verify_bundle; use dpp::block::block_info::BlockInfo; +use dpp::consensus::state::shielded::insufficient_pool_notes_error::InsufficientPoolNotesError; use dpp::consensus::state::shielded::invalid_anchor_error::InvalidAnchorError; use dpp::consensus::state::shielded::nullifier_already_spent_error::NullifierAlreadySpentError; use dpp::consensus::state::state_error::StateError; @@ -9,7 +10,7 @@ use dpp::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTra use dpp::version::PlatformVersion; use drive::drive::shielded::paths::{ shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, - shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY, + shielded_credit_pool_path, SHIELDED_ENCRYPTED_NOTES_KEY, SHIELDED_TOTAL_BALANCE_KEY, }; use drive::drive::Drive; use drive::grovedb::TransactionArg; @@ -75,6 +76,36 @@ impl ShieldedWithdrawalStateTransitionTransformIntoActionValidationV0 )? .unwrap_or(0); + // Check minimum notes threshold for outgoing transitions (anonymity set) + let min_notes = platform_version + .drive_abci + .validation_and_processing + .event_constants + .minimum_pool_notes_for_outgoing; + if min_notes > 0 { + let encrypted_notes_count = drive + .grove_get_raw_optional( + (&pool_path).into(), + &[SHIELDED_ENCRYPTED_NOTES_KEY], + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )? + .map(|element| element.count_value_or_default()) + .unwrap_or(0); + + if encrypted_notes_count < min_notes { + return Ok(ConsensusValidationResult::new_with_error( + StateError::InsufficientPoolNotesError(InsufficientPoolNotesError::new( + encrypted_notes_count, + min_notes, + )) + .into(), + )); + } + } + // Verify the pool has sufficient balance for the withdrawal. // value_balance is the total amount leaving the pool (amount + fee). let value_balance = match self { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs index cc3d6ef7031..b12163a60b0 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs @@ -17,7 +17,7 @@ mod tests { use dpp::state_transition::StateTransition; use drive::drive::shielded::paths::{ shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, - shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY, + shielded_credit_pool_path, shielded_credit_pool_encrypted_notes_path, SHIELDED_TOTAL_BALANCE_KEY, }; use drive::grovedb::Element; use platform_version::version::PlatformVersion; @@ -185,6 +185,41 @@ mod tests { .expect("should commit transaction"); } + /// Insert dummy encrypted notes into the shielded pool to meet the minimum + /// notes threshold for outgoing transitions. + fn insert_dummy_encrypted_notes( + platform: &crate::test::helpers::setup::TempPlatform, + count: u64, + ) { + let platform_version = PlatformVersion::latest(); + let grove_version = &platform_version.drive.grove_version; + let transaction = platform.drive.grove.start_transaction(); + let notes_path = shielded_credit_pool_encrypted_notes_path(); + + for i in 0..count { + platform + .drive + .grove + .insert( + ¬es_path, + &i.to_be_bytes(), + Element::Item(vec![0], None), + None, + Some(&transaction), + grove_version, + ) + .unwrap() + .expect("should insert dummy note"); + } + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("should commit transaction"); + } + /// Standard platform setup for tests. fn setup_platform( ) -> crate::test::helpers::setup::TempPlatform { @@ -434,10 +469,32 @@ mod tests { mod anchor_validation { use super::*; + #[test] + fn test_insufficient_pool_notes_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + // Non-zero anchor that exists in state, but no encrypted notes in pool + let anchor = [42u8; 32]; + insert_anchor_into_state(&platform, &anchor); + + let transition = create_default_unshield_transition(); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InsufficientPoolNotesError(_)) + )] + ); + } + #[test] fn test_invalid_anchor_returns_error() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); // Non-zero anchor that doesn't exist in state let transition = create_default_unshield_transition(); @@ -464,6 +521,7 @@ mod tests { fn test_nullifier_already_spent_returns_error() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); let anchor = [42u8; 32]; let nullifier = [1u8; 32]; // Same as create_dummy_serialized_action().nullifier @@ -541,6 +599,7 @@ mod tests { fn test_invalid_proof_returns_shielded_proof_error() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); let anchor = [42u8; 32]; @@ -566,6 +625,7 @@ mod tests { fn test_valid_unshield_proof_succeeds() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); let mut rng = OsRng; let pk = get_proving_key(); @@ -654,6 +714,7 @@ mod tests { fn test_wrong_encrypted_note_size_returns_error() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); let anchor = [42u8; 32]; @@ -804,6 +865,7 @@ mod tests { fn test_valid_proof_with_mutated_value_balance_is_rejected() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); // Bundle is signed for create_output_address() with amount = 5000 let output_address = create_output_address(); @@ -855,6 +917,7 @@ mod tests { fn test_different_output_address_with_same_valid_bundle_is_rejected() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); // Bundle is signed for the ORIGINAL address with amount = 5000 let original_address = create_output_address(); @@ -900,6 +963,7 @@ mod tests { fn test_duplicate_nullifiers_in_same_bundle() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); let anchor = [42u8; 32]; insert_anchor_into_state(&platform, &anchor); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs index 3b0c9f1d233..29045343d98 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs @@ -1,5 +1,6 @@ use crate::error::Error; use crate::execution::validation::state_transition::state_transitions::shielded_common::reconstruct_and_verify_bundle; +use dpp::consensus::state::shielded::insufficient_pool_notes_error::InsufficientPoolNotesError; use dpp::consensus::state::shielded::invalid_anchor_error::InvalidAnchorError; use dpp::consensus::state::shielded::nullifier_already_spent_error::NullifierAlreadySpentError; use dpp::consensus::state::state_error::StateError; @@ -8,7 +9,7 @@ use dpp::state_transition::unshield_transition::UnshieldTransition; use dpp::version::PlatformVersion; use drive::drive::shielded::paths::{ shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, - shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY, + shielded_credit_pool_path, SHIELDED_ENCRYPTED_NOTES_KEY, SHIELDED_TOTAL_BALANCE_KEY, }; use drive::drive::Drive; use drive::grovedb::TransactionArg; @@ -68,6 +69,36 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti )? .unwrap_or(0); + // Check minimum notes threshold for outgoing transitions (anonymity set) + let min_notes = platform_version + .drive_abci + .validation_and_processing + .event_constants + .minimum_pool_notes_for_outgoing; + if min_notes > 0 { + let encrypted_notes_count = drive + .grove_get_raw_optional( + (&pool_path).into(), + &[SHIELDED_ENCRYPTED_NOTES_KEY], + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )? + .map(|element| element.count_value_or_default()) + .unwrap_or(0); + + if encrypted_notes_count < min_notes { + return Ok(ConsensusValidationResult::new_with_error( + StateError::InsufficientPoolNotesError(InsufficientPoolNotesError::new( + encrypted_notes_count, + min_notes, + )) + .into(), + )); + } + } + // Verify the anchor exists in the recorded anchors tree let anchors_path = shielded_anchors_credit_pool_path(); let anchor_exists = drive.grove_has_raw( diff --git a/packages/rs-drive-abci/tests/strategy_tests/strategy.rs b/packages/rs-drive-abci/tests/strategy_tests/strategy.rs index c656b34544a..c9d7a6bc556 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/strategy.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/strategy.rs @@ -3,8 +3,15 @@ use crate::query::QueryStrategy; use dpp::block::block_info::BlockInfo; use dpp::dashcore::{Network, PrivateKey}; use dpp::dashcore::{ProTxHash, QuorumHash}; +use dpp::shielded::{compute_platform_sighash, SerializedAction}; use dpp::state_transition::identity_topup_transition::methods::IdentityTopUpTransitionMethodsV0; +use dpp::state_transition::shield_transition::methods::ShieldTransitionMethodsV0; +use dpp::state_transition::shield_transition::ShieldTransition; use dpp::ProtocolError; +use grovedb_commitment_tree::{ + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, Flags as OrchardFlags, + FullViewingKey, NoteValue, ProvingKey, Scope, SpendingKey, +}; use dpp::dashcore::secp256k1::SecretKey; use dpp::data_contract::document_type::random_document::CreateRandomDocument; @@ -109,6 +116,7 @@ use std::borrow::Cow; use std::collections::{BTreeMap, HashMap, HashSet}; use std::ops::RangeInclusive; use std::str::FromStr; +use std::sync::OnceLock; use strategy_tests::transitions::{ create_identity_credit_transfer_to_addresses_transition, create_identity_credit_transfer_to_addresses_transition_with_outputs, @@ -119,6 +127,44 @@ use strategy_tests::transitions::{ use strategy_tests::Strategy; use tenderdash_abci::proto::abci::{ExecTxResult, ValidatorSetUpdate}; +/// Cached Orchard proving key for strategy tests (~30s to build, reused across tests). +static TEST_PROVING_KEY: OnceLock = OnceLock::new(); + +fn get_proving_key() -> &'static ProvingKey { + TEST_PROVING_KEY.get_or_init(ProvingKey::build) +} + +/// Decompose an authorized Orchard bundle into platform serialization fields. +fn serialize_authorized_bundle( + bundle: &Bundle, +) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { + let actions: Vec = bundle + .actions() + .iter() + .map(|action| { + let enc = action.encrypted_note(); + let mut encrypted_note = Vec::with_capacity(692); + encrypted_note.extend_from_slice(&enc.epk_bytes); + encrypted_note.extend_from_slice(&enc.enc_ciphertext); + encrypted_note.extend_from_slice(&enc.out_ciphertext); + SerializedAction { + nullifier: action.nullifier().to_bytes(), + rk: <[u8; 32]>::from(action.rk()), + cmx: action.cmx().to_bytes(), + encrypted_note, + cv_net: action.cv_net().to_bytes(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()), + } + }) + .collect(); + let flags = bundle.flags().to_byte(); + let value_balance = *bundle.value_balance(); + let anchor = bundle.anchor().to_bytes(); + let proof = bundle.authorization().proof().as_ref().to_vec(); + let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); + (actions, flags, value_balance, anchor, proof, binding_sig) +} + #[derive(Clone, Debug, Default)] pub struct MasternodeListChangesStrategy { /// How many new hpmns on average per core chain lock increase @@ -1833,6 +1879,20 @@ impl NetworkStrategy { operations.push(batch_transition); } + OperationType::Shield(amount_range) => { + for _i in 0..count { + let Some(state_transition) = self.create_shield_transition( + current_addresses_with_balance, + amount_range, + signer, + rng, + platform_version, + ) else { + break; + }; + operations.push(state_transition); + } + } _ => {} } } @@ -2452,6 +2512,98 @@ impl NetworkStrategy { Some(funding_transition) } + + /// Build a Shield state transition (transparent addresses → shielded pool). + /// + /// Creates an output-only Orchard bundle (no spends) with a real Halo 2 proof, + /// signs the address input witnesses, and returns the transition. + fn create_shield_transition( + &mut self, + current_addresses_with_balance: &mut AddressesWithBalance, + amount_range: &AmountRange, + signer: &mut SimpleSigner, + rng: &mut StdRng, + platform_version: &PlatformVersion, + ) -> Option { + // 1. Pick input addresses with sufficient balances + let inputs = + current_addresses_with_balance.take_random_amounts_with_range(amount_range, rng)?; + + let total_input: Credits = inputs.values().map(|(_, credits)| credits).sum(); + + tracing::debug!(?inputs, total_input, "Preparing shield transition"); + + // 2. Create deterministic Orchard recipient (same key each time is fine for testing) + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + + // 3. Build output-only Orchard bundle (shield = outputs only, no spends) + let anchor = Anchor::empty_tree(); + let mut builder = Builder::new( + BundleType::Transactional { + flags: OrchardFlags::SPENDS_DISABLED, + bundle_required: false, + }, + anchor, + ); + + // Use total_input as the shielded value (fee will be deducted from inputs) + // value_balance will be negative (money flowing into the pool) + let shield_value = total_input; + builder + .add_output( + None, + recipient, + NoteValue::from_raw(shield_value), + [0u8; 512], + ) + .expect("expected to add output"); + + // 4. Build → prove → sign + let pk = get_proving_key(); + let mut bundle_rng = rand::rngs::OsRng; + let (unauthorized, _) = builder + .build::(&mut bundle_rng) + .expect("expected to build bundle") + .expect("expected bundle to be present"); + + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &[]); + let proven = unauthorized + .create_proof(pk, &mut bundle_rng) + .expect("expected to create proof"); + let bundle = proven + .apply_signatures(bundle_rng, sighash, &[]) + .expect("expected to apply signatures"); + + // 5. Decompose bundle into platform serialization fields + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + + // 6. Build ShieldTransition with signed address witnesses + let fee_strategy: AddressFundsFeeStrategy = + vec![AddressFundsFeeStrategyStep::DeductFromInput(0)].into(); + + let shield_transition = ShieldTransition::try_from_bundle_with_signer( + inputs, + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + fee_strategy, + signer, + 0, + platform_version, + ) + .expect("expected to create shield transition"); + + tracing::debug!("Shield transition successfully built and signed"); + + Some(shield_transition) + } } pub enum StrategyRandomness { diff --git a/packages/rs-drive-abci/tests/strategy_tests/test_cases/mod.rs b/packages/rs-drive-abci/tests/strategy_tests/test_cases/mod.rs index f48de066702..ae385fd7531 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/test_cases/mod.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/test_cases/mod.rs @@ -6,6 +6,7 @@ mod core_update_tests; mod data_contract_history_tests; mod identity_and_document_tests; mod identity_transfer_tests; +mod shielded_tests; mod token_tests; mod top_up_tests; mod update_identities_tests; diff --git a/packages/rs-drive-abci/tests/strategy_tests/test_cases/shielded_tests.rs b/packages/rs-drive-abci/tests/strategy_tests/test_cases/shielded_tests.rs new file mode 100644 index 00000000000..579d7c5e53d --- /dev/null +++ b/packages/rs-drive-abci/tests/strategy_tests/test_cases/shielded_tests.rs @@ -0,0 +1,125 @@ +#[cfg(test)] +mod tests { + + use crate::execution::run_chain_for_strategy; + use crate::strategy::NetworkStrategy; + use dpp::dash_to_credits; + use dpp::state_transition::StateTransition; + use drive_abci::config::{ + ChainLockConfig, ExecutionConfig, InstantLockConfig, PlatformConfig, PlatformTestConfig, + ValidatorSetConfig, + }; + use drive_abci::logging::LogLevel; + use drive_abci::test::helpers::setup::TestPlatformBuilder; + use strategy_tests::frequency::Frequency; + use strategy_tests::operations::{Operation, OperationType}; + use strategy_tests::{IdentityInsertInfo, StartAddresses, StartIdentities, Strategy}; + + /// Strategy test that funds addresses via asset locks and then shields funds + /// into the shielded credit pool through the multi-block execution pipeline. + /// + /// This exercises the full Shield transition lifecycle: + /// 1. Orchard bundle building (output-only, no spends) + /// 2. Halo 2 ZK proof generation (via cached ProvingKey) + /// 3. Address input witness signing + /// 4. Platform validation (structure + state + ZK proof verification) + /// 5. Storage operations (commitment tree, encrypted notes, pool balance) + /// + /// Note: The first run takes ~30s to build the ProvingKey (cached via OnceLock). + #[test] + fn run_chain_shield_transitions() { + drive_abci::logging::init_for_tests(LogLevel::Debug); + + let strategy = NetworkStrategy { + strategy: Strategy { + start_contracts: vec![], + operations: vec![ + // Fund addresses first (every block, 2-3 asset locks of 20 DASH each) + Operation { + op_type: OperationType::AddressFundingFromCoreAssetLock( + dash_to_credits!(20)..=dash_to_credits!(20), + ), + frequency: Frequency { + times_per_block_range: 2..4, + chance_per_block: None, + }, + }, + // Shield funds from funded addresses (1 per block, 1-5 DASH) + Operation { + op_type: OperationType::Shield( + dash_to_credits!(1)..=dash_to_credits!(5), + ), + frequency: Frequency { + times_per_block_range: 1..2, + chance_per_block: None, + }, + }, + ], + start_identities: StartIdentities::default(), + start_addresses: StartAddresses::default(), + identity_inserts: IdentityInsertInfo::default(), + identity_contract_nonce_gaps: None, + signer: None, + }, + total_hpmns: 100, + extra_normal_mns: 0, + validator_quorum_count: 24, + chain_lock_quorum_count: 24, + upgrading_info: None, + + proposer_strategy: Default::default(), + rotate_quorums: false, + failure_testing: None, + query_testing: None, + // Shield proof verification is implemented but we keep this simple + verify_state_transition_results: false, + sign_instant_locks: true, + ..Default::default() + }; + + let config = PlatformConfig { + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), + execution: ExecutionConfig { + verify_sum_trees: true, + ..Default::default() + }, + block_spacing_ms: 3000, + testing_configs: PlatformTestConfig::default_minimal_verifications(), + ..Default::default() + }; + + let mut platform = TestPlatformBuilder::new() + .with_config(config.clone()) + .build_with_mock_rpc(); + + let outcome = run_chain_for_strategy( + &mut platform, + 5, + strategy, + config, + 15, + &mut None, + &mut None, + ); + + // Count successful shield transitions across all blocks + let shield_count = outcome + .state_transition_results_per_block + .values() + .flat_map(|results| results.iter()) + .filter(|(st, result)| matches!(st, StateTransition::Shield(_)) && result.code == 0) + .count(); + + assert!( + shield_count > 0, + "expected at least one successful shield transition across 5 blocks" + ); + + tracing::info!( + shield_count, + "Shield strategy test completed successfully" + ); + } +} 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 7f68f5fb613..022b69f0bb3 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 @@ -24,6 +24,10 @@ pub struct DriveAbciValidationVersions { pub struct DriveAbciValidationConstants { pub maximum_vote_polls_to_process: u16, pub maximum_contenders_to_consider: u16, + /// Minimum number of encrypted notes in the shielded pool before outgoing + /// transitions (Unshield, ShieldedWithdrawal) are allowed. This ensures a + /// sufficient anonymity set before funds can leave the pool. + pub minimum_pool_notes_for_outgoing: u64, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs index 53b31b49e4c..6226ad4c6bb 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs @@ -257,5 +257,6 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V1: DriveAbciValidationVersions = event_constants: DriveAbciValidationConstants { maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, + minimum_pool_notes_for_outgoing: 250, }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs index 19e77ba362c..1882d4a8ca2 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs @@ -257,5 +257,6 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V2: DriveAbciValidationVersions = event_constants: DriveAbciValidationConstants { maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, + minimum_pool_notes_for_outgoing: 250, }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs index dbbb6bcd9b5..aecb62ff893 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs @@ -257,5 +257,6 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V3: DriveAbciValidationVersions = event_constants: DriveAbciValidationConstants { maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, + minimum_pool_notes_for_outgoing: 250, }, }; 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 0d17c1c432c..9755ffa344d 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 @@ -260,5 +260,6 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V4: DriveAbciValidationVersions = event_constants: DriveAbciValidationConstants { maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, + minimum_pool_notes_for_outgoing: 250, }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs index 6368e6927d3..425d4726e26 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs @@ -261,5 +261,6 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V5: DriveAbciValidationVersions = event_constants: DriveAbciValidationConstants { maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, + minimum_pool_notes_for_outgoing: 250, }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs index 18bfcbbe660..0f5396a58e3 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs @@ -264,5 +264,6 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V6: DriveAbciValidationVersions = event_constants: DriveAbciValidationConstants { maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, + minimum_pool_notes_for_outgoing: 250, }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs index 422cb31cf27..8653370db94 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs @@ -258,5 +258,6 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V7: DriveAbciValidationVersions = event_constants: DriveAbciValidationConstants { maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, + minimum_pool_notes_for_outgoing: 250, }, }; diff --git a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs index 672470cfdd7..7a8260989a2 100644 --- a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs +++ b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs @@ -88,7 +88,7 @@ use dpp::consensus::state::prefunded_specialized_balances::prefunded_specialized use dpp::consensus::state::prefunded_specialized_balances::prefunded_specialized_balance_not_found_error::PrefundedSpecializedBalanceNotFoundError; use dpp::consensus::state::token::{IdentityDoesNotHaveEnoughTokenBalanceError, IdentityTokenAccountNotFrozenError, IdentityTokenAccountFrozenError, TokenIsPausedError, IdentityTokenAccountAlreadyFrozenError, UnauthorizedTokenActionError, TokenSettingMaxSupplyToLessThanCurrentSupplyError, TokenMintPastMaxSupplyError, NewTokensDestinationIdentityDoesNotExistError, NewAuthorizedActionTakerIdentityDoesNotExistError, NewAuthorizedActionTakerGroupDoesNotExistError, NewAuthorizedActionTakerMainGroupNotSetError, InvalidGroupPositionError, TokenAlreadyPausedError, TokenNotPausedError, InvalidTokenClaimPropertyMismatch, InvalidTokenClaimNoCurrentRewards, InvalidTokenClaimWrongClaimant, TokenTransferRecipientIdentityNotExistError, PreProgrammedDistributionTimestampInPastError, IdentityHasNotAgreedToPayRequiredTokenAmountError, RequiredTokenPaymentInfoNotSetError, IdentityTryingToPayWithWrongTokenError, TokenDirectPurchaseUserPriceTooLow, TokenAmountUnderMinimumSaleAmount, TokenNotForDirectSale, InvalidTokenPositionStateError}; use dpp::consensus::state::address_funds::{AddressDoesNotExistError, AddressInvalidNonceError, AddressNotEnoughFundsError, AddressesNotEnoughFundsError}; -use dpp::consensus::state::shielded::{InvalidAnchorError, InvalidShieldedProofError, NullifierAlreadySpentError}; +use dpp::consensus::state::shielded::{InsufficientPoolNotesError, InvalidAnchorError, InvalidShieldedProofError, NullifierAlreadySpentError}; use dpp::consensus::basic::state_transition::{StateTransitionNotActiveError, TransitionOverMaxInputsError, TransitionOverMaxOutputsError, InputWitnessCountMismatchError, TransitionNoInputsError, TransitionNoOutputsError, FeeStrategyEmptyError, FeeStrategyDuplicateError, FeeStrategyIndexOutOfBoundsError, FeeStrategyTooManyStepsError, InputBelowMinimumError, OutputBelowMinimumError, InputOutputBalanceMismatchError, OutputsNotGreaterThanInputsError, WithdrawalBalanceMismatchError, InsufficientFundingAmountError, InputsNotLessThanOutputsError, OutputAddressAlsoInputError, InvalidRemainderOutputCountError, WithdrawalBelowMinAmountError, ShieldedNoActionsError, ShieldedEmptyProofError, ShieldedZeroAnchorError, ShieldedInvalidValueBalanceError, UnshieldAmountZeroError, UnshieldValueBalanceBelowAmountError}; use dpp::consensus::state::voting::masternode_incorrect_voter_identity_id_error::MasternodeIncorrectVoterIdentityIdError; use dpp::consensus::state::voting::masternode_incorrect_voting_address_error::MasternodeIncorrectVotingAddressError; @@ -451,6 +451,9 @@ pub fn from_state_error(state_error: &StateError) -> JsValue { StateError::InvalidShieldedProofError(e) => { generic_consensus_error!(InvalidShieldedProofError, e).into() } + StateError::InsufficientPoolNotesError(e) => { + generic_consensus_error!(InsufficientPoolNotesError, e).into() + } } } From 58056fb77e16c9104f139e4451adbfe7329bbf14 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 11 Feb 2026 22:57:01 +0000 Subject: [PATCH 13/40] more work --- .../shielded_withdrawal/tests.rs | 5 +++-- .../state_transitions/unshield/tests.rs | 5 +++-- .../test_cases/shielded_tests.rs | 20 ++++--------------- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs index e5ce68f9756..fa13bb09deb 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs @@ -17,8 +17,9 @@ mod tests { use dpp::state_transition::StateTransition; use dpp::withdrawal::Pooling; use drive::drive::shielded::paths::{ - shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, - shielded_credit_pool_path, shielded_credit_pool_encrypted_notes_path, SHIELDED_TOTAL_BALANCE_KEY, + shielded_anchors_credit_pool_path, shielded_credit_pool_encrypted_notes_path, + shielded_credit_pool_nullifiers_path, shielded_credit_pool_path, + SHIELDED_TOTAL_BALANCE_KEY, }; use drive::grovedb::Element; use platform_version::version::PlatformVersion; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs index b12163a60b0..b436af1f9b8 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs @@ -16,8 +16,9 @@ mod tests { use dpp::state_transition::unshield_transition::UnshieldTransition; use dpp::state_transition::StateTransition; use drive::drive::shielded::paths::{ - shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, - shielded_credit_pool_path, shielded_credit_pool_encrypted_notes_path, SHIELDED_TOTAL_BALANCE_KEY, + shielded_anchors_credit_pool_path, shielded_credit_pool_encrypted_notes_path, + shielded_credit_pool_nullifiers_path, shielded_credit_pool_path, + SHIELDED_TOTAL_BALANCE_KEY, }; use drive::grovedb::Element; use platform_version::version::PlatformVersion; diff --git a/packages/rs-drive-abci/tests/strategy_tests/test_cases/shielded_tests.rs b/packages/rs-drive-abci/tests/strategy_tests/test_cases/shielded_tests.rs index 579d7c5e53d..eafef099e7e 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/test_cases/shielded_tests.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/test_cases/shielded_tests.rs @@ -46,9 +46,7 @@ mod tests { }, // Shield funds from funded addresses (1 per block, 1-5 DASH) Operation { - op_type: OperationType::Shield( - dash_to_credits!(1)..=dash_to_credits!(5), - ), + op_type: OperationType::Shield(dash_to_credits!(1)..=dash_to_credits!(5)), frequency: Frequency { times_per_block_range: 1..2, chance_per_block: None, @@ -94,15 +92,8 @@ mod tests { .with_config(config.clone()) .build_with_mock_rpc(); - let outcome = run_chain_for_strategy( - &mut platform, - 5, - strategy, - config, - 15, - &mut None, - &mut None, - ); + let outcome = + run_chain_for_strategy(&mut platform, 5, strategy, config, 15, &mut None, &mut None); // Count successful shield transitions across all blocks let shield_count = outcome @@ -117,9 +108,6 @@ mod tests { "expected at least one successful shield transition across 5 blocks" ); - tracing::info!( - shield_count, - "Shield strategy test completed successfully" - ); + tracing::info!(shield_count, "Shield strategy test completed successfully"); } } From 99342bca975b9acbf2d6e18b113135acb0b4cdaf Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Thu, 12 Feb 2026 05:59:29 +0000 Subject: [PATCH 14/40] more work --- .../shielded_invalid_value_balance_error.rs | 5 + ...shield_value_balance_below_amount_error.rs | 2 +- packages/rs-dpp/src/errors/consensus/codes.rs | 1 + .../shielded/insufficient_pool_notes_error.rs | 2 +- .../shielded/common_validation.rs | 41 ++ .../state_transitions/shielded/mod.rs | 1 + .../shield_from_asset_lock_transition/mod.rs | 2 + .../v0/mod.rs | 2 +- .../v0/state_transition_like.rs | 2 +- .../v0/state_transition_validation.rs | 24 +- .../shield_transition/methods/v0/mod.rs | 1 + .../shielded/shield_transition/mod.rs | 2 + .../shielded/shield_transition/v0/mod.rs | 2 +- .../v0/state_transition_like.rs | 2 +- .../v0/state_transition_validation.rs | 24 +- .../methods/mod.rs | 6 +- .../methods/v0/mod.rs | 7 +- .../shielded_transfer_transition/mod.rs | 2 + .../shielded_transfer_transition/v0/mod.rs | 4 +- .../v0/state_transition_like.rs | 2 +- .../v0/state_transition_validation.rs | 33 +- .../v0/v0_methods.rs | 6 +- .../methods/mod.rs | 6 + .../methods/v0/mod.rs | 6 + .../shielded_withdrawal_transition/mod.rs | 2 + .../shielded_withdrawal_transition/v0/mod.rs | 2 +- .../v0/state_transition_like.rs | 2 +- .../v0/state_transition_validation.rs | 24 +- .../v0/v0_methods.rs | 6 + .../unshield_transition/methods/mod.rs | 5 + .../unshield_transition/methods/v0/mod.rs | 6 + .../shielded/unshield_transition/mod.rs | 2 + .../shielded/unshield_transition/v0/mod.rs | 2 +- .../v0/state_transition_like.rs | 2 +- .../v0/state_transition_validation.rs | 24 +- .../unshield_transition/v0/v0_methods.rs | 5 + .../execution/types/execution_event/mod.rs | 10 + .../state_transitions/shield/mod.rs | 8 + .../state_transitions/shield/tests.rs | 67 +-- .../shield/transform_into_action/v0/mod.rs | 38 +- .../shield_from_asset_lock/mod.rs | 4 + .../shield_from_asset_lock/tests.rs | 66 +-- .../transform_into_action/v0/mod.rs | 36 +- .../state_transitions/shielded_common/mod.rs | 151 ++++++- .../shielded_transfer/mod.rs | 14 +- .../shielded_transfer/tests.rs | 187 +-------- .../transform_into_action/v0/mod.rs | 148 ++++--- .../shielded_withdrawal/mod.rs | 12 +- .../shielded_withdrawal/tests.rs | 205 +-------- .../transform_into_action/v0/mod.rs | 157 +++---- .../state_transitions/test_helpers.rs | 194 ++++++++- .../state_transitions/unshield/mod.rs | 14 +- .../state_transitions/unshield/tests.rs | 205 +-------- .../unshield/transform_into_action/v0/mod.rs | 175 ++++---- .../state_transition/transformer/mod.rs | 29 +- .../query/shielded/encrypted_notes/v0/mod.rs | 11 - .../src/query/shielded/nullifiers/v0/mod.rs | 13 + packages/rs-drive-proof-verifier/src/types.rs | 2 +- .../action_convert_to_operations/mod.rs | 4 + .../shielded/mod.rs | 395 +++--------------- .../shield_from_asset_lock_transition.rs | 81 ++++ .../shielded/shield_transition.rs | 67 +++ .../shielded/shielded_transfer_transition.rs | 62 +++ .../shielded_withdrawal_transition.rs | 82 ++++ .../shielded/unshield_transition.rs | 70 ++++ .../system/mod.rs | 1 + .../system/penalize_shielded_pool.rs | 38 ++ .../src/state_transition_action/mod.rs | 6 + .../shielded/shield/mod.rs | 4 +- .../shielded/shield/v0/mod.rs | 2 +- .../shielded/shield_from_asset_lock/mod.rs | 4 +- .../shielded/shielded_transfer/mod.rs | 6 +- .../shielded/shielded_transfer/v0/mod.rs | 2 +- .../shielded/shielded_withdrawal/mod.rs | 6 +- .../shielded_withdrawal/v0/transformer.rs | 4 +- .../shielded/unshield/mod.rs | 6 +- .../shielded/unshield/v0/mod.rs | 2 +- .../src/state_transition_action/system/mod.rs | 3 + .../penalize_shielded_pool_action/mod.rs | 40 ++ .../penalize_shielded_pool_action/v0/mod.rs | 12 + .../src/util/batch/drive_op_batch/shielded.rs | 8 +- .../shielded/verify_shielded_anchors/mod.rs | 2 +- .../verify_shielded_anchors/v0/mod.rs | 16 +- .../verify_shielded_encrypted_notes/v0/mod.rs | 32 +- .../mod.rs | 2 + .../v1.rs | 2 + .../v2.rs | 2 + .../platform/transition/shielded_transfer.rs | 4 +- .../shield_from_asset_lock_transition.rs | 12 +- .../src/shielded/shield_transition.rs | 12 +- .../shielded/shielded_transfer_transition.rs | 12 +- .../shielded_withdrawal_transition.rs | 12 +- .../src/shielded/unshield_transition.rs | 12 +- 93 files changed, 1552 insertions(+), 1486 deletions(-) create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/common_validation.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_from_asset_lock_transition.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_transition.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs create mode 100644 packages/rs-drive/src/state_transition_action/action_convert_to_operations/system/penalize_shielded_pool.rs create mode 100644 packages/rs-drive/src/state_transition_action/system/penalize_shielded_pool_action/mod.rs create mode 100644 packages/rs-drive/src/state_transition_action/system/penalize_shielded_pool_action/v0/mod.rs diff --git a/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_invalid_value_balance_error.rs b/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_invalid_value_balance_error.rs index ea73a426d46..77cc5176e88 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_invalid_value_balance_error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_invalid_value_balance_error.rs @@ -16,6 +16,11 @@ pub struct ShieldedInvalidValueBalanceError { DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION */ + /// A human-readable description of the validation failure (e.g. "must be negative", + /// "must be positive", "must be zero"). Ideally this would be typed fields such as + /// `value_balance: i64` and `reason: &'static str`, but because this struct derives + /// `PlatformSerialize`/`Encode` and is part of the consensus protocol (error code 10822), + /// changing the field layout would break wire compatibility. Use a new version instead. message: String, } diff --git a/packages/rs-dpp/src/errors/consensus/basic/state_transition/unshield_value_balance_below_amount_error.rs b/packages/rs-dpp/src/errors/consensus/basic/state_transition/unshield_value_balance_below_amount_error.rs index 910eea46de0..bbaae67bfb6 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/state_transition/unshield_value_balance_below_amount_error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/state_transition/unshield_value_balance_below_amount_error.rs @@ -8,7 +8,7 @@ use thiserror::Error; #[derive( Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, )] -#[error("Unshield value_balance ({value_balance}) must be >= amount ({amount})")] +#[error("value_balance ({value_balance}) must be >= amount ({amount})")] #[platform_serialize(unversioned)] pub struct UnshieldValueBalanceBelowAmountError { /* diff --git a/packages/rs-dpp/src/errors/consensus/codes.rs b/packages/rs-dpp/src/errors/consensus/codes.rs index 7019611c4c5..294f2c3ad68 100644 --- a/packages/rs-dpp/src/errors/consensus/codes.rs +++ b/packages/rs-dpp/src/errors/consensus/codes.rs @@ -232,6 +232,7 @@ impl ErrorWithCode for BasicError { Self::OutputAddressAlsoInputError(_) => 10816, Self::InvalidRemainderOutputCountError(_) => 10817, Self::WithdrawalBelowMinAmountError(_) => 10818, + // Shielded transition errors (10819-10824) Self::ShieldedNoActionsError(_) => 10819, Self::ShieldedEmptyProofError(_) => 10820, Self::ShieldedZeroAnchorError(_) => 10821, diff --git a/packages/rs-dpp/src/errors/consensus/state/shielded/insufficient_pool_notes_error.rs b/packages/rs-dpp/src/errors/consensus/state/shielded/insufficient_pool_notes_error.rs index 6e193ef0f56..3358017ab95 100644 --- a/packages/rs-dpp/src/errors/consensus/state/shielded/insufficient_pool_notes_error.rs +++ b/packages/rs-dpp/src/errors/consensus/state/shielded/insufficient_pool_notes_error.rs @@ -10,7 +10,7 @@ use thiserror::Error; )] #[platform_serialize(unversioned)] #[error( - "shielded pool has insufficient notes for outgoing transition: pool has {current_count} notes but minimum {minimum_required} required" + "Shielded pool has insufficient notes for outgoing transition: pool has {current_count} notes but minimum {minimum_required} required" )] pub struct InsufficientPoolNotesError { /* diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/common_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/common_validation.rs new file mode 100644 index 00000000000..b2ea5e97f24 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/common_validation.rs @@ -0,0 +1,41 @@ +use crate::consensus::basic::state_transition::{ + ShieldedEmptyProofError, ShieldedNoActionsError, ShieldedZeroAnchorError, +}; +use crate::consensus::basic::BasicError; +use crate::shielded::SerializedAction; +use crate::validation::SimpleConsensusValidationResult; + +/// Validate that the actions list is not empty. +pub fn validate_actions_not_empty( + actions: &[SerializedAction], +) -> Option { + if actions.is_empty() { + Some(SimpleConsensusValidationResult::new_with_error( + BasicError::ShieldedNoActionsError(ShieldedNoActionsError::new()).into(), + )) + } else { + None + } +} + +/// Validate that the proof is not empty. +pub fn validate_proof_not_empty(proof: &[u8]) -> Option { + if proof.is_empty() { + Some(SimpleConsensusValidationResult::new_with_error( + BasicError::ShieldedEmptyProofError(ShieldedEmptyProofError::new()).into(), + )) + } else { + None + } +} + +/// Validate that the anchor is not all zeros (for transitions that consume notes). +pub fn validate_anchor_not_zero(anchor: &[u8; 32]) -> Option { + if *anchor == [0u8; 32] { + Some(SimpleConsensusValidationResult::new_with_error( + BasicError::ShieldedZeroAnchorError(ShieldedZeroAnchorError::new()).into(), + )) + } else { + None + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/mod.rs index 6201633ba62..cb79e3f690f 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/mod.rs @@ -1,3 +1,4 @@ +pub(crate) mod common_validation; pub mod shield_from_asset_lock_transition; pub mod shield_transition; pub mod shielded_transfer_transition; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/mod.rs index 1e87529f11a..4d496b73de7 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/mod.rs @@ -10,6 +10,8 @@ use crate::state_transition::shield_from_asset_lock_transition::v0::ShieldFromAs use crate::state_transition::shield_from_asset_lock_transition::v0::ShieldFromAssetLockTransitionV0Signable; use crate::state_transition::StateTransitionFieldTypes; +pub type ShieldFromAssetLockTransitionLatest = ShieldFromAssetLockTransitionV0; + use crate::ProtocolError; use bincode::{Decode, Encode}; use derive_more::From; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs index f2faf935a67..f9f9e0d1cde 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs @@ -2,7 +2,7 @@ mod proved; mod state_transition_like; mod state_transition_validation; mod types; -mod v0_methods; +pub(super) mod v0_methods; mod version; use crate::identity::state_transition::asset_lock_proof::AssetLockProof; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_like.rs index 186631184dd..6314d80b308 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_like.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_like.rs @@ -27,7 +27,7 @@ impl StateTransitionLike for ShieldFromAssetLockTransitionV0 { StateTransitionType::ShieldFromAssetLock } - /// Returns IDs of the modified data + /// Returns IDs of modified data (none for shielded transitions) fn modified_data_ids(&self) -> Vec { vec![] } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_validation.rs index 345e6a141ce..407918caac5 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_validation.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_validation.rs @@ -1,8 +1,9 @@ -use crate::consensus::basic::state_transition::{ - ShieldedEmptyProofError, ShieldedInvalidValueBalanceError, ShieldedNoActionsError, -}; +use crate::consensus::basic::state_transition::ShieldedInvalidValueBalanceError; use crate::consensus::basic::BasicError; use crate::state_transition::shield_from_asset_lock_transition::v0::ShieldFromAssetLockTransitionV0; +use crate::state_transition::state_transitions::shielded::common_validation::{ + validate_actions_not_empty, validate_anchor_not_zero, validate_proof_not_empty, +}; use crate::state_transition::StateTransitionStructureValidation; use crate::validation::SimpleConsensusValidationResult; use platform_version::version::PlatformVersion; @@ -13,10 +14,8 @@ impl StateTransitionStructureValidation for ShieldFromAssetLockTransitionV0 { _platform_version: &PlatformVersion, ) -> SimpleConsensusValidationResult { // Actions must not be empty - if self.actions.is_empty() { - return SimpleConsensusValidationResult::new_with_error( - BasicError::ShieldedNoActionsError(ShieldedNoActionsError::new()).into(), - ); + if let Some(err) = validate_actions_not_empty(&self.actions) { + return err; } // value_balance must be negative (credits flowing into pool) @@ -32,10 +31,13 @@ impl StateTransitionStructureValidation for ShieldFromAssetLockTransitionV0 { } // Proof must not be empty - if self.proof.is_empty() { - return SimpleConsensusValidationResult::new_with_error( - BasicError::ShieldedEmptyProofError(ShieldedEmptyProofError::new()).into(), - ); + if let Some(err) = validate_proof_not_empty(&self.proof) { + return err; + } + + // Anchor must not be all zeros + if let Some(err) = validate_anchor_not_zero(&self.anchor) { + return err; } SimpleConsensusValidationResult::new() diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/methods/v0/mod.rs index 8ddca9d82a3..49f1d4d29e3 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/methods/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/methods/v0/mod.rs @@ -21,6 +21,7 @@ use platform_version::version::PlatformVersion; pub trait ShieldTransitionMethodsV0 { #[cfg(feature = "state-transition-signing")] + #[allow(clippy::too_many_arguments)] fn try_from_bundle_with_signer>( inputs: BTreeMap, actions: Vec, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/mod.rs index 1aaccded5ea..720b637ebfe 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/mod.rs @@ -9,6 +9,8 @@ use crate::state_transition::shield_transition::v0::ShieldTransitionV0; use crate::state_transition::shield_transition::v0::ShieldTransitionV0Signable; use crate::state_transition::StateTransitionFieldTypes; +pub type ShieldTransitionLatest = ShieldTransitionV0; + use crate::identity::state_transition::OptionallyAssetLockProved; use crate::ProtocolError; use bincode::{Decode, Encode}; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs index 1a8df6e526e..63463a36c85 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs @@ -2,7 +2,7 @@ mod state_transition_like; mod state_transition_validation; mod types; #[cfg(feature = "state-transition-signing")] -mod v0_methods; +pub(super) mod v0_methods; mod version; use std::collections::BTreeMap; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_like.rs index e41278acbdc..2fbe21a3f39 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_like.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_like.rs @@ -28,7 +28,7 @@ impl StateTransitionLike for ShieldTransitionV0 { Shield } - /// Returns ID of the created contract + /// Returns IDs of modified data (none for shielded transitions) fn modified_data_ids(&self) -> Vec { vec![] } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs index 418750cb3c6..a423e874cf1 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs @@ -1,10 +1,13 @@ use crate::consensus::basic::state_transition::{ FeeStrategyDuplicateError, FeeStrategyEmptyError, FeeStrategyTooManyStepsError, - InputBelowMinimumError, InputWitnessCountMismatchError, ShieldedEmptyProofError, - ShieldedInvalidValueBalanceError, ShieldedNoActionsError, TransitionNoInputsError, + InputBelowMinimumError, InputWitnessCountMismatchError, ShieldedInvalidValueBalanceError, + TransitionNoInputsError, }; use crate::consensus::basic::BasicError; use crate::state_transition::shield_transition::v0::ShieldTransitionV0; +use crate::state_transition::state_transitions::shielded::common_validation::{ + validate_actions_not_empty, validate_anchor_not_zero, validate_proof_not_empty, +}; use crate::state_transition::StateTransitionStructureValidation; use crate::validation::SimpleConsensusValidationResult; use platform_version::version::PlatformVersion; @@ -16,10 +19,8 @@ impl StateTransitionStructureValidation for ShieldTransitionV0 { platform_version: &PlatformVersion, ) -> SimpleConsensusValidationResult { // Actions must not be empty - if self.actions.is_empty() { - return SimpleConsensusValidationResult::new_with_error( - BasicError::ShieldedNoActionsError(ShieldedNoActionsError::new()).into(), - ); + if let Some(err) = validate_actions_not_empty(&self.actions) { + return err; } // Inputs must not be empty (shield requires address funding) @@ -72,10 +73,13 @@ impl StateTransitionStructureValidation for ShieldTransitionV0 { } // Proof must not be empty - if self.proof.is_empty() { - return SimpleConsensusValidationResult::new_with_error( - BasicError::ShieldedEmptyProofError(ShieldedEmptyProofError::new()).into(), - ); + if let Some(err) = validate_proof_not_empty(&self.proof) { + return err; + } + + // Anchor must not be all zeros + if let Some(err) = validate_anchor_not_zero(&self.anchor) { + return err; } // Fee strategy validation (reuse address funds patterns) diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/mod.rs index 7b48e98ba1e..b0af25fa28a 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/mod.rs @@ -2,8 +2,10 @@ mod v0; pub use v0::*; +#[cfg(feature = "state-transition-signing")] use crate::shielded::SerializedAction; use crate::state_transition::shielded_transfer_transition::ShieldedTransferTransition; +#[cfg(feature = "state-transition-signing")] use crate::{ prelude::UserFeeIncrease, state_transition::{ @@ -11,13 +13,15 @@ use crate::{ }, ProtocolError, }; +#[cfg(feature = "state-transition-signing")] use platform_version::version::PlatformVersion; impl ShieldedTransferTransitionMethodsV0 for ShieldedTransferTransition { + #[cfg(feature = "state-transition-signing")] fn try_from_bundle( actions: Vec, flags: u8, - value_balance: i64, + value_balance: u64, anchor: [u8; 32], proof: Vec, binding_signature: [u8; 64], diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/v0/mod.rs index a72f656d871..45dfda02a85 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/v0/mod.rs @@ -1,13 +1,18 @@ +#[cfg(feature = "state-transition-signing")] use crate::shielded::SerializedAction; use crate::state_transition::StateTransitionType; +#[cfg(feature = "state-transition-signing")] use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; +#[cfg(feature = "state-transition-signing")] use platform_version::version::PlatformVersion; pub trait ShieldedTransferTransitionMethodsV0 { + #[cfg(feature = "state-transition-signing")] + #[allow(clippy::too_many_arguments)] fn try_from_bundle( actions: Vec, flags: u8, - value_balance: i64, + value_balance: u64, anchor: [u8; 32], proof: Vec, binding_signature: [u8; 64], diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/mod.rs index 9026cbd655d..9d22a44bab8 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/mod.rs @@ -9,6 +9,8 @@ use crate::state_transition::shielded_transfer_transition::v0::ShieldedTransferT use crate::state_transition::shielded_transfer_transition::v0::ShieldedTransferTransitionV0Signable; use crate::state_transition::StateTransitionFieldTypes; +pub type ShieldedTransferTransitionLatest = ShieldedTransferTransitionV0; + use crate::identity::state_transition::OptionallyAssetLockProved; use crate::ProtocolError; use bincode::{Decode, Encode}; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs index 4d92237f8ed..1a817ac2f60 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs @@ -1,7 +1,7 @@ mod state_transition_like; mod state_transition_validation; mod types; -mod v0_methods; +pub(super) mod v0_methods; mod version; use crate::prelude::UserFeeIncrease; @@ -34,7 +34,7 @@ pub struct ShieldedTransferTransitionV0 { /// Bundle flags (spends_enabled | outputs_enabled) pub flags: u8, /// Net value balance (fee amount extracted from shielded pool) - pub value_balance: i64, + pub value_balance: u64, /// Merkle root of the commitment tree used for spends pub anchor: [u8; 32], /// Halo2 proof bytes diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_like.rs index df051601d51..aa27728f8d6 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_like.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_like.rs @@ -27,7 +27,7 @@ impl StateTransitionLike for ShieldedTransferTransitionV0 { ShieldedTransfer } - /// Returns ID of the created contract + /// Returns IDs of modified data (none for shielded transitions) fn modified_data_ids(&self) -> Vec { vec![] } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs index 1205908f031..97f05189a73 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs @@ -1,9 +1,9 @@ -use crate::consensus::basic::state_transition::{ - ShieldedEmptyProofError, ShieldedInvalidValueBalanceError, ShieldedNoActionsError, - ShieldedZeroAnchorError, -}; +use crate::consensus::basic::state_transition::ShieldedInvalidValueBalanceError; use crate::consensus::basic::BasicError; use crate::state_transition::shielded_transfer_transition::v0::ShieldedTransferTransitionV0; +use crate::state_transition::state_transitions::shielded::common_validation::{ + validate_actions_not_empty, validate_anchor_not_zero, validate_proof_not_empty, +}; use crate::state_transition::StateTransitionStructureValidation; use crate::validation::SimpleConsensusValidationResult; use platform_version::version::PlatformVersion; @@ -14,19 +14,16 @@ impl StateTransitionStructureValidation for ShieldedTransferTransitionV0 { _platform_version: &PlatformVersion, ) -> SimpleConsensusValidationResult { // Actions must not be empty - if self.actions.is_empty() { - return SimpleConsensusValidationResult::new_with_error( - BasicError::ShieldedNoActionsError(ShieldedNoActionsError::new()).into(), - ); + if let Some(err) = validate_actions_not_empty(&self.actions) { + return err; } - // value_balance must be >= 0 (fee extracted from pool, 0 means no fee) - if self.value_balance < 0 { + // value_balance must fit in i64 (required for Orchard protocol) + if self.value_balance > i64::MAX as u64 { return SimpleConsensusValidationResult::new_with_error( BasicError::ShieldedInvalidValueBalanceError( ShieldedInvalidValueBalanceError::new( - "shielded transfer value_balance must be non-negative (fee only)" - .to_string(), + "shielded transfer value_balance exceeds maximum allowed value".to_string(), ), ) .into(), @@ -34,17 +31,13 @@ impl StateTransitionStructureValidation for ShieldedTransferTransitionV0 { } // Proof must not be empty - if self.proof.is_empty() { - return SimpleConsensusValidationResult::new_with_error( - BasicError::ShieldedEmptyProofError(ShieldedEmptyProofError::new()).into(), - ); + if let Some(err) = validate_proof_not_empty(&self.proof) { + return err; } // Anchor must not be all zeros - if self.anchor == [0u8; 32] { - return SimpleConsensusValidationResult::new_with_error( - BasicError::ShieldedZeroAnchorError(ShieldedZeroAnchorError::new()).into(), - ); + if let Some(err) = validate_anchor_not_zero(&self.anchor) { + return err; } SimpleConsensusValidationResult::new() diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/v0_methods.rs index 006bbe015f0..4447d14f1f2 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/v0_methods.rs @@ -1,14 +1,18 @@ +#[cfg(feature = "state-transition-signing")] use crate::shielded::SerializedAction; use crate::state_transition::shielded_transfer_transition::methods::ShieldedTransferTransitionMethodsV0; use crate::state_transition::shielded_transfer_transition::v0::ShieldedTransferTransitionV0; +#[cfg(feature = "state-transition-signing")] use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; +#[cfg(feature = "state-transition-signing")] use platform_version::version::PlatformVersion; impl ShieldedTransferTransitionMethodsV0 for ShieldedTransferTransitionV0 { + #[cfg(feature = "state-transition-signing")] fn try_from_bundle( actions: Vec, flags: u8, - value_balance: i64, + value_balance: u64, anchor: [u8; 32], proof: Vec, binding_signature: [u8; 64], diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/mod.rs index 50215bfbf45..84b2153623c 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/mod.rs @@ -2,10 +2,14 @@ mod v0; pub use v0::*; +#[cfg(feature = "state-transition-signing")] use crate::identity::core_script::CoreScript; +#[cfg(feature = "state-transition-signing")] use crate::shielded::SerializedAction; use crate::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; +#[cfg(feature = "state-transition-signing")] use crate::withdrawal::Pooling; +#[cfg(feature = "state-transition-signing")] use crate::{ prelude::UserFeeIncrease, state_transition::{ @@ -13,9 +17,11 @@ use crate::{ }, ProtocolError, }; +#[cfg(feature = "state-transition-signing")] use platform_version::version::PlatformVersion; impl ShieldedWithdrawalTransitionMethodsV0 for ShieldedWithdrawalTransition { + #[cfg(feature = "state-transition-signing")] fn try_from_bundle( amount: u64, actions: Vec, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/v0/mod.rs index 8781b68ff8a..75e62fd4fb6 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/v0/mod.rs @@ -1,11 +1,17 @@ +#[cfg(feature = "state-transition-signing")] use crate::identity::core_script::CoreScript; +#[cfg(feature = "state-transition-signing")] use crate::shielded::SerializedAction; use crate::state_transition::StateTransitionType; +#[cfg(feature = "state-transition-signing")] use crate::withdrawal::Pooling; +#[cfg(feature = "state-transition-signing")] use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; +#[cfg(feature = "state-transition-signing")] use platform_version::version::PlatformVersion; pub trait ShieldedWithdrawalTransitionMethodsV0 { + #[cfg(feature = "state-transition-signing")] #[allow(clippy::too_many_arguments)] fn try_from_bundle( amount: u64, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/mod.rs index 089f5cb389d..f4f56847ee4 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/mod.rs @@ -9,6 +9,8 @@ use crate::state_transition::shielded_withdrawal_transition::v0::ShieldedWithdra use crate::state_transition::shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0Signable; use crate::state_transition::StateTransitionFieldTypes; +pub type ShieldedWithdrawalTransitionLatest = ShieldedWithdrawalTransitionV0; + use crate::identity::state_transition::OptionallyAssetLockProved; use crate::ProtocolError; use bincode::{Decode, Encode}; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs index beb6225ee1e..afa629898f4 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs @@ -1,7 +1,7 @@ mod state_transition_like; mod state_transition_validation; mod types; -mod v0_methods; +pub(super) mod v0_methods; mod version; use crate::identity::core_script::CoreScript; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_like.rs index 24187f2492f..ea62fb381dc 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_like.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_like.rs @@ -27,7 +27,7 @@ impl StateTransitionLike for ShieldedWithdrawalTransitionV0 { ShieldedWithdrawal } - /// Returns ID of the created contract + /// Returns IDs of modified data (none for shielded transitions) fn modified_data_ids(&self) -> Vec { vec![] } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_validation.rs index c587643a585..db89ea551c4 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_validation.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_validation.rs @@ -1,9 +1,11 @@ use crate::consensus::basic::state_transition::{ - ShieldedEmptyProofError, ShieldedInvalidValueBalanceError, ShieldedNoActionsError, - ShieldedZeroAnchorError, UnshieldAmountZeroError, UnshieldValueBalanceBelowAmountError, + ShieldedInvalidValueBalanceError, UnshieldAmountZeroError, UnshieldValueBalanceBelowAmountError, }; use crate::consensus::basic::BasicError; use crate::state_transition::shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0; +use crate::state_transition::state_transitions::shielded::common_validation::{ + validate_actions_not_empty, validate_anchor_not_zero, validate_proof_not_empty, +}; use crate::state_transition::StateTransitionStructureValidation; use crate::validation::SimpleConsensusValidationResult; use platform_version::version::PlatformVersion; @@ -14,10 +16,8 @@ impl StateTransitionStructureValidation for ShieldedWithdrawalTransitionV0 { _platform_version: &PlatformVersion, ) -> SimpleConsensusValidationResult { // Actions must not be empty - if self.actions.is_empty() { - return SimpleConsensusValidationResult::new_with_error( - BasicError::ShieldedNoActionsError(ShieldedNoActionsError::new()).into(), - ); + if let Some(err) = validate_actions_not_empty(&self.actions) { + return err; } // Amount must be > 0 @@ -50,17 +50,13 @@ impl StateTransitionStructureValidation for ShieldedWithdrawalTransitionV0 { } // Proof must not be empty - if self.proof.is_empty() { - return SimpleConsensusValidationResult::new_with_error( - BasicError::ShieldedEmptyProofError(ShieldedEmptyProofError::new()).into(), - ); + if let Some(err) = validate_proof_not_empty(&self.proof) { + return err; } // Anchor must not be all zeros - if self.anchor == [0u8; 32] { - return SimpleConsensusValidationResult::new_with_error( - BasicError::ShieldedZeroAnchorError(ShieldedZeroAnchorError::new()).into(), - ); + if let Some(err) = validate_anchor_not_zero(&self.anchor) { + return err; } SimpleConsensusValidationResult::new() diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/v0_methods.rs index 60ff12e632c..28095dbf0de 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/v0_methods.rs @@ -1,12 +1,18 @@ +#[cfg(feature = "state-transition-signing")] use crate::identity::core_script::CoreScript; +#[cfg(feature = "state-transition-signing")] use crate::shielded::SerializedAction; use crate::state_transition::shielded_withdrawal_transition::methods::ShieldedWithdrawalTransitionMethodsV0; use crate::state_transition::shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0; +#[cfg(feature = "state-transition-signing")] use crate::withdrawal::Pooling; +#[cfg(feature = "state-transition-signing")] use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; +#[cfg(feature = "state-transition-signing")] use platform_version::version::PlatformVersion; impl ShieldedWithdrawalTransitionMethodsV0 for ShieldedWithdrawalTransitionV0 { + #[cfg(feature = "state-transition-signing")] fn try_from_bundle( amount: u64, actions: Vec, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/mod.rs index 8ba9d1040c8..224f5542171 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/mod.rs @@ -2,17 +2,22 @@ mod v0; pub use v0::*; +#[cfg(feature = "state-transition-signing")] use crate::address_funds::PlatformAddress; +#[cfg(feature = "state-transition-signing")] use crate::shielded::SerializedAction; use crate::state_transition::unshield_transition::UnshieldTransition; +#[cfg(feature = "state-transition-signing")] use crate::{ prelude::UserFeeIncrease, state_transition::{unshield_transition::v0::UnshieldTransitionV0, StateTransition}, ProtocolError, }; +#[cfg(feature = "state-transition-signing")] use platform_version::version::PlatformVersion; impl UnshieldTransitionMethodsV0 for UnshieldTransition { + #[cfg(feature = "state-transition-signing")] fn try_from_bundle( output_address: PlatformAddress, amount: u64, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/v0/mod.rs index 2765518cb79..7bf750ac53b 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/v0/mod.rs @@ -1,10 +1,16 @@ +#[cfg(feature = "state-transition-signing")] use crate::address_funds::PlatformAddress; +#[cfg(feature = "state-transition-signing")] use crate::shielded::SerializedAction; use crate::state_transition::StateTransitionType; +#[cfg(feature = "state-transition-signing")] use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; +#[cfg(feature = "state-transition-signing")] use platform_version::version::PlatformVersion; pub trait UnshieldTransitionMethodsV0 { + #[cfg(feature = "state-transition-signing")] + #[allow(clippy::too_many_arguments)] fn try_from_bundle( output_address: PlatformAddress, amount: u64, diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/mod.rs index 668f007e757..8fe541491b3 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/mod.rs @@ -9,6 +9,8 @@ use crate::state_transition::unshield_transition::v0::UnshieldTransitionV0; use crate::state_transition::unshield_transition::v0::UnshieldTransitionV0Signable; use crate::state_transition::StateTransitionFieldTypes; +pub type UnshieldTransitionLatest = UnshieldTransitionV0; + use crate::identity::state_transition::OptionallyAssetLockProved; use crate::ProtocolError; use bincode::{Decode, Encode}; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs index 99710b08c7c..ba27a4aadb2 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs @@ -1,7 +1,7 @@ mod state_transition_like; mod state_transition_validation; mod types; -mod v0_methods; +pub(super) mod v0_methods; mod version; use crate::address_funds::PlatformAddress; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_like.rs index f3c508f0f0e..85423c358bf 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_like.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_like.rs @@ -27,7 +27,7 @@ impl StateTransitionLike for UnshieldTransitionV0 { Unshield } - /// Returns ID of the created contract + /// Returns IDs of modified data (none for shielded transitions) fn modified_data_ids(&self) -> Vec { vec![] } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs index 68ee5ec3d83..71e41aa71f5 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs @@ -1,8 +1,10 @@ use crate::consensus::basic::state_transition::{ - ShieldedEmptyProofError, ShieldedInvalidValueBalanceError, ShieldedNoActionsError, - ShieldedZeroAnchorError, UnshieldAmountZeroError, UnshieldValueBalanceBelowAmountError, + ShieldedInvalidValueBalanceError, UnshieldAmountZeroError, UnshieldValueBalanceBelowAmountError, }; use crate::consensus::basic::BasicError; +use crate::state_transition::state_transitions::shielded::common_validation::{ + validate_actions_not_empty, validate_anchor_not_zero, validate_proof_not_empty, +}; use crate::state_transition::unshield_transition::v0::UnshieldTransitionV0; use crate::state_transition::StateTransitionStructureValidation; use crate::validation::SimpleConsensusValidationResult; @@ -14,10 +16,8 @@ impl StateTransitionStructureValidation for UnshieldTransitionV0 { _platform_version: &PlatformVersion, ) -> SimpleConsensusValidationResult { // Actions must not be empty - if self.actions.is_empty() { - return SimpleConsensusValidationResult::new_with_error( - BasicError::ShieldedNoActionsError(ShieldedNoActionsError::new()).into(), - ); + if let Some(err) = validate_actions_not_empty(&self.actions) { + return err; } // Amount must be > 0 @@ -50,17 +50,13 @@ impl StateTransitionStructureValidation for UnshieldTransitionV0 { } // Proof must not be empty - if self.proof.is_empty() { - return SimpleConsensusValidationResult::new_with_error( - BasicError::ShieldedEmptyProofError(ShieldedEmptyProofError::new()).into(), - ); + if let Some(err) = validate_proof_not_empty(&self.proof) { + return err; } // Anchor must not be all zeros - if self.anchor == [0u8; 32] { - return SimpleConsensusValidationResult::new_with_error( - BasicError::ShieldedZeroAnchorError(ShieldedZeroAnchorError::new()).into(), - ); + if let Some(err) = validate_anchor_not_zero(&self.anchor) { + return err; } SimpleConsensusValidationResult::new() diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/v0_methods.rs index 95b1f1231c9..ff4d97d10b9 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/v0_methods.rs @@ -1,11 +1,16 @@ +#[cfg(feature = "state-transition-signing")] use crate::address_funds::PlatformAddress; +#[cfg(feature = "state-transition-signing")] use crate::shielded::SerializedAction; use crate::state_transition::unshield_transition::methods::UnshieldTransitionMethodsV0; use crate::state_transition::unshield_transition::v0::UnshieldTransitionV0; +#[cfg(feature = "state-transition-signing")] use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; +#[cfg(feature = "state-transition-signing")] use platform_version::version::PlatformVersion; impl UnshieldTransitionMethodsV0 for UnshieldTransitionV0 { + #[cfg(feature = "state-transition-signing")] fn try_from_bundle( output_address: PlatformAddress, amount: u64, diff --git a/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs b/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs index 95f03fe4906..82ee1ae10ce 100644 --- a/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs +++ b/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs @@ -24,6 +24,7 @@ use drive::state_transition_action::shielded::shielded_transfer::ShieldedTransfe use drive::state_transition_action::shielded::unshield::UnshieldTransitionAction; use drive::state_transition_action::system::bump_address_input_nonces_action::BumpAddressInputNonceActionAccessorsV0; use drive::state_transition_action::system::partially_use_asset_lock_action::PartiallyUseAssetLockActionAccessorsV0; +use drive::state_transition_action::system::penalize_shielded_pool_action::PenalizeShieldedPoolActionAccessorsV0; use drive::util::batch::DriveOperation; /// An execution event @@ -500,6 +501,15 @@ impl ExecutionEvent<'_> { fees_to_add_to_pool: 0, }) } + StateTransitionAction::PenalizeShieldedPoolAction(ref penalize_action) => { + let penalty_amount = penalize_action.penalty_amount(); + let operations = + action.into_high_level_drive_operations(epoch, platform_version)?; + Ok(ExecutionEvent::PaidFixedCost { + operations, + fees_to_add_to_pool: penalty_amount, + }) + } _ => { let user_fee_increase = action.user_fee_increase(); let operations = diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/mod.rs index ba3a3dfa59e..9c840487a4a 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/mod.rs @@ -3,6 +3,7 @@ mod tests; mod transform_into_action; use dpp::address_funds::PlatformAddress; +use dpp::block::block_info::BlockInfo; use dpp::fee::Credits; use dpp::prelude::AddressNonce; use dpp::state_transition::shield_transition::ShieldTransition; @@ -13,6 +14,7 @@ use std::collections::BTreeMap; use crate::error::execution::ExecutionError; use crate::error::Error; +use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use crate::execution::validation::state_transition::shield::transform_into_action::v0::ShieldStateTransitionTransformIntoActionValidationV0; use crate::platform_types::platform::PlatformRef; use crate::rpc::core::CoreRPCLike; @@ -26,6 +28,8 @@ pub trait StateTransitionShieldTransitionActionTransformer { &self, platform: &PlatformRef, inputs_with_remaining_balance: BTreeMap, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, tx: TransactionArg, ) -> Result, Error>; } @@ -35,6 +39,8 @@ impl StateTransitionShieldTransitionActionTransformer for ShieldTransition { &self, platform: &PlatformRef, inputs_with_remaining_balance: BTreeMap, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, tx: TransactionArg, ) -> Result, Error> { let platform_version = platform.state.current_platform_version()?; @@ -50,6 +56,8 @@ impl StateTransitionShieldTransitionActionTransformer for ShieldTransition { platform.drive, tx, inputs_with_remaining_balance, + block_info, + execution_context, platform_version, ), version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs index 6a5149b70f3..6c93c77a546 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs @@ -1,18 +1,15 @@ #[cfg(test)] mod tests { - use crate::config::{PlatformConfig, PlatformTestConfig}; use crate::execution::validation::state_transition::state_transitions::shielded_common::compute_platform_sighash; use crate::execution::validation::state_transition::state_transitions::test_helpers::{ - create_dummy_witness, create_platform_address, setup_address_with_balance, - TestAddressSigner, + create_dummy_serialized_action, create_dummy_witness, create_platform_address, + process_transition, setup_address_with_balance, setup_platform, TestAddressSigner, }; use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; - use crate::test::helpers::setup::TestPlatformBuilder; use assert_matches::assert_matches; use dpp::address_funds::{ AddressFundsFeeStrategy, AddressFundsFeeStrategyStep, AddressWitness, PlatformAddress, }; - use dpp::block::block_info::BlockInfo; use dpp::consensus::basic::BasicError; use dpp::consensus::signature::SignatureError; use dpp::consensus::state::state_error::StateError; @@ -36,22 +33,9 @@ mod tests { use std::sync::OnceLock; // ========================================== - // Helper Functions + // Helper Functions (transition-specific) // ========================================== - /// Create a `SerializedAction` with syntactically valid sizes but meaningless crypto data. - /// Passes structure validation (correct field sizes) but will fail ZK proof verification. - fn create_dummy_serialized_action() -> SerializedAction { - SerializedAction { - nullifier: [1u8; 32], - rk: [2u8; 32], - cmx: [3u8; 32], - encrypted_note: vec![4u8; 692], // epk(32) + enc(580) + out(80) - cv_net: [5u8; 32], - spend_auth_sig: [6u8; 64], - } - } - /// Builds a raw `ShieldTransitionV0` with dummy witnesses. Used for structure validation tests /// that don't need valid signatures (the structure error is caught before or alongside witness /// validation, or inputs are empty so witness validation is vacuously true). @@ -150,51 +134,6 @@ mod tests { ) } - /// Standard platform setup for tests. - fn setup_platform( - ) -> crate::test::helpers::setup::TempPlatform { - let platform_config = PlatformConfig { - testing_configs: PlatformTestConfig { - disable_instant_lock_signature_verification: true, - ..Default::default() - }, - ..Default::default() - }; - - TestPlatformBuilder::new() - .with_config(platform_config) - .with_latest_protocol_version() - .build_with_mock_rpc() - .set_genesis_state() - } - - /// Execute a state transition through the full processing pipeline and return the result. - fn process_transition( - platform: &crate::test::helpers::setup::TempPlatform, - transition: StateTransition, - platform_version: &PlatformVersion, - ) -> crate::platform_types::state_transitions_processing_result::StateTransitionsProcessingResult - { - let transition_bytes = transition - .serialize_to_bytes() - .expect("should serialize transition"); - let platform_state = platform.state.load(); - let transaction = platform.drive.grove.start_transaction(); - - platform - .platform - .process_raw_state_transitions( - &vec![transition_bytes], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - false, - None, - ) - .expect("expected to process state transition") - } - // ========================================== // Orchard Proving Key (cached, ~30s to build) // ========================================== diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs index 0439508554b..8514137d2da 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs @@ -1,19 +1,24 @@ use crate::error::Error; -use crate::execution::validation::state_transition::state_transitions::shielded_common::reconstruct_and_verify_bundle; +use crate::execution::types::execution_operation::ValidationOperation; +use crate::execution::types::state_transition_execution_context::{ + StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0, +}; +use crate::execution::validation::state_transition::state_transitions::shielded_common::{ + read_pool_total_balance, reconstruct_and_verify_bundle, +}; use dpp::address_funds::PlatformAddress; +use dpp::block::block_info::BlockInfo; use dpp::consensus::state::shielded::invalid_shielded_proof_error::InvalidShieldedProofError; use dpp::consensus::state::state_error::StateError; use dpp::fee::Credits; use dpp::prelude::{AddressNonce, ConsensusValidationResult}; use dpp::state_transition::shield_transition::ShieldTransition; use dpp::version::PlatformVersion; -use drive::drive::shielded::paths::{shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY}; use drive::drive::Drive; use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::shield::ShieldTransitionAction; use drive::state_transition_action::system::bump_address_input_nonces_action::BumpAddressInputNoncesAction; use drive::state_transition_action::StateTransitionAction; -use drive::util::grove_operations::DirectQueryType; use std::collections::BTreeMap; pub(in crate::execution::validation::state_transition::state_transitions::shield) trait ShieldStateTransitionTransformIntoActionValidationV0 @@ -23,6 +28,8 @@ pub(in crate::execution::validation::state_transition::state_transitions::shield drive: &Drive, transaction: TransactionArg, inputs_with_remaining_balance: BTreeMap, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, platform_version: &PlatformVersion, ) -> Result, Error>; } @@ -33,6 +40,8 @@ impl ShieldStateTransitionTransformIntoActionValidationV0 for ShieldTransition { drive: &Drive, transaction: TransactionArg, inputs_with_remaining_balance: BTreeMap, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, platform_version: &PlatformVersion, ) -> Result, Error> { // Extract note commitments and encrypted notes from serialized actions @@ -75,18 +84,19 @@ impl ShieldStateTransitionTransformIntoActionValidationV0 for ShieldTransition { // Read current shielded pool state from GroveDB let mut drive_operations = vec![]; - let pool_path = shielded_credit_pool_path(); + let current_total_balance = + read_pool_total_balance(drive, transaction, &mut drive_operations, platform_version)?; - let current_total_balance = drive - .grove_get_raw_value_u64_from_encoded_var_vec( - (&pool_path).into(), - &[SHIELDED_TOTAL_BALANCE_KEY], - DirectQueryType::StatefulDirectQuery, - transaction, - &mut drive_operations, - &platform_version.drive, - )? - .unwrap_or(0); + // Calculate fees from the GroveDB operations + let fee = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + drive.config.epochs_per_era, + platform_version, + None, + )?; + execution_context.add_operation(ValidationOperation::PrecalculatedOperation(fee)); // Verify the ZK proof let (actions, flags, value_balance, anchor, proof, binding_signature) = match self { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/mod.rs index a1b47eef5ef..0d842f23284 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/mod.rs @@ -3,6 +3,7 @@ mod transform_into_action; #[cfg(test)] mod tests; +use dpp::block::block_info::BlockInfo; use dpp::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; use crate::error::execution::ExecutionError; @@ -25,6 +26,7 @@ pub(in crate::execution) trait StateTransitionShieldFromAssetLockTransitionActio platform: &PlatformRef, signable_bytes: Vec, validation_mode: ValidationMode, + block_info: &BlockInfo, execution_context: &mut StateTransitionExecutionContext, tx: TransactionArg, ) -> Result, Error>; @@ -38,6 +40,7 @@ impl StateTransitionShieldFromAssetLockTransitionActionTransformer platform: &PlatformRef, signable_bytes: Vec, validation_mode: ValidationMode, + block_info: &BlockInfo, execution_context: &mut StateTransitionExecutionContext, tx: TransactionArg, ) -> Result, Error> { @@ -54,6 +57,7 @@ impl StateTransitionShieldFromAssetLockTransitionActionTransformer platform, signable_bytes, validation_mode, + block_info, execution_context, tx, ), diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs index bd15d5f3076..4af3906a2c9 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs @@ -1,11 +1,11 @@ #[cfg(test)] mod tests { - use crate::config::{PlatformConfig, PlatformTestConfig}; use crate::execution::validation::state_transition::state_transitions::shielded_common::compute_platform_sighash; + use crate::execution::validation::state_transition::state_transitions::test_helpers::{ + create_dummy_serialized_action, process_transition, setup_platform, + }; use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; - use crate::test::helpers::setup::TestPlatformBuilder; use assert_matches::assert_matches; - use dpp::block::block_info::BlockInfo; use dpp::consensus::basic::BasicError; use dpp::consensus::signature::SignatureError; use dpp::consensus::state::state_error::StateError; @@ -31,22 +31,9 @@ mod tests { use std::sync::OnceLock; // ========================================== - // Helper Functions + // Helper Functions (transition-specific) // ========================================== - /// Create a `SerializedAction` with syntactically valid sizes but meaningless crypto data. - /// Passes structure validation (correct field sizes) but will fail ZK proof verification. - fn create_dummy_serialized_action() -> SerializedAction { - SerializedAction { - nullifier: [1u8; 32], - rk: [2u8; 32], - cmx: [3u8; 32], - encrypted_note: vec![4u8; 692], // epk(32) + enc(580) + out(80) - cv_net: [5u8; 32], - spend_auth_sig: [6u8; 64], - } - } - /// Creates an asset lock proof and returns it with the private key bytes for ECDSA signing. fn create_asset_lock_proof_with_key( rng: &mut StdRng, @@ -143,51 +130,6 @@ mod tests { )) } - /// Standard platform setup for tests with instant lock signature verification disabled. - fn setup_platform( - ) -> crate::test::helpers::setup::TempPlatform { - let platform_config = PlatformConfig { - testing_configs: PlatformTestConfig { - disable_instant_lock_signature_verification: true, - ..Default::default() - }, - ..Default::default() - }; - - TestPlatformBuilder::new() - .with_config(platform_config) - .with_latest_protocol_version() - .build_with_mock_rpc() - .set_genesis_state() - } - - /// Execute a state transition through the full processing pipeline and return the result. - fn process_transition( - platform: &crate::test::helpers::setup::TempPlatform, - transition: StateTransition, - platform_version: &PlatformVersion, - ) -> crate::platform_types::state_transitions_processing_result::StateTransitionsProcessingResult - { - let transition_bytes = transition - .serialize_to_bytes() - .expect("should serialize transition"); - let platform_state = platform.state.load(); - let transaction = platform.drive.grove.start_transaction(); - - platform - .platform - .process_raw_state_transitions( - &vec![transition_bytes], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - false, - None, - ) - .expect("expected to process state transition") - } - // ========================================== // Orchard Proving Key (cached, ~30s to build) // ========================================== diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs index 2e2c08e62f7..c6be736535b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs @@ -7,12 +7,15 @@ use crate::execution::types::state_transition_execution_context::{ }; use crate::execution::validation::state_transition::common::asset_lock::proof::validate::AssetLockProofValidation; use crate::execution::validation::state_transition::common::asset_lock::transaction::fetch_asset_lock_transaction_output_sync::fetch_asset_lock_transaction_output_sync; -use crate::execution::validation::state_transition::state_transitions::shielded_common::reconstruct_and_verify_bundle; +use crate::execution::validation::state_transition::state_transitions::shielded_common::{ + read_pool_total_balance, reconstruct_and_verify_bundle, +}; use crate::execution::validation::state_transition::ValidationMode; use crate::platform_types::platform::PlatformRef; use crate::platform_types::platform_state::PlatformStateV0Methods; use crate::rpc::core::CoreRPCLike; use dpp::asset_lock::reduced_asset_lock_value::{AssetLockValue, AssetLockValueGettersV0}; +use dpp::block::block_info::BlockInfo; use dpp::balances::credits::CREDITS_PER_DUFF; use dpp::consensus::basic::identity::IdentityAssetLockTransactionOutPointNotEnoughBalanceError; use dpp::consensus::signature::{BasicECDSAError, SignatureError}; @@ -28,13 +31,12 @@ use dpp::prelude::ConsensusValidationResult; use dpp::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; use dpp::state_transition::signable_bytes_hasher::SignableBytesHasher; use dpp::state_transition::{StateTransitionEstimatedFeeValidation, StateTransitionSingleSigned}; -use drive::drive::shielded::paths::{shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY}; +use drive::drive::Drive; use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::shield_from_asset_lock::ShieldFromAssetLockTransitionAction; use drive::state_transition_action::system::partially_use_asset_lock_action::PartiallyUseAssetLockActionV0; use drive::state_transition_action::system::partially_use_asset_lock_action::PartiallyUseAssetLockAction; use drive::state_transition_action::StateTransitionAction; -use drive::util::grove_operations::DirectQueryType; pub(in crate::execution::validation::state_transition::state_transitions::shield_from_asset_lock) trait ShieldFromAssetLockStateTransitionTransformIntoActionValidationV0 { @@ -43,6 +45,7 @@ pub(in crate::execution::validation::state_transition::state_transitions::shield platform: &PlatformRef, signable_bytes: Vec, validation_mode: ValidationMode, + block_info: &BlockInfo, execution_context: &mut StateTransitionExecutionContext, tx: TransactionArg, ) -> Result, Error>; @@ -56,6 +59,7 @@ impl ShieldFromAssetLockStateTransitionTransformIntoActionValidationV0 platform: &PlatformRef, signable_bytes: Vec, validation_mode: ValidationMode, + block_info: &BlockInfo, execution_context: &mut StateTransitionExecutionContext, tx: TransactionArg, ) -> Result, Error> { @@ -238,19 +242,19 @@ impl ShieldFromAssetLockStateTransitionTransformIntoActionValidationV0 // Step 8: Read current shielded pool total balance from GroveDB let mut drive_operations = vec![]; - let pool_path = shielded_credit_pool_path(); - - let current_total_balance = platform - .drive - .grove_get_raw_value_u64_from_encoded_var_vec( - (&pool_path).into(), - &[SHIELDED_TOTAL_BALANCE_KEY], - DirectQueryType::StatefulDirectQuery, - tx, - &mut drive_operations, - &platform_version.drive, - )? - .unwrap_or(0); + let current_total_balance = + read_pool_total_balance(&platform.drive, tx, &mut drive_operations, platform_version)?; + + // Calculate fees from the GroveDB operations + let fee = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + platform.drive.config.epochs_per_era, + platform_version, + None, + )?; + execution_context.add_operation(ValidationOperation::PrecalculatedOperation(fee)); // Step 9: Verify Orchard ZK proof via reconstruct_and_verify_bundle() // Use EMPTY extra_sighash_data -- no transparent binding needed since diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs index 865a46c6198..7b2ebc75b7e 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs @@ -1,6 +1,23 @@ +use crate::error::Error; +use dpp::consensus::state::shielded::insufficient_pool_notes_error::InsufficientPoolNotesError; +use dpp::consensus::state::shielded::invalid_anchor_error::InvalidAnchorError; use dpp::consensus::state::shielded::invalid_shielded_proof_error::InvalidShieldedProofError; +use dpp::consensus::state::shielded::nullifier_already_spent_error::NullifierAlreadySpentError; +use dpp::consensus::state::state_error::StateError; +use dpp::fee::Credits; +use dpp::prelude::ConsensusValidationResult; pub use dpp::shielded::compute_platform_sighash; use dpp::shielded::SerializedAction; +use dpp::version::PlatformVersion; +use drive::drive::shielded::paths::{ + shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, + shielded_credit_pool_path, SHIELDED_ENCRYPTED_NOTES_KEY, SHIELDED_TOTAL_BALANCE_KEY, +}; +use drive::drive::Drive; +use drive::fees::op::LowLevelDriveOperation; +use drive::grovedb::TransactionArg; +use drive::state_transition_action::StateTransitionAction; +use drive::util::grove_operations::DirectQueryType; use grovedb_commitment_tree::{ Action, Anchor, Authorized, BatchValidator, Bundle, ExtractedNoteCommitment, Flags, Nullifier, Proof, VerifyingKey, @@ -66,15 +83,17 @@ pub fn reconstruct_and_verify_bundle( a.encrypted_note.len() ))); } - let epk_bytes: [u8; 32] = a.encrypted_note[..EPK_SIZE].try_into().unwrap(); + let epk_bytes: [u8; 32] = a.encrypted_note[..EPK_SIZE] + .try_into() + .expect("length verified to be ENCRYPTED_NOTE_SIZE"); let enc_ciphertext: [u8; ENC_CIPHERTEXT_SIZE] = a.encrypted_note [EPK_SIZE..EPK_SIZE + ENC_CIPHERTEXT_SIZE] .try_into() - .unwrap(); + .expect("length verified to be ENCRYPTED_NOTE_SIZE"); let out_ciphertext: [u8; OUT_CIPHERTEXT_SIZE] = a.encrypted_note [EPK_SIZE + ENC_CIPHERTEXT_SIZE..] .try_into() - .unwrap(); + .expect("length verified to be ENCRYPTED_NOTE_SIZE"); let nullifier: Nullifier = Option::from(Nullifier::from_bytes(&a.nullifier)) .ok_or_else(|| InvalidShieldedProofError::new("invalid nullifier bytes".to_string()))?; @@ -159,3 +178,129 @@ pub fn reconstruct_and_verify_bundle( Ok(()) } + +/// Read the current shielded pool total balance from GroveDB. +/// Returns 0 if the balance key doesn't exist yet. +pub fn read_pool_total_balance( + drive: &Drive, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, +) -> Result { + let pool_path = shielded_credit_pool_path(); + Ok(drive + .grove_get_raw_value_u64_from_encoded_var_vec( + (&pool_path).into(), + &[SHIELDED_TOTAL_BALANCE_KEY], + DirectQueryType::StatefulDirectQuery, + transaction, + drive_operations, + &platform_version.drive, + )? + .unwrap_or(0)) +} + +/// Verify that the anchor exists in the recorded anchors tree. +/// Returns a consensus error if the anchor is not found. +pub fn validate_anchor_exists( + drive: &Drive, + anchor: &[u8; 32], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, +) -> Result>, Error> { + let anchors_path = shielded_anchors_credit_pool_path(); + let anchor_exists = drive.grove_has_raw( + (&anchors_path).into(), + anchor, + DirectQueryType::StatefulDirectQuery, + transaction, + drive_operations, + &platform_version.drive, + )?; + if !anchor_exists { + Ok(Some(ConsensusValidationResult::new_with_error( + StateError::InvalidAnchorError(InvalidAnchorError::new(*anchor)).into(), + ))) + } else { + Ok(None) + } +} + +/// Defense-in-depth: reject duplicate nullifiers within the same bundle, +/// then check that no nullifier has already been spent in state. +pub fn validate_nullifiers( + drive: &Drive, + nullifiers: &[[u8; 32]], + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, +) -> Result>, Error> { + // Intra-bundle duplicate check + let mut seen_nullifiers = std::collections::HashSet::new(); + for nullifier in nullifiers { + if !seen_nullifiers.insert(nullifier) { + return Ok(Some(ConsensusValidationResult::new_with_error( + StateError::NullifierAlreadySpentError(NullifierAlreadySpentError::new(*nullifier)) + .into(), + ))); + } + } + // Check against state + let nullifiers_path = shielded_credit_pool_nullifiers_path(); + for nullifier in nullifiers { + let exists = drive.grove_has_raw( + (&nullifiers_path).into(), + nullifier, + DirectQueryType::StatefulDirectQuery, + transaction, + drive_operations, + &platform_version.drive, + )?; + if exists { + return Ok(Some(ConsensusValidationResult::new_with_error( + StateError::NullifierAlreadySpentError(NullifierAlreadySpentError::new(*nullifier)) + .into(), + ))); + } + } + Ok(None) +} + +/// Check minimum notes threshold for outgoing transitions (anonymity set). +pub fn validate_minimum_pool_notes( + drive: &Drive, + transaction: TransactionArg, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, +) -> Result>, Error> { + let min_notes = platform_version + .drive_abci + .validation_and_processing + .event_constants + .minimum_pool_notes_for_outgoing; + if min_notes > 0 { + let pool_path = shielded_credit_pool_path(); + let encrypted_notes_count = drive + .grove_get_raw_optional( + (&pool_path).into(), + &[SHIELDED_ENCRYPTED_NOTES_KEY], + DirectQueryType::StatefulDirectQuery, + transaction, + drive_operations, + &platform_version.drive, + )? + .map(|element| element.count_value_or_default()) + .unwrap_or(0); + if encrypted_notes_count < min_notes { + return Ok(Some(ConsensusValidationResult::new_with_error( + StateError::InsufficientPoolNotesError(InsufficientPoolNotesError::new( + encrypted_notes_count, + min_notes, + )) + .into(), + ))); + } + } + Ok(None) +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/mod.rs index 4aa62c80362..bf0ce41200a 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/mod.rs @@ -3,6 +3,7 @@ mod transform_into_action; #[cfg(test)] mod tests; +use dpp::block::block_info::BlockInfo; use dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition; use dpp::validation::ConsensusValidationResult; use drive::grovedb::TransactionArg; @@ -10,6 +11,7 @@ use drive::state_transition_action::StateTransitionAction; use crate::error::execution::ExecutionError; use crate::error::Error; +use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use crate::execution::validation::state_transition::shielded_transfer::transform_into_action::v0::ShieldedTransferStateTransitionTransformIntoActionValidationV0; use crate::platform_types::platform::PlatformRef; use crate::rpc::core::CoreRPCLike; @@ -22,6 +24,8 @@ pub trait StateTransitionShieldedTransferTransitionActionTransformer { fn transform_into_action_for_shielded_transfer_transition( &self, platform: &PlatformRef, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, tx: TransactionArg, ) -> Result, Error>; } @@ -30,6 +34,8 @@ impl StateTransitionShieldedTransferTransitionActionTransformer for ShieldedTran fn transform_into_action_for_shielded_transfer_transition( &self, platform: &PlatformRef, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, tx: TransactionArg, ) -> Result, Error> { let platform_version = platform.state.current_platform_version()?; @@ -41,7 +47,13 @@ impl StateTransitionShieldedTransferTransitionActionTransformer for ShieldedTran .shielded_transfer_state_transition .transform_into_action { - 0 => self.transform_into_action_v0(platform.drive, tx, platform_version), + 0 => self.transform_into_action_v0( + platform.drive, + tx, + block_info, + execution_context, + platform_version, + ), version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { method: "shielded transfer transition: transform_into_action".to_string(), known_versions: vec![0], diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs index ef3479fb872..1f272ada3c2 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs @@ -1,49 +1,31 @@ #[cfg(test)] mod tests { - use crate::config::{PlatformConfig, PlatformTestConfig}; use crate::execution::validation::state_transition::state_transitions::shielded_common::compute_platform_sighash; + use crate::execution::validation::state_transition::state_transitions::test_helpers::{ + create_dummy_serialized_action, insert_anchor_into_state, insert_nullifier_into_state, + process_transition, set_pool_total_balance, setup_platform, + }; use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; - use crate::test::helpers::setup::TestPlatformBuilder; use assert_matches::assert_matches; - use dpp::block::block_info::BlockInfo; use dpp::consensus::basic::BasicError; use dpp::consensus::state::state_error::StateError; use dpp::consensus::ConsensusError; - use dpp::serialization::PlatformSerializable; use dpp::shielded::SerializedAction; use dpp::state_transition::shielded_transfer_transition::v0::ShieldedTransferTransitionV0; use dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition; use dpp::state_transition::StateTransition; - use drive::drive::shielded::paths::{ - shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, - shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY, - }; - use drive::grovedb::Element; use platform_version::version::PlatformVersion; // ========================================== - // Helper Functions + // Helper Functions (transition-specific) // ========================================== - /// Create a `SerializedAction` with syntactically valid sizes but meaningless crypto data. - /// Passes structure validation (correct field sizes) but will fail ZK proof verification. - fn create_dummy_serialized_action() -> SerializedAction { - SerializedAction { - nullifier: [1u8; 32], - rk: [2u8; 32], - cmx: [3u8; 32], - encrypted_note: vec![4u8; 692], // epk(32) + enc(580) + out(80) - cv_net: [5u8; 32], - spend_auth_sig: [6u8; 64], - } - } - /// Builds a `ShieldedTransferTransition` state transition. /// No signing needed since shielded transfers have no witnesses. fn create_shielded_transfer_transition( actions: Vec, flags: u8, - value_balance: i64, + value_balance: u64, anchor: [u8; 32], proof: Vec, binding_signature: [u8; 64], @@ -76,147 +58,6 @@ mod tests { ) } - /// Insert a fake anchor into the shielded anchors tree via GroveDB. - fn insert_anchor_into_state( - platform: &crate::test::helpers::setup::TempPlatform, - anchor: &[u8; 32], - ) { - let platform_version = PlatformVersion::latest(); - let grove_version = &platform_version.drive.grove_version; - let transaction = platform.drive.grove.start_transaction(); - let anchors_path = shielded_anchors_credit_pool_path(); - - platform - .drive - .grove - .insert( - &anchors_path, - anchor, - Element::Item(vec![], None), - None, - Some(&transaction), - grove_version, - ) - .unwrap() - .expect("should insert anchor"); - - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("should commit transaction"); - } - - /// Insert a nullifier into the nullifiers tree via GroveDB. - fn insert_nullifier_into_state( - platform: &crate::test::helpers::setup::TempPlatform, - nullifier: &[u8; 32], - ) { - let platform_version = PlatformVersion::latest(); - let grove_version = &platform_version.drive.grove_version; - let transaction = platform.drive.grove.start_transaction(); - let nullifiers_path = shielded_credit_pool_nullifiers_path(); - - platform - .drive - .grove - .insert( - &nullifiers_path, - nullifier, - Element::Item(vec![], None), - None, - Some(&transaction), - grove_version, - ) - .unwrap() - .expect("should insert nullifier"); - - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("should commit transaction"); - } - - /// Set the shielded pool total balance in GroveDB. - fn set_pool_total_balance( - platform: &crate::test::helpers::setup::TempPlatform, - balance: u64, - ) { - let platform_version = PlatformVersion::latest(); - let grove_version = &platform_version.drive.grove_version; - let transaction = platform.drive.grove.start_transaction(); - let pool_path = shielded_credit_pool_path(); - - platform - .drive - .grove - .insert( - &pool_path, - &[SHIELDED_TOTAL_BALANCE_KEY], - Element::new_sum_item(balance as i64), - None, - Some(&transaction), - grove_version, - ) - .unwrap() - .expect("should set total balance"); - - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("should commit transaction"); - } - - /// Standard platform setup for tests. - fn setup_platform( - ) -> crate::test::helpers::setup::TempPlatform { - let platform_config = PlatformConfig { - testing_configs: PlatformTestConfig { - disable_instant_lock_signature_verification: true, - ..Default::default() - }, - ..Default::default() - }; - - TestPlatformBuilder::new() - .with_config(platform_config) - .with_latest_protocol_version() - .build_with_mock_rpc() - .set_genesis_state() - } - - /// Execute a state transition through the full processing pipeline and return the result. - fn process_transition( - platform: &crate::test::helpers::setup::TempPlatform, - transition: StateTransition, - platform_version: &PlatformVersion, - ) -> crate::platform_types::state_transitions_processing_result::StateTransitionsProcessingResult - { - let transition_bytes = transition - .serialize_to_bytes() - .expect("should serialize transition"); - let platform_state = platform.state.load(); - let transaction = platform.drive.grove.start_transaction(); - - platform - .platform - .process_raw_state_transitions( - &vec![transition_bytes], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - false, - None, - ) - .expect("expected to process state transition") - } - // ========================================== // STRUCTURE VALIDATION TESTS (BasicError) // ========================================== @@ -250,14 +91,14 @@ mod tests { } #[test] - fn test_negative_value_balance_returns_error() { + fn test_value_balance_exceeding_i64_max_returns_error() { let platform_version = PlatformVersion::latest(); let platform = setup_platform(); let transition = create_shielded_transfer_transition( vec![create_dummy_serialized_action()], 0x03, - -1000, // Negative — invalid for shielded transfer (must be >= 0) + i64::MAX as u64 + 1, // Exceeds i64::MAX — invalid [42u8; 32], vec![0u8; 100], [0u8; 64], @@ -407,7 +248,7 @@ mod tests { fn serialize_authorized_bundle( bundle: &Bundle, - ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { + ) -> (Vec, u8, u64, [u8; 32], Vec, [u8; 64]) { let actions: Vec = bundle .actions() .iter() @@ -428,7 +269,7 @@ mod tests { }) .collect(); let flags = bundle.flags().to_byte(); - let value_balance = *bundle.value_balance(); + let value_balance = *bundle.value_balance() as u64; let anchor = bundle.anchor().to_bytes(); let proof = bundle.authorization().proof().as_ref().to_vec(); let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); @@ -596,7 +437,7 @@ mod tests { fn serialize_authorized_bundle( bundle: &Bundle, - ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { + ) -> (Vec, u8, u64, [u8; 32], Vec, [u8; 64]) { let actions: Vec = bundle .actions() .iter() @@ -617,7 +458,7 @@ mod tests { }) .collect(); let flags = bundle.flags().to_byte(); - let value_balance = *bundle.value_balance(); + let value_balance = *bundle.value_balance() as u64; let anchor = bundle.anchor().to_bytes(); let proof = bundle.authorization().proof().as_ref().to_vec(); let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); @@ -627,7 +468,7 @@ mod tests { /// Build a valid Orchard bundle for shielded transfer tests. /// Returns (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig). fn build_valid_shielded_transfer_bundle( - ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { + ) -> (Vec, u8, u64, [u8; 32], Vec, [u8; 64]) { let mut rng = OsRng; let pk = get_proving_key(); @@ -687,7 +528,7 @@ mod tests { assert_eq!(value_balance, 0); // ATTACK: Mutate value_balance from 0 to 5000 - let mutated_value_balance = 5000i64; + let mutated_value_balance = 5000u64; // Set pool balance so fee deduction doesn't underflow set_pool_total_balance(&platform, 10_000); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs index 859a28f9f8e..b1380522c76 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs @@ -1,21 +1,24 @@ use crate::error::Error; -use crate::execution::validation::state_transition::state_transitions::shielded_common::reconstruct_and_verify_bundle; -use dpp::consensus::state::shielded::invalid_anchor_error::InvalidAnchorError; -use dpp::consensus::state::shielded::nullifier_already_spent_error::NullifierAlreadySpentError; +use crate::execution::types::execution_operation::ValidationOperation; +use crate::execution::types::state_transition_execution_context::{ + StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0, +}; +use crate::execution::validation::state_transition::state_transitions::shielded_common::{ + read_pool_total_balance, reconstruct_and_verify_bundle, validate_anchor_exists, + validate_nullifiers, +}; +use dpp::block::block_info::BlockInfo; use dpp::consensus::state::state_error::StateError; use dpp::fee::Credits; use dpp::prelude::ConsensusValidationResult; use dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition; use dpp::version::PlatformVersion; -use drive::drive::shielded::paths::{ - shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, - shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY, -}; use drive::drive::Drive; use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::shielded_transfer::ShieldedTransferTransitionAction; +use drive::state_transition_action::system::penalize_shielded_pool_action::v0::PenalizeShieldedPoolActionV0; +use drive::state_transition_action::system::penalize_shielded_pool_action::PenalizeShieldedPoolAction; use drive::state_transition_action::StateTransitionAction; -use drive::util::grove_operations::DirectQueryType; pub(in crate::execution::validation::state_transition::state_transitions::shielded_transfer) trait ShieldedTransferStateTransitionTransformIntoActionValidationV0 { @@ -23,6 +26,8 @@ pub(in crate::execution::validation::state_transition::state_transitions::shield &self, drive: &Drive, transaction: TransactionArg, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, platform_version: &PlatformVersion, ) -> Result, Error>; } @@ -32,6 +37,8 @@ impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 for Shielded &self, drive: &Drive, transaction: TransactionArg, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, platform_version: &PlatformVersion, ) -> Result, Error> { // Extract nullifiers, note commitments, and encrypted notes from serialized actions @@ -54,84 +61,72 @@ impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 for Shielded ShieldedTransferTransition::V0(v0) => v0.anchor, }; - // The value_balance is positive for shielded transfer (fee extracted from pool) + // The value_balance is the fee amount extracted from the shielded pool let fee_amount: Credits = match self { - ShieldedTransferTransition::V0(v0) => v0.value_balance as u64, + ShieldedTransferTransition::V0(v0) => v0.value_balance, }; // Read current shielded pool state from GroveDB let mut drive_operations = vec![]; - let pool_path = shielded_credit_pool_path(); - - let current_total_balance = drive - .grove_get_raw_value_u64_from_encoded_var_vec( - (&pool_path).into(), - &[SHIELDED_TOTAL_BALANCE_KEY], - DirectQueryType::StatefulDirectQuery, - transaction, - &mut drive_operations, - &platform_version.drive, - )? - .unwrap_or(0); + let current_total_balance = + read_pool_total_balance(drive, transaction, &mut drive_operations, platform_version)?; + + // Verify the pool has sufficient balance for the fee + if current_total_balance < fee_amount { + return Ok(ConsensusValidationResult::new_with_error( + StateError::InvalidShieldedProofError( + dpp::consensus::state::shielded::invalid_shielded_proof_error::InvalidShieldedProofError::new( + format!( + "shielded pool has insufficient balance: pool has {} but fee requires {}", + current_total_balance, fee_amount + ), + ), + ) + .into(), + )); + } // Verify the anchor exists in the recorded anchors tree - let anchors_path = shielded_anchors_credit_pool_path(); - let anchor_exists = drive.grove_has_raw( - (&anchors_path).into(), + if let Some(err) = validate_anchor_exists( + drive, &anchor, - DirectQueryType::StatefulDirectQuery, transaction, &mut drive_operations, - &platform_version.drive, - )?; - - if !anchor_exists { - return Ok(ConsensusValidationResult::new_with_error( - StateError::InvalidAnchorError(InvalidAnchorError::new(anchor)).into(), - )); + platform_version, + )? { + return Ok(err); } - // Defense-in-depth: reject duplicate nullifiers within the same bundle - let mut seen_nullifiers = std::collections::HashSet::new(); - for nullifier in &nullifiers { - if !seen_nullifiers.insert(nullifier) { - return Ok(ConsensusValidationResult::new_with_error( - StateError::NullifierAlreadySpentError(NullifierAlreadySpentError::new( - *nullifier, - )) - .into(), - )); - } + // Validate nullifiers: intra-bundle duplicates + already-spent in state + if let Some(err) = validate_nullifiers( + drive, + &nullifiers, + transaction, + &mut drive_operations, + platform_version, + )? { + return Ok(err); } - // Check that no nullifier has already been spent in the state - let nullifiers_path = shielded_credit_pool_nullifiers_path(); - for nullifier in &nullifiers { - let exists = drive.grove_has_raw( - (&nullifiers_path).into(), - nullifier, - DirectQueryType::StatefulDirectQuery, - transaction, - &mut drive_operations, - &platform_version.drive, - )?; - - if exists { - return Ok(ConsensusValidationResult::new_with_error( - StateError::NullifierAlreadySpentError(NullifierAlreadySpentError::new( - *nullifier, - )) - .into(), - )); - } - } + // Calculate fees from the GroveDB operations + let fee = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + drive.config.epochs_per_era, + platform_version, + None, + )?; + execution_context.add_operation(ValidationOperation::PrecalculatedOperation(fee)); // Verify the ZK proof + // Cast value_balance to i64 for Orchard protocol — safe because structure + // validation already verified value_balance <= i64::MAX let (st_actions, st_flags, st_value_balance, st_proof, st_binding_sig) = match self { ShieldedTransferTransition::V0(v0) => ( &v0.actions, v0.flags, - v0.value_balance, + v0.value_balance as i64, v0.proof.as_slice(), &v0.binding_signature, ), @@ -146,8 +141,25 @@ impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 for Shielded st_binding_sig, &[], // No transparent fields to bind for shielded transfer ) { - return Ok(ConsensusValidationResult::new_with_error( - StateError::InvalidShieldedProofError(e).into(), + let penalty = platform_version + .drive_abci + .validation_and_processing + .penalties + .shielded_proof_verification_failure; + + let penalty_amount = std::cmp::min(penalty, current_total_balance); + + let penalize_action = StateTransitionAction::PenalizeShieldedPoolAction( + PenalizeShieldedPoolAction::from(PenalizeShieldedPoolActionV0 { + penalty_amount, + nullifiers: nullifiers.clone(), + current_total_balance, + }), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + penalize_action, + vec![StateError::InvalidShieldedProofError(e).into()], )); } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/mod.rs index 58f70bcd1dd..494bb288179 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/mod.rs @@ -1,3 +1,4 @@ +#[cfg(test)] mod tests; mod transform_into_action; @@ -9,6 +10,7 @@ use drive::state_transition_action::StateTransitionAction; use crate::error::execution::ExecutionError; use crate::error::Error; +use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use crate::execution::validation::state_transition::shielded_withdrawal::transform_into_action::v0::ShieldedWithdrawalStateTransitionTransformIntoActionValidationV0; use crate::platform_types::platform::PlatformRef; use crate::platform_types::platform_state::PlatformStateV0Methods; @@ -21,6 +23,7 @@ pub trait StateTransitionShieldedWithdrawalTransitionActionTransformer { &self, platform: &PlatformRef, block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, tx: TransactionArg, ) -> Result, Error>; } @@ -30,6 +33,7 @@ impl StateTransitionShieldedWithdrawalTransitionActionTransformer for ShieldedWi &self, platform: &PlatformRef, block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, tx: TransactionArg, ) -> Result, Error> { let platform_version = platform.state.current_platform_version()?; @@ -41,7 +45,13 @@ impl StateTransitionShieldedWithdrawalTransitionActionTransformer for ShieldedWi .shielded_withdrawal_state_transition .transform_into_action { - 0 => self.transform_into_action_v0(platform.drive, block_info, tx, platform_version), + 0 => self.transform_into_action_v0( + platform.drive, + block_info, + execution_context, + tx, + platform_version, + ), version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { method: "shielded withdrawal transition: transform_into_action".to_string(), known_versions: vec![0], diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs index fa13bb09deb..1ae4bb36a1d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs @@ -1,46 +1,27 @@ #[cfg(test)] mod tests { - use crate::config::{PlatformConfig, PlatformTestConfig}; use crate::execution::validation::state_transition::state_transitions::shielded_common::compute_platform_sighash; + use crate::execution::validation::state_transition::state_transitions::test_helpers::{ + create_dummy_serialized_action, insert_anchor_into_state, insert_dummy_encrypted_notes, + insert_nullifier_into_state, process_transition, set_pool_total_balance, setup_platform, + }; use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; - use crate::test::helpers::setup::TestPlatformBuilder; use assert_matches::assert_matches; - use dpp::block::block_info::BlockInfo; use dpp::consensus::basic::BasicError; use dpp::consensus::state::state_error::StateError; use dpp::consensus::ConsensusError; use dpp::identity::core_script::CoreScript; - use dpp::serialization::PlatformSerializable; use dpp::shielded::SerializedAction; use dpp::state_transition::shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0; use dpp::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; use dpp::state_transition::StateTransition; use dpp::withdrawal::Pooling; - use drive::drive::shielded::paths::{ - shielded_anchors_credit_pool_path, shielded_credit_pool_encrypted_notes_path, - shielded_credit_pool_nullifiers_path, shielded_credit_pool_path, - SHIELDED_TOTAL_BALANCE_KEY, - }; - use drive::grovedb::Element; use platform_version::version::PlatformVersion; // ========================================== - // Helper Functions + // Helper Functions (transition-specific) // ========================================== - /// Create a `SerializedAction` with syntactically valid sizes but meaningless crypto data. - /// Passes structure validation (correct field sizes) but will fail ZK proof verification. - fn create_dummy_serialized_action() -> SerializedAction { - SerializedAction { - nullifier: [1u8; 32], - rk: [2u8; 32], - cmx: [3u8; 32], - encrypted_note: vec![4u8; 692], // epk(32) + enc(580) + out(80) - cv_net: [5u8; 32], - spend_auth_sig: [6u8; 64], - } - } - /// Create a dummy CoreScript (P2PKH) for the withdrawal output. fn create_output_script() -> CoreScript { CoreScript::new_p2pkh([7u8; 20]) @@ -98,182 +79,6 @@ mod tests { ) } - /// Insert a fake anchor into the shielded anchors tree via GroveDB. - fn insert_anchor_into_state( - platform: &crate::test::helpers::setup::TempPlatform, - anchor: &[u8; 32], - ) { - let platform_version = PlatformVersion::latest(); - let grove_version = &platform_version.drive.grove_version; - let transaction = platform.drive.grove.start_transaction(); - let anchors_path = shielded_anchors_credit_pool_path(); - - platform - .drive - .grove - .insert( - &anchors_path, - anchor, - Element::Item(vec![], None), - None, - Some(&transaction), - grove_version, - ) - .unwrap() - .expect("should insert anchor"); - - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("should commit transaction"); - } - - /// Insert a nullifier into the nullifiers tree via GroveDB. - fn insert_nullifier_into_state( - platform: &crate::test::helpers::setup::TempPlatform, - nullifier: &[u8; 32], - ) { - let platform_version = PlatformVersion::latest(); - let grove_version = &platform_version.drive.grove_version; - let transaction = platform.drive.grove.start_transaction(); - let nullifiers_path = shielded_credit_pool_nullifiers_path(); - - platform - .drive - .grove - .insert( - &nullifiers_path, - nullifier, - Element::Item(vec![], None), - None, - Some(&transaction), - grove_version, - ) - .unwrap() - .expect("should insert nullifier"); - - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("should commit transaction"); - } - - /// Set the shielded pool total balance in GroveDB. - fn set_pool_total_balance( - platform: &crate::test::helpers::setup::TempPlatform, - balance: u64, - ) { - let platform_version = PlatformVersion::latest(); - let grove_version = &platform_version.drive.grove_version; - let transaction = platform.drive.grove.start_transaction(); - let pool_path = shielded_credit_pool_path(); - - platform - .drive - .grove - .insert( - &pool_path, - &[SHIELDED_TOTAL_BALANCE_KEY], - Element::new_sum_item(balance as i64), - None, - Some(&transaction), - grove_version, - ) - .unwrap() - .expect("should set total balance"); - - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("should commit transaction"); - } - - /// Insert dummy encrypted notes into the shielded pool to meet the minimum - /// notes threshold for outgoing transitions. - fn insert_dummy_encrypted_notes( - platform: &crate::test::helpers::setup::TempPlatform, - count: u64, - ) { - let platform_version = PlatformVersion::latest(); - let grove_version = &platform_version.drive.grove_version; - let transaction = platform.drive.grove.start_transaction(); - let notes_path = shielded_credit_pool_encrypted_notes_path(); - - for i in 0..count { - platform - .drive - .grove - .insert( - ¬es_path, - &i.to_be_bytes(), - Element::Item(vec![0], None), - None, - Some(&transaction), - grove_version, - ) - .unwrap() - .expect("should insert dummy note"); - } - - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("should commit transaction"); - } - - /// Standard platform setup for tests. - fn setup_platform( - ) -> crate::test::helpers::setup::TempPlatform { - let platform_config = PlatformConfig { - testing_configs: PlatformTestConfig { - disable_instant_lock_signature_verification: true, - ..Default::default() - }, - ..Default::default() - }; - - TestPlatformBuilder::new() - .with_config(platform_config) - .with_latest_protocol_version() - .build_with_mock_rpc() - .set_genesis_state() - } - - /// Execute a state transition through the full processing pipeline and return the result. - fn process_transition( - platform: &crate::test::helpers::setup::TempPlatform, - transition: StateTransition, - platform_version: &PlatformVersion, - ) -> crate::platform_types::state_transitions_processing_result::StateTransitionsProcessingResult - { - let transition_bytes = transition - .serialize_to_bytes() - .expect("should serialize transition"); - let platform_state = platform.state.load(); - let transaction = platform.drive.grove.start_transaction(); - - platform - .platform - .process_raw_state_transitions( - &vec![transition_bytes], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - false, - None, - ) - .expect("expected to process state transition") - } - // ========================================== // STRUCTURE VALIDATION TESTS (BasicError) // ========================================== diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs index 4ef408aa75c..35a41d49128 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs @@ -1,22 +1,23 @@ use crate::error::Error; -use crate::execution::validation::state_transition::state_transitions::shielded_common::reconstruct_and_verify_bundle; +use crate::execution::types::execution_operation::ValidationOperation; +use crate::execution::types::state_transition_execution_context::{ + StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0, +}; +use crate::execution::validation::state_transition::state_transitions::shielded_common::{ + read_pool_total_balance, reconstruct_and_verify_bundle, validate_anchor_exists, + validate_minimum_pool_notes, validate_nullifiers, +}; use dpp::block::block_info::BlockInfo; -use dpp::consensus::state::shielded::insufficient_pool_notes_error::InsufficientPoolNotesError; -use dpp::consensus::state::shielded::invalid_anchor_error::InvalidAnchorError; -use dpp::consensus::state::shielded::nullifier_already_spent_error::NullifierAlreadySpentError; use dpp::consensus::state::state_error::StateError; use dpp::prelude::ConsensusValidationResult; use dpp::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; use dpp::version::PlatformVersion; -use drive::drive::shielded::paths::{ - shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, - shielded_credit_pool_path, SHIELDED_ENCRYPTED_NOTES_KEY, SHIELDED_TOTAL_BALANCE_KEY, -}; use drive::drive::Drive; use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::shielded_withdrawal::ShieldedWithdrawalTransitionAction; +use drive::state_transition_action::system::penalize_shielded_pool_action::v0::PenalizeShieldedPoolActionV0; +use drive::state_transition_action::system::penalize_shielded_pool_action::PenalizeShieldedPoolAction; use drive::state_transition_action::StateTransitionAction; -use drive::util::grove_operations::DirectQueryType; pub(in crate::execution::validation::state_transition::state_transitions::shielded_withdrawal) trait ShieldedWithdrawalStateTransitionTransformIntoActionValidationV0 { @@ -24,6 +25,7 @@ pub(in crate::execution::validation::state_transition::state_transitions::shield &self, drive: &Drive, block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result, Error>; @@ -36,6 +38,7 @@ impl ShieldedWithdrawalStateTransitionTransformIntoActionValidationV0 &self, drive: &Drive, block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result, Error> { @@ -63,47 +66,17 @@ impl ShieldedWithdrawalStateTransitionTransformIntoActionValidationV0 // Read current shielded pool total balance from GroveDB let mut drive_operations = vec![]; - let pool_path = shielded_credit_pool_path(); - - let current_total_balance = drive - .grove_get_raw_value_u64_from_encoded_var_vec( - (&pool_path).into(), - &[SHIELDED_TOTAL_BALANCE_KEY], - DirectQueryType::StatefulDirectQuery, - transaction, - &mut drive_operations, - &platform_version.drive, - )? - .unwrap_or(0); + let current_total_balance = + read_pool_total_balance(drive, transaction, &mut drive_operations, platform_version)?; // Check minimum notes threshold for outgoing transitions (anonymity set) - let min_notes = platform_version - .drive_abci - .validation_and_processing - .event_constants - .minimum_pool_notes_for_outgoing; - if min_notes > 0 { - let encrypted_notes_count = drive - .grove_get_raw_optional( - (&pool_path).into(), - &[SHIELDED_ENCRYPTED_NOTES_KEY], - DirectQueryType::StatefulDirectQuery, - transaction, - &mut drive_operations, - &platform_version.drive, - )? - .map(|element| element.count_value_or_default()) - .unwrap_or(0); - - if encrypted_notes_count < min_notes { - return Ok(ConsensusValidationResult::new_with_error( - StateError::InsufficientPoolNotesError(InsufficientPoolNotesError::new( - encrypted_notes_count, - min_notes, - )) - .into(), - )); - } + if let Some(err) = validate_minimum_pool_notes( + drive, + transaction, + &mut drive_operations, + platform_version, + )? { + return Ok(err); } // Verify the pool has sufficient balance for the withdrawal. @@ -129,56 +102,37 @@ impl ShieldedWithdrawalStateTransitionTransformIntoActionValidationV0 } // Verify the anchor exists in the recorded anchors tree - let anchors_path = shielded_anchors_credit_pool_path(); - let anchor_exists = drive.grove_has_raw( - (&anchors_path).into(), + if let Some(err) = validate_anchor_exists( + drive, &anchor, - DirectQueryType::StatefulDirectQuery, transaction, &mut drive_operations, - &platform_version.drive, - )?; - - if !anchor_exists { - return Ok(ConsensusValidationResult::new_with_error( - StateError::InvalidAnchorError(InvalidAnchorError::new(anchor)).into(), - )); + platform_version, + )? { + return Ok(err); } - // Defense-in-depth: reject duplicate nullifiers within the same bundle - let mut seen_nullifiers = std::collections::HashSet::new(); - for nullifier in &nullifiers { - if !seen_nullifiers.insert(nullifier) { - return Ok(ConsensusValidationResult::new_with_error( - StateError::NullifierAlreadySpentError(NullifierAlreadySpentError::new( - *nullifier, - )) - .into(), - )); - } + // Validate nullifiers: intra-bundle duplicates + already-spent in state + if let Some(err) = validate_nullifiers( + drive, + &nullifiers, + transaction, + &mut drive_operations, + platform_version, + )? { + return Ok(err); } - // Check that no nullifier has already been spent in the state - let nullifiers_path = shielded_credit_pool_nullifiers_path(); - for nullifier in &nullifiers { - let exists = drive.grove_has_raw( - (&nullifiers_path).into(), - nullifier, - DirectQueryType::StatefulDirectQuery, - transaction, - &mut drive_operations, - &platform_version.drive, - )?; - - if exists { - return Ok(ConsensusValidationResult::new_with_error( - StateError::NullifierAlreadySpentError(NullifierAlreadySpentError::new( - *nullifier, - )) - .into(), - )); - } - } + // Calculate fees from the GroveDB operations + let fee = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + drive.config.epochs_per_era, + platform_version, + None, + )?; + execution_context.add_operation(ValidationOperation::PrecalculatedOperation(fee)); // Verify the Orchard ZK proof, binding transparent fields to the sighash. // For shielded withdrawal, the extra_sighash_data binds the withdrawal @@ -219,8 +173,25 @@ impl ShieldedWithdrawalStateTransitionTransformIntoActionValidationV0 st_binding_sig, &extra_sighash_data, ) { - return Ok(ConsensusValidationResult::new_with_error( - StateError::InvalidShieldedProofError(e).into(), + let penalty = platform_version + .drive_abci + .validation_and_processing + .penalties + .shielded_proof_verification_failure; + + let penalty_amount = std::cmp::min(penalty, current_total_balance); + + let penalize_action = StateTransitionAction::PenalizeShieldedPoolAction( + PenalizeShieldedPoolAction::from(PenalizeShieldedPoolActionV0 { + penalty_amount, + nullifiers: nullifiers.clone(), + current_total_balance, + }), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + penalize_action, + vec![StateError::InvalidShieldedProofError(e).into()], )); } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/test_helpers.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/test_helpers.rs index f25e081e185..a124daeec57 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/test_helpers.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/test_helpers.rs @@ -2,11 +2,14 @@ //! //! This module provides common test infrastructure for testing state transitions //! that involve platform addresses, including signers, address creation helpers, -//! and balance setup utilities. +//! balance setup utilities, and shielded pool state helpers. +use crate::config::{PlatformConfig, PlatformTestConfig}; +use crate::platform_types::state_transitions_processing_result::StateTransitionsProcessingResult; use crate::rpc::core::MockCoreRPCLike; -use crate::test::helpers::setup::TempPlatform; +use crate::test::helpers::setup::{TempPlatform, TestPlatformBuilder}; use dpp::address_funds::{AddressWitness, PlatformAddress}; +use dpp::block::block_info::BlockInfo; use dpp::dashcore::blockdata::script::ScriptBuf; use dpp::dashcore::hashes::{sha256, Hash}; use dpp::dashcore::secp256k1::{PublicKey as RawPublicKey, Secp256k1, SecretKey as RawSecretKey}; @@ -14,7 +17,15 @@ use dpp::dashcore::PublicKey; use dpp::identity::signer::Signer; use dpp::platform_value::BinaryData; use dpp::prelude::AddressNonce; +use dpp::serialization::PlatformSerializable; +use dpp::shielded::SerializedAction; +use dpp::state_transition::StateTransition; use dpp::ProtocolError; +use drive::drive::shielded::paths::{ + shielded_anchors_credit_pool_path, shielded_credit_pool_encrypted_notes_path, + shielded_credit_pool_nullifiers_path, shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY, +}; +use drive::grovedb::Element; use platform_version::version::PlatformVersion; use std::collections::HashMap; @@ -387,3 +398,182 @@ pub fn setup_address_with_balance_and_system_credits( ) .expect("expected to apply drive operations"); } + +// ========================================== +// Shielded Test Helpers +// ========================================== + +/// Create a `SerializedAction` with syntactically valid sizes but meaningless crypto data. +/// Passes structure validation (correct field sizes) but will fail ZK proof verification. +pub fn create_dummy_serialized_action() -> SerializedAction { + SerializedAction { + nullifier: [1u8; 32], + rk: [2u8; 32], + cmx: [3u8; 32], + encrypted_note: vec![4u8; 692], // epk(32) + enc(580) + out(80) + cv_net: [5u8; 32], + spend_auth_sig: [6u8; 64], + } +} + +/// Standard platform setup for shielded tests with instant lock signature verification disabled. +pub fn setup_platform() -> TempPlatform { + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + TestPlatformBuilder::new() + .with_config(platform_config) + .with_latest_protocol_version() + .build_with_mock_rpc() + .set_genesis_state() +} + +/// Execute a state transition through the full processing pipeline and return the result. +pub fn process_transition( + platform: &TempPlatform, + transition: StateTransition, + platform_version: &PlatformVersion, +) -> StateTransitionsProcessingResult { + let transition_bytes = transition + .serialize_to_bytes() + .expect("should serialize transition"); + let platform_state = platform.state.load(); + let transaction = platform.drive.grove.start_transaction(); + + platform + .platform + .process_raw_state_transitions( + &vec![transition_bytes], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition") +} + +/// Insert a fake anchor into the shielded anchors tree via GroveDB. +pub fn insert_anchor_into_state(platform: &TempPlatform, anchor: &[u8; 32]) { + let platform_version = PlatformVersion::latest(); + let grove_version = &platform_version.drive.grove_version; + let transaction = platform.drive.grove.start_transaction(); + let anchors_path = shielded_anchors_credit_pool_path(); + + platform + .drive + .grove + .insert( + &anchors_path, + anchor, + Element::Item(vec![], None), + None, + Some(&transaction), + grove_version, + ) + .unwrap() + .expect("should insert anchor"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("should commit transaction"); +} + +/// Insert a nullifier into the nullifiers tree via GroveDB. +pub fn insert_nullifier_into_state(platform: &TempPlatform, nullifier: &[u8; 32]) { + let platform_version = PlatformVersion::latest(); + let grove_version = &platform_version.drive.grove_version; + let transaction = platform.drive.grove.start_transaction(); + let nullifiers_path = shielded_credit_pool_nullifiers_path(); + + platform + .drive + .grove + .insert( + &nullifiers_path, + nullifier, + Element::Item(vec![], None), + None, + Some(&transaction), + grove_version, + ) + .unwrap() + .expect("should insert nullifier"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("should commit transaction"); +} + +/// Set the shielded pool total balance in GroveDB. +pub fn set_pool_total_balance(platform: &TempPlatform, balance: u64) { + let platform_version = PlatformVersion::latest(); + let grove_version = &platform_version.drive.grove_version; + let transaction = platform.drive.grove.start_transaction(); + let pool_path = shielded_credit_pool_path(); + + platform + .drive + .grove + .insert( + &pool_path, + &[SHIELDED_TOTAL_BALANCE_KEY], + Element::new_sum_item(balance as i64), + None, + Some(&transaction), + grove_version, + ) + .unwrap() + .expect("should set total balance"); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("should commit transaction"); +} + +/// Insert dummy encrypted notes into the shielded pool to meet the minimum +/// notes threshold for outgoing transitions. +pub fn insert_dummy_encrypted_notes(platform: &TempPlatform, count: u64) { + let platform_version = PlatformVersion::latest(); + let grove_version = &platform_version.drive.grove_version; + let transaction = platform.drive.grove.start_transaction(); + let notes_path = shielded_credit_pool_encrypted_notes_path(); + + for i in 0..count { + platform + .drive + .grove + .insert( + ¬es_path, + &i.to_be_bytes(), + Element::Item(vec![0], None), + None, + Some(&transaction), + grove_version, + ) + .unwrap() + .expect("should insert dummy note"); + } + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("should commit transaction"); +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/mod.rs index e798a9037c9..3d12c471f22 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/mod.rs @@ -3,6 +3,7 @@ mod transform_into_action; #[cfg(test)] mod tests; +use dpp::block::block_info::BlockInfo; use dpp::state_transition::unshield_transition::UnshieldTransition; use dpp::validation::ConsensusValidationResult; use drive::grovedb::TransactionArg; @@ -10,6 +11,7 @@ use drive::state_transition_action::StateTransitionAction; use crate::error::execution::ExecutionError; use crate::error::Error; +use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use crate::execution::validation::state_transition::unshield::transform_into_action::v0::UnshieldStateTransitionTransformIntoActionValidationV0; use crate::platform_types::platform::PlatformRef; use crate::rpc::core::CoreRPCLike; @@ -22,6 +24,8 @@ pub trait StateTransitionUnshieldTransitionActionTransformer { fn transform_into_action_for_unshield_transition( &self, platform: &PlatformRef, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, tx: TransactionArg, ) -> Result, Error>; } @@ -30,6 +34,8 @@ impl StateTransitionUnshieldTransitionActionTransformer for UnshieldTransition { fn transform_into_action_for_unshield_transition( &self, platform: &PlatformRef, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, tx: TransactionArg, ) -> Result, Error> { let platform_version = platform.state.current_platform_version()?; @@ -41,7 +47,13 @@ impl StateTransitionUnshieldTransitionActionTransformer for UnshieldTransition { .unshield_state_transition .transform_into_action { - 0 => self.transform_into_action_v0(platform.drive, tx, platform_version), + 0 => self.transform_into_action_v0( + platform.drive, + tx, + block_info, + execution_context, + platform_version, + ), version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { method: "unshield transition: transform_into_action".to_string(), known_versions: vec![0], diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs index b436af1f9b8..5eda2c34e78 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs @@ -1,45 +1,26 @@ #[cfg(test)] mod tests { - use crate::config::{PlatformConfig, PlatformTestConfig}; use crate::execution::validation::state_transition::state_transitions::shielded_common::compute_platform_sighash; + use crate::execution::validation::state_transition::state_transitions::test_helpers::{ + create_dummy_serialized_action, insert_anchor_into_state, insert_dummy_encrypted_notes, + insert_nullifier_into_state, process_transition, set_pool_total_balance, setup_platform, + }; use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult; - use crate::test::helpers::setup::TestPlatformBuilder; use assert_matches::assert_matches; use dpp::address_funds::PlatformAddress; - use dpp::block::block_info::BlockInfo; use dpp::consensus::basic::BasicError; use dpp::consensus::state::state_error::StateError; use dpp::consensus::ConsensusError; - use dpp::serialization::PlatformSerializable; use dpp::shielded::SerializedAction; use dpp::state_transition::unshield_transition::v0::UnshieldTransitionV0; use dpp::state_transition::unshield_transition::UnshieldTransition; use dpp::state_transition::StateTransition; - use drive::drive::shielded::paths::{ - shielded_anchors_credit_pool_path, shielded_credit_pool_encrypted_notes_path, - shielded_credit_pool_nullifiers_path, shielded_credit_pool_path, - SHIELDED_TOTAL_BALANCE_KEY, - }; - use drive::grovedb::Element; use platform_version::version::PlatformVersion; // ========================================== - // Helper Functions + // Helper Functions (transition-specific) // ========================================== - /// Create a `SerializedAction` with syntactically valid sizes but meaningless crypto data. - /// Passes structure validation (correct field sizes) but will fail ZK proof verification. - fn create_dummy_serialized_action() -> SerializedAction { - SerializedAction { - nullifier: [1u8; 32], - rk: [2u8; 32], - cmx: [3u8; 32], - encrypted_note: vec![4u8; 692], // epk(32) + enc(580) + out(80) - cv_net: [5u8; 32], - spend_auth_sig: [6u8; 64], - } - } - /// Create a dummy PlatformAddress for the output. fn create_output_address() -> PlatformAddress { let mut hash = [0u8; 20]; @@ -90,182 +71,6 @@ mod tests { ) } - /// Insert a fake anchor into the shielded anchors tree via GroveDB. - fn insert_anchor_into_state( - platform: &crate::test::helpers::setup::TempPlatform, - anchor: &[u8; 32], - ) { - let platform_version = PlatformVersion::latest(); - let grove_version = &platform_version.drive.grove_version; - let transaction = platform.drive.grove.start_transaction(); - let anchors_path = shielded_anchors_credit_pool_path(); - - platform - .drive - .grove - .insert( - &anchors_path, - anchor, - Element::Item(vec![], None), - None, - Some(&transaction), - grove_version, - ) - .unwrap() - .expect("should insert anchor"); - - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("should commit transaction"); - } - - /// Insert a nullifier into the nullifiers tree via GroveDB. - fn insert_nullifier_into_state( - platform: &crate::test::helpers::setup::TempPlatform, - nullifier: &[u8; 32], - ) { - let platform_version = PlatformVersion::latest(); - let grove_version = &platform_version.drive.grove_version; - let transaction = platform.drive.grove.start_transaction(); - let nullifiers_path = shielded_credit_pool_nullifiers_path(); - - platform - .drive - .grove - .insert( - &nullifiers_path, - nullifier, - Element::Item(vec![], None), - None, - Some(&transaction), - grove_version, - ) - .unwrap() - .expect("should insert nullifier"); - - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("should commit transaction"); - } - - /// Set the shielded pool total balance in GroveDB. - fn set_pool_total_balance( - platform: &crate::test::helpers::setup::TempPlatform, - balance: u64, - ) { - let platform_version = PlatformVersion::latest(); - let grove_version = &platform_version.drive.grove_version; - let transaction = platform.drive.grove.start_transaction(); - let pool_path = shielded_credit_pool_path(); - - platform - .drive - .grove - .insert( - &pool_path, - &[SHIELDED_TOTAL_BALANCE_KEY], - Element::new_sum_item(balance as i64), - None, - Some(&transaction), - grove_version, - ) - .unwrap() - .expect("should set total balance"); - - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("should commit transaction"); - } - - /// Insert dummy encrypted notes into the shielded pool to meet the minimum - /// notes threshold for outgoing transitions. - fn insert_dummy_encrypted_notes( - platform: &crate::test::helpers::setup::TempPlatform, - count: u64, - ) { - let platform_version = PlatformVersion::latest(); - let grove_version = &platform_version.drive.grove_version; - let transaction = platform.drive.grove.start_transaction(); - let notes_path = shielded_credit_pool_encrypted_notes_path(); - - for i in 0..count { - platform - .drive - .grove - .insert( - ¬es_path, - &i.to_be_bytes(), - Element::Item(vec![0], None), - None, - Some(&transaction), - grove_version, - ) - .unwrap() - .expect("should insert dummy note"); - } - - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("should commit transaction"); - } - - /// Standard platform setup for tests. - fn setup_platform( - ) -> crate::test::helpers::setup::TempPlatform { - let platform_config = PlatformConfig { - testing_configs: PlatformTestConfig { - disable_instant_lock_signature_verification: true, - ..Default::default() - }, - ..Default::default() - }; - - TestPlatformBuilder::new() - .with_config(platform_config) - .with_latest_protocol_version() - .build_with_mock_rpc() - .set_genesis_state() - } - - /// Execute a state transition through the full processing pipeline and return the result. - fn process_transition( - platform: &crate::test::helpers::setup::TempPlatform, - transition: StateTransition, - platform_version: &PlatformVersion, - ) -> crate::platform_types::state_transitions_processing_result::StateTransitionsProcessingResult - { - let transition_bytes = transition - .serialize_to_bytes() - .expect("should serialize transition"); - let platform_state = platform.state.load(); - let transaction = platform.drive.grove.start_transaction(); - - platform - .platform - .process_raw_state_transitions( - &vec![transition_bytes], - &platform_state, - &BlockInfo::default(), - &transaction, - platform_version, - false, - None, - ) - .expect("expected to process state transition") - } - // ========================================== // STRUCTURE VALIDATION TESTS (BasicError) // ========================================== diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs index 29045343d98..5c7351ca738 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs @@ -1,21 +1,23 @@ use crate::error::Error; -use crate::execution::validation::state_transition::state_transitions::shielded_common::reconstruct_and_verify_bundle; -use dpp::consensus::state::shielded::insufficient_pool_notes_error::InsufficientPoolNotesError; -use dpp::consensus::state::shielded::invalid_anchor_error::InvalidAnchorError; -use dpp::consensus::state::shielded::nullifier_already_spent_error::NullifierAlreadySpentError; +use crate::execution::types::execution_operation::ValidationOperation; +use crate::execution::types::state_transition_execution_context::{ + StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0, +}; +use crate::execution::validation::state_transition::state_transitions::shielded_common::{ + read_pool_total_balance, reconstruct_and_verify_bundle, validate_anchor_exists, + validate_minimum_pool_notes, validate_nullifiers, +}; +use dpp::block::block_info::BlockInfo; use dpp::consensus::state::state_error::StateError; use dpp::prelude::ConsensusValidationResult; use dpp::state_transition::unshield_transition::UnshieldTransition; use dpp::version::PlatformVersion; -use drive::drive::shielded::paths::{ - shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, - shielded_credit_pool_path, SHIELDED_ENCRYPTED_NOTES_KEY, SHIELDED_TOTAL_BALANCE_KEY, -}; use drive::drive::Drive; use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::unshield::UnshieldTransitionAction; +use drive::state_transition_action::system::penalize_shielded_pool_action::v0::PenalizeShieldedPoolActionV0; +use drive::state_transition_action::system::penalize_shielded_pool_action::PenalizeShieldedPoolAction; use drive::state_transition_action::StateTransitionAction; -use drive::util::grove_operations::DirectQueryType; pub(in crate::execution::validation::state_transition::state_transitions::unshield) trait UnshieldStateTransitionTransformIntoActionValidationV0 { @@ -23,6 +25,8 @@ pub(in crate::execution::validation::state_transition::state_transitions::unshie &self, drive: &Drive, transaction: TransactionArg, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, platform_version: &PlatformVersion, ) -> Result, Error>; } @@ -32,6 +36,8 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti &self, drive: &Drive, transaction: TransactionArg, + block_info: &BlockInfo, + execution_context: &mut StateTransitionExecutionContext, platform_version: &PlatformVersion, ) -> Result, Error> { // Extract nullifiers, note commitments, and encrypted notes from serialized actions @@ -56,100 +62,51 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti // Read current shielded pool state from GroveDB let mut drive_operations = vec![]; - let pool_path = shielded_credit_pool_path(); - - let current_total_balance = drive - .grove_get_raw_value_u64_from_encoded_var_vec( - (&pool_path).into(), - &[SHIELDED_TOTAL_BALANCE_KEY], - DirectQueryType::StatefulDirectQuery, - transaction, - &mut drive_operations, - &platform_version.drive, - )? - .unwrap_or(0); + let current_total_balance = + read_pool_total_balance(drive, transaction, &mut drive_operations, platform_version)?; // Check minimum notes threshold for outgoing transitions (anonymity set) - let min_notes = platform_version - .drive_abci - .validation_and_processing - .event_constants - .minimum_pool_notes_for_outgoing; - if min_notes > 0 { - let encrypted_notes_count = drive - .grove_get_raw_optional( - (&pool_path).into(), - &[SHIELDED_ENCRYPTED_NOTES_KEY], - DirectQueryType::StatefulDirectQuery, - transaction, - &mut drive_operations, - &platform_version.drive, - )? - .map(|element| element.count_value_or_default()) - .unwrap_or(0); - - if encrypted_notes_count < min_notes { - return Ok(ConsensusValidationResult::new_with_error( - StateError::InsufficientPoolNotesError(InsufficientPoolNotesError::new( - encrypted_notes_count, - min_notes, - )) - .into(), - )); - } + if let Some(err) = validate_minimum_pool_notes( + drive, + transaction, + &mut drive_operations, + platform_version, + )? { + return Ok(err); } // Verify the anchor exists in the recorded anchors tree - let anchors_path = shielded_anchors_credit_pool_path(); - let anchor_exists = drive.grove_has_raw( - (&anchors_path).into(), + if let Some(err) = validate_anchor_exists( + drive, &anchor, - DirectQueryType::StatefulDirectQuery, transaction, &mut drive_operations, - &platform_version.drive, - )?; - - if !anchor_exists { - return Ok(ConsensusValidationResult::new_with_error( - StateError::InvalidAnchorError(InvalidAnchorError::new(anchor)).into(), - )); + platform_version, + )? { + return Ok(err); } - // Defense-in-depth: reject duplicate nullifiers within the same bundle - let mut seen_nullifiers = std::collections::HashSet::new(); - for nullifier in &nullifiers { - if !seen_nullifiers.insert(nullifier) { - return Ok(ConsensusValidationResult::new_with_error( - StateError::NullifierAlreadySpentError(NullifierAlreadySpentError::new( - *nullifier, - )) - .into(), - )); - } + // Validate nullifiers: intra-bundle duplicates + already-spent in state + if let Some(err) = validate_nullifiers( + drive, + &nullifiers, + transaction, + &mut drive_operations, + platform_version, + )? { + return Ok(err); } - // Check that no nullifier has already been spent in the state - let nullifiers_path = shielded_credit_pool_nullifiers_path(); - for nullifier in &nullifiers { - let exists = drive.grove_has_raw( - (&nullifiers_path).into(), - nullifier, - DirectQueryType::StatefulDirectQuery, - transaction, - &mut drive_operations, - &platform_version.drive, - )?; - - if exists { - return Ok(ConsensusValidationResult::new_with_error( - StateError::NullifierAlreadySpentError(NullifierAlreadySpentError::new( - *nullifier, - )) - .into(), - )); - } - } + // Calculate fees from the GroveDB operations + let fee = Drive::calculate_fee( + None, + Some(drive_operations), + &block_info.epoch, + drive.config.epochs_per_era, + platform_version, + None, + )?; + execution_context.add_operation(ValidationOperation::PrecalculatedOperation(fee)); // Verify the ZK proof, binding transparent fields to the sighash let ( @@ -172,6 +129,21 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti ), }; + // Verify the pool has sufficient balance for the unshield amount + if current_total_balance < amount { + return Ok(ConsensusValidationResult::new_with_error( + StateError::InvalidShieldedProofError( + dpp::consensus::state::shielded::invalid_shielded_proof_error::InvalidShieldedProofError::new( + format!( + "shielded pool has insufficient balance: pool has {} but unshield requires {}", + current_total_balance, amount + ), + ), + ) + .into(), + )); + } + // Serialize transparent fields to bind them to the Orchard sighash. // This prevents an attacker from substituting a different output_address // or amount while reusing a valid Orchard bundle. @@ -187,8 +159,25 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti st_binding_sig, &extra_sighash_data, ) { - return Ok(ConsensusValidationResult::new_with_error( - StateError::InvalidShieldedProofError(e).into(), + let penalty = platform_version + .drive_abci + .validation_and_processing + .penalties + .shielded_proof_verification_failure; + + let penalty_amount = std::cmp::min(penalty, current_total_balance); + + let penalize_action = StateTransitionAction::PenalizeShieldedPoolAction( + PenalizeShieldedPoolAction::from(PenalizeShieldedPoolActionV0 { + penalty_amount, + nullifiers: nullifiers.clone(), + current_total_balance, + }), + ); + + return Ok(ConsensusValidationResult::new_with_data_and_errors( + penalize_action, + vec![StateError::InvalidShieldedProofError(e).into()], )); } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs index ba5ca5e135c..9a9de3e81d6 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/transformer/mod.rs @@ -244,27 +244,42 @@ impl StateTransitionActionTransformer for StateTransition { st.transform_into_action_for_shield_transition( platform, remaining_address_input_balances.clone(), + block_info, + execution_context, tx, ) } - StateTransition::ShieldedTransfer(st) => { - st.transform_into_action_for_shielded_transfer_transition(platform, tx) - } - StateTransition::Unshield(st) => { - st.transform_into_action_for_unshield_transition(platform, tx) - } + StateTransition::ShieldedTransfer(st) => st + .transform_into_action_for_shielded_transfer_transition( + platform, + block_info, + execution_context, + tx, + ), + StateTransition::Unshield(st) => st.transform_into_action_for_unshield_transition( + platform, + block_info, + execution_context, + tx, + ), StateTransition::ShieldFromAssetLock(st) => { let signable_bytes = self.signable_bytes()?; st.transform_into_action_for_shield_from_asset_lock_transition( platform, signable_bytes, validation_mode, + block_info, execution_context, tx, ) } StateTransition::ShieldedWithdrawal(st) => st - .transform_into_action_for_shielded_withdrawal_transition(platform, block_info, tx), + .transform_into_action_for_shielded_withdrawal_transition( + platform, + block_info, + execution_context, + tx, + ), } } } diff --git a/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs index 63c036d3f48..0d22d4df4af 100644 --- a/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs @@ -1,4 +1,3 @@ -use crate::error::query::QueryError; use crate::error::Error; use crate::platform_types::platform::Platform; use crate::platform_types::platform_state::PlatformState; @@ -15,7 +14,6 @@ use dpp::check_validation_result_with_data; use dpp::validation::ValidationResult; use dpp::version::PlatformVersion; use drive::drive::shielded::paths::shielded_credit_pool_encrypted_notes_path_vec; -use drive::error::query::QuerySyntaxError; use drive::grovedb::query_result_type::QueryResultType; use drive::grovedb::{PathQuery, Query, SizedQuery}; use drive::util::grove_operations::GroveDBToUse; @@ -38,15 +36,6 @@ impl Platform { count as u16 }; - if limit > max_elements as u16 { - return Ok(QueryValidationResult::new_with_error(QueryError::Query( - QuerySyntaxError::InvalidLimit(format!( - "trying to get {} encrypted notes, maximum is {}", - limit, max_elements - )), - ))); - } - let query = if start_index == 0 { Query::new_range_full() } else { diff --git a/packages/rs-drive-abci/src/query/shielded/nullifiers/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/nullifiers/v0/mod.rs index 0795200b328..b0fb644f87c 100644 --- a/packages/rs-drive-abci/src/query/shielded/nullifiers/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/shielded/nullifiers/v0/mod.rs @@ -45,6 +45,19 @@ impl Platform { )); } + // Validate that all nullifiers are exactly 32 bytes + for (i, nullifier) in nullifiers.iter().enumerate() { + if nullifier.len() != 32 { + return Ok(QueryValidationResult::new_with_error( + QueryError::InvalidArgument(format!( + "nullifier at index {} has invalid length: expected 32 bytes, got {}", + i, + nullifier.len() + )), + )); + } + } + let response = if prove { let path_query = PathQuery { path: shielded_credit_pool_nullifiers_path_vec(), diff --git a/packages/rs-drive-proof-verifier/src/types.rs b/packages/rs-drive-proof-verifier/src/types.rs index 65d1194c7c2..98f31d31e3a 100644 --- a/packages/rs-drive-proof-verifier/src/types.rs +++ b/packages/rs-drive-proof-verifier/src/types.rs @@ -799,7 +799,7 @@ pub struct ShieldedEncryptedNotes(pub Vec); derive(Encode, Decode, PlatformSerialize, PlatformDeserialize), platform_serialize(unversioned) )] -pub struct ShieldedAnchors(pub Vec>); +pub struct ShieldedAnchors(pub Vec<[u8; 32]>); /// Status of a single nullifier (spent or unspent) #[derive(Debug, Clone)] diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs index 1ed7ba86664..dbfa6c50e04 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/mod.rs @@ -123,6 +123,10 @@ impl DriveHighLevelOperationConverter for StateTransitionAction { StateTransitionAction::ShieldedWithdrawalAction(shielded_withdrawal_action) => { shielded_withdrawal_action.into_high_level_drive_operations(epoch, platform_version) } + StateTransitionAction::PenalizeShieldedPoolAction(penalize_shielded_pool_action) => { + penalize_shielded_pool_action + .into_high_level_drive_operations(epoch, platform_version) + } } } } diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs index 8c98eb892d3..ee4b02f91be 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs @@ -1,19 +1,12 @@ -use crate::error::Error; -use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; -use crate::state_transition_action::shielded::shield::ShieldTransitionAction; -use crate::state_transition_action::shielded::shield_from_asset_lock::ShieldFromAssetLockTransitionAction; -use crate::state_transition_action::shielded::shielded_transfer::ShieldedTransferTransitionAction; -use crate::state_transition_action::shielded::shielded_withdrawal::ShieldedWithdrawalTransitionAction; -use crate::state_transition_action::shielded::unshield::UnshieldTransitionAction; +mod shield_from_asset_lock_transition; +mod shield_transition; +mod shielded_transfer_transition; +mod shielded_withdrawal_transition; +mod unshield_transition; + use crate::util::batch::drive_op_batch::finalize_task::DriveOperationFinalizeTask; -use crate::util::batch::drive_op_batch::{ - AddressFundsOperationType, ShieldedPoolOperationType, SystemOperationType, -}; -use crate::util::batch::{DocumentOperationType, DriveOperation}; -use crate::util::object_size_info::{DocumentInfo, OwnedDocumentInfo}; -use dpp::asset_lock::reduced_asset_lock_value::AssetLockValue; -use dpp::block::epoch::Epoch; -use dpp::version::PlatformVersion; +use crate::util::batch::drive_op_batch::ShieldedPoolOperationType; +use crate::util::batch::DriveOperation; use grovedb::Element; /// Build the encrypted note items (cmx || encrypted_note) for auto-incremented insertion. @@ -32,345 +25,51 @@ fn build_encrypted_note_items( .collect() } -impl DriveHighLevelOperationConverter for ShieldTransitionAction { - fn into_high_level_drive_operations<'a>( - self, - _epoch: &Epoch, - _platform_version: &PlatformVersion, - ) -> Result>, Error> { - match self { - ShieldTransitionAction::V0(v0) => { - let mut ops: Vec> = Vec::new(); - - // 1. Debit each input address: set remaining balance - for (address, (nonce, remaining_balance)) in v0.inputs_with_remaining_balance { - ops.push(DriveOperation::AddressFundsOperation( - AddressFundsOperationType::SetBalanceToAddress { - address, - nonce, - balance: remaining_balance, - }, - )); - } - - // 2. Append each note commitment to the commitment tree - for cmx in v0.note_commitments.iter() { - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::AppendNoteCommitment { cmx: *cmx }, - )); - } - - // 3. Insert encrypted notes with auto-incremented keys in count tree - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::InsertEncryptedNotes { - items: build_encrypted_note_items( - &v0.note_commitments, - &v0.encrypted_notes, - ), - }, - )); - - // 4. Update total balance SumItem: current_total_balance + shield_amount - let new_total_balance = v0 - .current_total_balance - .checked_add(v0.shield_amount) - .ok_or_else(|| { - Error::Drive(crate::error::drive::DriveError::CorruptedDriveState( - "shielded pool total balance overflow when adding shield amount" - .to_string(), - )) - })?; - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::UpdateTotalBalance { new_total_balance }, - )); - - // Checkpoint the commitment tree and record anchor after batch is applied - ops.push(DriveOperation::FinalizeOperation( - DriveOperationFinalizeTask::RecordShieldedAnchor, - )); - - Ok(ops) - } - } +/// Append each note commitment to the commitment tree. +pub(super) fn append_note_commitments<'a>( + ops: &mut Vec>, + note_commitments: &[[u8; 32]], +) { + for cmx in note_commitments.iter() { + ops.push(DriveOperation::ShieldedPoolOperation( + ShieldedPoolOperationType::AppendNoteCommitment { cmx: *cmx }, + )); } } -impl DriveHighLevelOperationConverter for ShieldedTransferTransitionAction { - fn into_high_level_drive_operations<'a>( - self, - _epoch: &Epoch, - _platform_version: &PlatformVersion, - ) -> Result>, Error> { - match self { - ShieldedTransferTransitionAction::V0(v0) => { - let mut ops: Vec> = Vec::new(); - - // 1. Insert each nullifier (InsertOnly to prevent double-spend) - for nullifier in v0.nullifiers.iter() { - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::InsertNullifier { - nullifier: *nullifier, - }, - )); - } - - // 2. Append each note commitment to the commitment tree - for cmx in v0.note_commitments.iter() { - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::AppendNoteCommitment { cmx: *cmx }, - )); - } - - // 3. Insert encrypted notes with auto-incremented keys in count tree - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::InsertEncryptedNotes { - items: build_encrypted_note_items( - &v0.note_commitments, - &v0.encrypted_notes, - ), - }, - )); - - // 4. Update total balance SumItem: subtract fee_amount - let new_total_balance = v0 - .current_total_balance - .checked_sub(v0.fee_amount) - .ok_or_else(|| { - Error::Drive(crate::error::drive::DriveError::CorruptedDriveState( - "shielded pool total balance underflow when subtracting fee_amount" - .to_string(), - )) - })?; - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::UpdateTotalBalance { new_total_balance }, - )); - - // Checkpoint the commitment tree and record anchor after batch is applied - ops.push(DriveOperation::FinalizeOperation( - DriveOperationFinalizeTask::RecordShieldedAnchor, - )); - - Ok(ops) - } - } +/// Insert each nullifier (InsertOnly to prevent double-spend). +pub(super) fn insert_nullifiers<'a>(ops: &mut Vec>, nullifiers: &[[u8; 32]]) { + for nullifier in nullifiers.iter() { + ops.push(DriveOperation::ShieldedPoolOperation( + ShieldedPoolOperationType::InsertNullifier { + nullifier: *nullifier, + }, + )); } } -impl DriveHighLevelOperationConverter for UnshieldTransitionAction { - fn into_high_level_drive_operations<'a>( - self, - _epoch: &Epoch, - _platform_version: &PlatformVersion, - ) -> Result>, Error> { - match self { - UnshieldTransitionAction::V0(v0) => { - let mut ops: Vec> = Vec::new(); - - // 1. Insert each nullifier (InsertOnly to prevent double-spend) - for nullifier in v0.nullifiers.iter() { - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::InsertNullifier { - nullifier: *nullifier, - }, - )); - } - - // 2. Credit the output address with the unshielded amount - ops.push(DriveOperation::AddressFundsOperation( - AddressFundsOperationType::AddBalanceToAddress { - address: v0.output_address, - balance_to_add: v0.amount, - }, - )); - - // 3. Append each note commitment (change outputs) to the commitment tree - for cmx in v0.note_commitments.iter() { - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::AppendNoteCommitment { cmx: *cmx }, - )); - } - - // 4. Insert encrypted notes with auto-incremented keys in count tree - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::InsertEncryptedNotes { - items: build_encrypted_note_items( - &v0.note_commitments, - &v0.encrypted_notes, - ), - }, - )); - - // 5. Update total balance SumItem: subtract the unshielded amount - // (fee is handled separately by the fee system) - let new_total_balance = v0 - .current_total_balance - .checked_sub(v0.amount) - .ok_or_else(|| Error::Drive( - crate::error::drive::DriveError::CorruptedDriveState( - "shielded pool total balance underflow when subtracting unshield amount".to_string(), - ), - ))?; - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::UpdateTotalBalance { new_total_balance }, - )); - - // Checkpoint the commitment tree and record anchor after batch is applied - ops.push(DriveOperation::FinalizeOperation( - DriveOperationFinalizeTask::RecordShieldedAnchor, - )); - - Ok(ops) - } - } - } -} - -impl DriveHighLevelOperationConverter for ShieldFromAssetLockTransitionAction { - fn into_high_level_drive_operations<'a>( - self, - _epoch: &Epoch, - _platform_version: &PlatformVersion, - ) -> Result>, Error> { - match self { - ShieldFromAssetLockTransitionAction::V0(v0) => { - let mut ops: Vec> = Vec::new(); - - // 1. Add credits to system from the asset lock - ops.push(DriveOperation::SystemOperation( - SystemOperationType::AddToSystemCredits { - amount: v0.asset_lock_value_to_be_consumed, - }, - )); - - // 2. Record asset lock as consumed (prevent replay) - let asset_lock_value = AssetLockValue::new( - v0.asset_lock_value_to_be_consumed, - vec![], // tx_out_script not needed for shielded - 0, // remaining_credit_value = 0 (fully consumed) - vec![], // no used tags for shielded - _platform_version, - ) - .map_err(|e| Error::Protocol(Box::new(e)))?; - ops.push(DriveOperation::SystemOperation( - SystemOperationType::AddUsedAssetLock { - asset_lock_outpoint: v0.asset_lock_outpoint.into(), - asset_lock_value, - }, - )); - - // 3. Append note commitments to commitment tree - for cmx in v0.note_commitments.iter() { - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::AppendNoteCommitment { cmx: *cmx }, - )); - } - - // 4. Insert encrypted notes with auto-incremented keys in count tree - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::InsertEncryptedNotes { - items: build_encrypted_note_items( - &v0.note_commitments, - &v0.encrypted_notes, - ), - }, - )); - - // 5. Update total balance: current_total_balance + shield_amount - let new_total_balance = v0.current_total_balance.checked_add(v0.shield_amount) - .ok_or_else(|| Error::Drive( - crate::error::drive::DriveError::CorruptedDriveState( - "shielded pool total balance overflow when adding shield_from_asset_lock amount".to_string(), - ), - ))?; - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::UpdateTotalBalance { new_total_balance }, - )); - - // 6. Record anchor after batch is applied - ops.push(DriveOperation::FinalizeOperation( - DriveOperationFinalizeTask::RecordShieldedAnchor, - )); - - Ok(ops) - } - } - } +/// Insert encrypted notes with auto-incremented keys in count tree. +pub(super) fn insert_encrypted_notes<'a>( + ops: &mut Vec>, + note_commitments: &[[u8; 32]], + encrypted_notes: &[Vec], +) { + ops.push(DriveOperation::ShieldedPoolOperation( + ShieldedPoolOperationType::InsertEncryptedNotes { + items: build_encrypted_note_items(note_commitments, encrypted_notes), + }, + )); } -impl DriveHighLevelOperationConverter for ShieldedWithdrawalTransitionAction { - fn into_high_level_drive_operations<'a>( - self, - _epoch: &Epoch, - _platform_version: &PlatformVersion, - ) -> Result>, Error> { - match self { - ShieldedWithdrawalTransitionAction::V0(v0) => { - let mut ops: Vec> = Vec::new(); - - // 1. Insert nullifiers (prevent double-spend) - for nullifier in v0.nullifiers.iter() { - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::InsertNullifier { - nullifier: *nullifier, - }, - )); - } - - // 2. Append change note commitments to commitment tree - for cmx in v0.note_commitments.iter() { - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::AppendNoteCommitment { cmx: *cmx }, - )); - } - - // 3. Insert encrypted change notes with auto-incremented keys in count tree - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::InsertEncryptedNotes { - items: build_encrypted_note_items( - &v0.note_commitments, - &v0.encrypted_notes, - ), - }, - )); - - // 4. Update total balance: subtract withdrawal amount - let new_total_balance = v0 - .current_total_balance - .checked_sub(v0.amount) - .ok_or_else(|| Error::Drive( - crate::error::drive::DriveError::CorruptedDriveState( - "shielded pool total balance underflow when subtracting shielded_withdrawal amount".to_string(), - ), - ))?; - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::UpdateTotalBalance { new_total_balance }, - )); - - // 5. Add withdrawal document - ops.push(DriveOperation::DocumentOperation( - DocumentOperationType::AddWithdrawalDocument { - owned_document_info: OwnedDocumentInfo { - document_info: DocumentInfo::DocumentOwnedInfo(( - v0.prepared_withdrawal_document, - None, - )), - owner_id: None, - }, - }, - )); - - // 6. Remove credits from system (they leave the system to Core) - ops.push(DriveOperation::SystemOperation( - SystemOperationType::RemoveFromSystemCredits { amount: v0.amount }, - )); - - // 7. Record anchor after batch is applied - ops.push(DriveOperation::FinalizeOperation( - DriveOperationFinalizeTask::RecordShieldedAnchor, - )); - - Ok(ops) - } - } - } +/// Update pool total balance and record shielded anchor. +pub(super) fn update_balance_and_record_anchor<'a>( + ops: &mut Vec>, + new_total_balance: u64, +) { + ops.push(DriveOperation::ShieldedPoolOperation( + ShieldedPoolOperationType::UpdateTotalBalance { new_total_balance }, + )); + ops.push(DriveOperation::FinalizeOperation( + DriveOperationFinalizeTask::RecordShieldedAnchor, + )); } diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_from_asset_lock_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_from_asset_lock_transition.rs new file mode 100644 index 00000000000..26a9aedd634 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_from_asset_lock_transition.rs @@ -0,0 +1,81 @@ +use super::{append_note_commitments, insert_encrypted_notes, update_balance_and_record_anchor}; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; +use crate::state_transition_action::shielded::shield_from_asset_lock::ShieldFromAssetLockTransitionAction; +use crate::util::batch::drive_op_batch::SystemOperationType; +use crate::util::batch::DriveOperation; +use dpp::asset_lock::reduced_asset_lock_value::AssetLockValue; +use dpp::block::epoch::Epoch; +use dpp::version::PlatformVersion; + +impl DriveHighLevelOperationConverter for ShieldFromAssetLockTransitionAction { + fn into_high_level_drive_operations<'a>( + self, + _epoch: &Epoch, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .state_transitions + .convert_to_high_level_operations + .shield_from_asset_lock_transition + { + 0 => match self { + ShieldFromAssetLockTransitionAction::V0(v0) => { + let mut ops: Vec> = Vec::new(); + + // 1. Add credits to system from the asset lock + ops.push(DriveOperation::SystemOperation( + SystemOperationType::AddToSystemCredits { + amount: v0.asset_lock_value_to_be_consumed, + }, + )); + + // 2. Record asset lock as consumed (prevent replay) + let asset_lock_value = AssetLockValue::new( + v0.asset_lock_value_to_be_consumed, + vec![], // tx_out_script not needed for shielded + 0, // remaining_credit_value = 0 (fully consumed) + vec![], // no used tags for shielded + platform_version, + ) + .map_err(|e| Error::Protocol(Box::new(e)))?; + ops.push(DriveOperation::SystemOperation( + SystemOperationType::AddUsedAssetLock { + asset_lock_outpoint: v0.asset_lock_outpoint.into(), + asset_lock_value, + }, + )); + + // 3. Append note commitments to commitment tree + append_note_commitments(&mut ops, &v0.note_commitments); + + // 4. Insert encrypted notes with auto-incremented keys in count tree + insert_encrypted_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); + + // 5. Update total balance and record anchor + let new_total_balance = + v0.current_total_balance + .checked_add(v0.shield_amount) + .ok_or_else(|| { + Error::Drive(DriveError::CorruptedDriveState( + "shielded pool total balance overflow when adding shield_from_asset_lock amount" + .to_string(), + )) + })?; + update_balance_and_record_anchor(&mut ops, new_total_balance); + + Ok(ops) + } + }, + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "ShieldFromAssetLockTransitionAction::into_high_level_drive_operations" + .to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_transition.rs new file mode 100644 index 00000000000..b6b5a06fdc6 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_transition.rs @@ -0,0 +1,67 @@ +use super::{append_note_commitments, insert_encrypted_notes, update_balance_and_record_anchor}; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; +use crate::state_transition_action::shielded::shield::ShieldTransitionAction; +use crate::util::batch::drive_op_batch::AddressFundsOperationType; +use crate::util::batch::DriveOperation; +use dpp::block::epoch::Epoch; +use dpp::version::PlatformVersion; + +impl DriveHighLevelOperationConverter for ShieldTransitionAction { + fn into_high_level_drive_operations<'a>( + self, + _epoch: &Epoch, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .state_transitions + .convert_to_high_level_operations + .shield_transition + { + 0 => match self { + ShieldTransitionAction::V0(v0) => { + let mut ops: Vec> = Vec::new(); + + // 1. Debit each input address: set remaining balance + for (address, (nonce, remaining_balance)) in v0.inputs_with_remaining_balance { + ops.push(DriveOperation::AddressFundsOperation( + AddressFundsOperationType::SetBalanceToAddress { + address, + nonce, + balance: remaining_balance, + }, + )); + } + + // 2. Append each note commitment to the commitment tree + append_note_commitments(&mut ops, &v0.note_commitments); + + // 3. Insert encrypted notes with auto-incremented keys in count tree + insert_encrypted_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); + + // 4. Update total balance and record anchor + let new_total_balance = v0 + .current_total_balance + .checked_add(v0.shield_amount) + .ok_or_else(|| { + Error::Drive(DriveError::CorruptedDriveState( + "shielded pool total balance overflow when adding shield amount" + .to_string(), + )) + })?; + update_balance_and_record_anchor(&mut ops, new_total_balance); + + Ok(ops) + } + }, + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "ShieldTransitionAction::into_high_level_drive_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs new file mode 100644 index 00000000000..5b5043390ba --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs @@ -0,0 +1,62 @@ +use super::{ + append_note_commitments, insert_encrypted_notes, insert_nullifiers, + update_balance_and_record_anchor, +}; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; +use crate::state_transition_action::shielded::shielded_transfer::ShieldedTransferTransitionAction; +use crate::util::batch::DriveOperation; +use dpp::block::epoch::Epoch; +use dpp::version::PlatformVersion; + +impl DriveHighLevelOperationConverter for ShieldedTransferTransitionAction { + fn into_high_level_drive_operations<'a>( + self, + _epoch: &Epoch, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .state_transitions + .convert_to_high_level_operations + .shielded_transfer_transition + { + 0 => match self { + ShieldedTransferTransitionAction::V0(v0) => { + let mut ops: Vec> = Vec::new(); + + // 1. Insert each nullifier (InsertOnly to prevent double-spend) + insert_nullifiers(&mut ops, &v0.nullifiers); + + // 2. Append each note commitment to the commitment tree + append_note_commitments(&mut ops, &v0.note_commitments); + + // 3. Insert encrypted notes with auto-incremented keys in count tree + insert_encrypted_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); + + // 4. Update total balance and record anchor + let new_total_balance = v0 + .current_total_balance + .checked_sub(v0.fee_amount) + .ok_or_else(|| { + Error::Drive(DriveError::CorruptedDriveState( + "shielded pool total balance underflow when subtracting fee_amount" + .to_string(), + )) + })?; + update_balance_and_record_anchor(&mut ops, new_total_balance); + + Ok(ops) + } + }, + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "ShieldedTransferTransitionAction::into_high_level_drive_operations" + .to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs new file mode 100644 index 00000000000..b617411cd01 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs @@ -0,0 +1,82 @@ +use super::{ + append_note_commitments, insert_encrypted_notes, insert_nullifiers, + update_balance_and_record_anchor, +}; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; +use crate::state_transition_action::shielded::shielded_withdrawal::ShieldedWithdrawalTransitionAction; +use crate::util::batch::drive_op_batch::SystemOperationType; +use crate::util::batch::{DocumentOperationType, DriveOperation}; +use crate::util::object_size_info::{DocumentInfo, OwnedDocumentInfo}; +use dpp::block::epoch::Epoch; +use dpp::version::PlatformVersion; + +impl DriveHighLevelOperationConverter for ShieldedWithdrawalTransitionAction { + fn into_high_level_drive_operations<'a>( + self, + _epoch: &Epoch, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .state_transitions + .convert_to_high_level_operations + .shielded_withdrawal_transition + { + 0 => match self { + ShieldedWithdrawalTransitionAction::V0(v0) => { + let mut ops: Vec> = Vec::new(); + + // 1. Insert nullifiers (prevent double-spend) + insert_nullifiers(&mut ops, &v0.nullifiers); + + // 2. Append change note commitments to commitment tree + append_note_commitments(&mut ops, &v0.note_commitments); + + // 3. Insert encrypted change notes with auto-incremented keys in count tree + insert_encrypted_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); + + // 4. Update total balance: subtract withdrawal amount + let new_total_balance = + v0.current_total_balance + .checked_sub(v0.amount) + .ok_or_else(|| { + Error::Drive(DriveError::CorruptedDriveState( + "shielded pool total balance underflow when subtracting shielded_withdrawal amount" + .to_string(), + )) + })?; + update_balance_and_record_anchor(&mut ops, new_total_balance); + + // 5. Add withdrawal document + ops.push(DriveOperation::DocumentOperation( + DocumentOperationType::AddWithdrawalDocument { + owned_document_info: OwnedDocumentInfo { + document_info: DocumentInfo::DocumentOwnedInfo(( + v0.prepared_withdrawal_document, + None, + )), + owner_id: None, + }, + }, + )); + + // 6. Remove credits from system (they leave the system to Core) + ops.push(DriveOperation::SystemOperation( + SystemOperationType::RemoveFromSystemCredits { amount: v0.amount }, + )); + + Ok(ops) + } + }, + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "ShieldedWithdrawalTransitionAction::into_high_level_drive_operations" + .to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs new file mode 100644 index 00000000000..a63a820baa5 --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs @@ -0,0 +1,70 @@ +use super::{ + append_note_commitments, insert_encrypted_notes, insert_nullifiers, + update_balance_and_record_anchor, +}; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; +use crate::state_transition_action::shielded::unshield::UnshieldTransitionAction; +use crate::util::batch::drive_op_batch::AddressFundsOperationType; +use crate::util::batch::DriveOperation; +use dpp::block::epoch::Epoch; +use dpp::version::PlatformVersion; + +impl DriveHighLevelOperationConverter for UnshieldTransitionAction { + fn into_high_level_drive_operations<'a>( + self, + _epoch: &Epoch, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .state_transitions + .convert_to_high_level_operations + .unshield_transition + { + 0 => match self { + UnshieldTransitionAction::V0(v0) => { + let mut ops: Vec> = Vec::new(); + + // 1. Insert each nullifier (InsertOnly to prevent double-spend) + insert_nullifiers(&mut ops, &v0.nullifiers); + + // 2. Credit the output address with the unshielded amount + ops.push(DriveOperation::AddressFundsOperation( + AddressFundsOperationType::AddBalanceToAddress { + address: v0.output_address, + balance_to_add: v0.amount, + }, + )); + + // 3. Append each note commitment (change outputs) to the commitment tree + append_note_commitments(&mut ops, &v0.note_commitments); + + // 4. Insert encrypted notes with auto-incremented keys in count tree + insert_encrypted_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); + + // 5. Update total balance and record anchor + let new_total_balance = + v0.current_total_balance + .checked_sub(v0.amount) + .ok_or_else(|| { + Error::Drive(DriveError::CorruptedDriveState( + "shielded pool total balance underflow when subtracting unshield amount" + .to_string(), + )) + })?; + update_balance_and_record_anchor(&mut ops, new_total_balance); + + Ok(ops) + } + }, + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "UnshieldTransitionAction::into_high_level_drive_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/system/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/system/mod.rs index 84721e56f9d..f3fe110aac1 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/system/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/system/mod.rs @@ -2,3 +2,4 @@ mod bump_address_input_nonces; mod bump_identity_data_contract_nonce; mod bump_identity_nonce; mod partially_use_asset_lock; +mod penalize_shielded_pool; diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/system/penalize_shielded_pool.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/system/penalize_shielded_pool.rs new file mode 100644 index 00000000000..a62d0b8a2aa --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/system/penalize_shielded_pool.rs @@ -0,0 +1,38 @@ +use crate::error::Error; +use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; +use crate::state_transition_action::system::penalize_shielded_pool_action::PenalizeShieldedPoolAction; +use crate::util::batch::drive_op_batch::ShieldedPoolOperationType; +use crate::util::batch::DriveOperation; +use dpp::block::epoch::Epoch; +use dpp::version::PlatformVersion; + +impl DriveHighLevelOperationConverter for PenalizeShieldedPoolAction { + fn into_high_level_drive_operations<'a>( + self, + _epoch: &Epoch, + _platform_version: &PlatformVersion, + ) -> Result>, Error> { + match self { + PenalizeShieldedPoolAction::V0(v0) => { + let mut ops: Vec> = Vec::new(); + + // 1. Record nullifiers as spent (prevents replaying the same invalid proof) + for nullifier in v0.nullifiers.iter() { + ops.push(DriveOperation::ShieldedPoolOperation( + ShieldedPoolOperationType::InsertNullifier { + nullifier: *nullifier, + }, + )); + } + + // 2. Deduct penalty from pool total balance + let new_total_balance = v0.current_total_balance.saturating_sub(v0.penalty_amount); + ops.push(DriveOperation::ShieldedPoolOperation( + ShieldedPoolOperationType::UpdateTotalBalance { new_total_balance }, + )); + + Ok(ops) + } + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/mod.rs index 304bcc6c735..0e658f3ed72 100644 --- a/packages/rs-drive/src/state_transition_action/mod.rs +++ b/packages/rs-drive/src/state_transition_action/mod.rs @@ -46,6 +46,7 @@ use crate::state_transition_action::system::bump_identity_nonce_action::{ use crate::state_transition_action::system::partially_use_asset_lock_action::{ PartiallyUseAssetLockAction, PartiallyUseAssetLockActionAccessorsV0, }; +use crate::state_transition_action::system::penalize_shielded_pool_action::PenalizeShieldedPoolAction; use derive_more::From; use dpp::prelude::UserFeeIncrease; @@ -107,6 +108,8 @@ pub enum StateTransitionAction { ShieldFromAssetLockAction(ShieldFromAssetLockTransitionAction), /// shielded withdrawal (shielded pool -> L1 core address) ShieldedWithdrawalAction(ShieldedWithdrawalTransitionAction), + /// penalize shielded pool for invalid ZK proof + PenalizeShieldedPoolAction(PenalizeShieldedPoolAction), } impl StateTransitionAction { @@ -157,6 +160,9 @@ impl StateTransitionAction { StateTransitionAction::UnshieldAction(action) => action.user_fee_increase(), StateTransitionAction::ShieldFromAssetLockAction(action) => action.user_fee_increase(), StateTransitionAction::ShieldedWithdrawalAction(action) => action.user_fee_increase(), + StateTransitionAction::PenalizeShieldedPoolAction(_) => { + UserFeeIncrease::default() // 0 (no user fee increase for penalty actions) + } } } } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/mod.rs index c19419bbc88..d7ab7f7b1dd 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/mod.rs @@ -33,13 +33,13 @@ impl ShieldTransitionAction { } } /// Get note commitments - pub fn note_commitments(&self) -> &Vec<[u8; 32]> { + pub fn note_commitments(&self) -> &[[u8; 32]] { match self { ShieldTransitionAction::V0(transition) => &transition.note_commitments, } } /// Get encrypted notes - pub fn encrypted_notes(&self) -> &Vec> { + pub fn encrypted_notes(&self) -> &[Vec] { match self { ShieldTransitionAction::V0(transition) => &transition.encrypted_notes, } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs index 72845049af8..fee8a77ed44 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs @@ -6,7 +6,7 @@ use dpp::prelude::{AddressNonce, UserFeeIncrease}; use std::collections::BTreeMap; /// Shield transition action v0 -#[derive(Default, Debug, Clone)] +#[derive(Debug, Clone)] pub struct ShieldTransitionActionV0 { /// inputs with remaining balance after shielding pub inputs_with_remaining_balance: BTreeMap, diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/mod.rs index 9a7d23dc9ba..dfd3e7d93e6 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/mod.rs @@ -45,13 +45,13 @@ impl ShieldFromAssetLockTransitionAction { } } /// Get note commitments - pub fn note_commitments(&self) -> &Vec<[u8; 32]> { + pub fn note_commitments(&self) -> &[[u8; 32]] { match self { ShieldFromAssetLockTransitionAction::V0(transition) => &transition.note_commitments, } } /// Get encrypted notes - pub fn encrypted_notes(&self) -> &Vec> { + pub fn encrypted_notes(&self) -> &[Vec] { match self { ShieldFromAssetLockTransitionAction::V0(transition) => &transition.encrypted_notes, } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/mod.rs index 4571a55d1f4..ee59e530ad7 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/mod.rs @@ -17,19 +17,19 @@ pub enum ShieldedTransferTransitionAction { impl ShieldedTransferTransitionAction { /// Get nullifiers - pub fn nullifiers(&self) -> &Vec<[u8; 32]> { + pub fn nullifiers(&self) -> &[[u8; 32]] { match self { ShieldedTransferTransitionAction::V0(transition) => &transition.nullifiers, } } /// Get note commitments - pub fn note_commitments(&self) -> &Vec<[u8; 32]> { + pub fn note_commitments(&self) -> &[[u8; 32]] { match self { ShieldedTransferTransitionAction::V0(transition) => &transition.note_commitments, } } /// Get encrypted notes - pub fn encrypted_notes(&self) -> &Vec> { + pub fn encrypted_notes(&self) -> &[Vec] { match self { ShieldedTransferTransitionAction::V0(transition) => &transition.encrypted_notes, } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs index 55baa9c4a80..0ff42384677 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs @@ -4,7 +4,7 @@ use dpp::fee::Credits; use dpp::prelude::UserFeeIncrease; /// Shielded transfer transition action v0 -#[derive(Default, Debug, Clone)] +#[derive(Debug, Clone)] pub struct ShieldedTransferTransitionActionV0 { /// Nullifiers from spent notes pub nullifiers: Vec<[u8; 32]>, diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/mod.rs index b9b8b4f54db..6838f0dbef8 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/mod.rs @@ -26,19 +26,19 @@ impl ShieldedWithdrawalTransitionAction { } } /// Get nullifiers - pub fn nullifiers(&self) -> &Vec<[u8; 32]> { + pub fn nullifiers(&self) -> &[[u8; 32]] { match self { ShieldedWithdrawalTransitionAction::V0(transition) => &transition.nullifiers, } } /// Get note commitments - pub fn note_commitments(&self) -> &Vec<[u8; 32]> { + pub fn note_commitments(&self) -> &[[u8; 32]] { match self { ShieldedWithdrawalTransitionAction::V0(transition) => &transition.note_commitments, } } /// Get encrypted notes - pub fn encrypted_notes(&self) -> &Vec> { + pub fn encrypted_notes(&self) -> &[Vec] { match self { ShieldedWithdrawalTransitionAction::V0(transition) => &transition.encrypted_notes, } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/transformer.rs index 34e2054803f..94d9199e2d7 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/transformer.rs @@ -46,7 +46,9 @@ impl ShieldedWithdrawalTransitionActionV0 { let withdrawal_document = DocumentV0 { id: document_id, owner_id, - properties: document_data.into_btree_string_map().unwrap(), + properties: document_data + .into_btree_string_map() + .expect("platform_value macro produces a map"), revision: Some(1), created_at: Some(creation_time_ms), updated_at: Some(creation_time_ms), diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/mod.rs index 868b732de81..3c5b3d1f150 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/unshield/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/mod.rs @@ -30,19 +30,19 @@ impl UnshieldTransitionAction { } } /// Get nullifiers - pub fn nullifiers(&self) -> &Vec<[u8; 32]> { + pub fn nullifiers(&self) -> &[[u8; 32]] { match self { UnshieldTransitionAction::V0(transition) => &transition.nullifiers, } } /// Get note commitments - pub fn note_commitments(&self) -> &Vec<[u8; 32]> { + pub fn note_commitments(&self) -> &[[u8; 32]] { match self { UnshieldTransitionAction::V0(transition) => &transition.note_commitments, } } /// Get encrypted notes - pub fn encrypted_notes(&self) -> &Vec> { + pub fn encrypted_notes(&self) -> &[Vec] { match self { UnshieldTransitionAction::V0(transition) => &transition.encrypted_notes, } diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs index 0d11bebc68c..7cd7d394e10 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs @@ -5,7 +5,7 @@ use dpp::fee::Credits; use dpp::prelude::UserFeeIncrease; /// Unshield transition action v0 -#[derive(Default, Debug, Clone)] +#[derive(Debug, Clone)] pub struct UnshieldTransitionActionV0 { /// The address receiving unshielded funds pub output_address: PlatformAddress, diff --git a/packages/rs-drive/src/state_transition_action/system/mod.rs b/packages/rs-drive/src/state_transition_action/system/mod.rs index debd41e2d57..4bd2d5bde80 100644 --- a/packages/rs-drive/src/state_transition_action/system/mod.rs +++ b/packages/rs-drive/src/state_transition_action/system/mod.rs @@ -9,3 +9,6 @@ pub mod partially_use_asset_lock_action; /// bump address input nonce action pub mod bump_address_input_nonces_action; + +/// penalize shielded pool action +pub mod penalize_shielded_pool_action; diff --git a/packages/rs-drive/src/state_transition_action/system/penalize_shielded_pool_action/mod.rs b/packages/rs-drive/src/state_transition_action/system/penalize_shielded_pool_action/mod.rs new file mode 100644 index 00000000000..a44aa21d4df --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/system/penalize_shielded_pool_action/mod.rs @@ -0,0 +1,40 @@ +/// Penalize the shielded pool when proof verification fails for pool-spending transitions +pub mod v0; + +use derive_more::From; +use v0::PenalizeShieldedPoolActionV0; + +/// Action to deduct a penalty from the shielded pool and record nullifiers as spent +#[derive(Debug, Clone, From)] +pub enum PenalizeShieldedPoolAction { + /// V0 + V0(PenalizeShieldedPoolActionV0), +} + +/// Accessors for PenalizeShieldedPoolAction +pub trait PenalizeShieldedPoolActionAccessorsV0 { + /// The penalty amount to deduct from the pool + fn penalty_amount(&self) -> u64; + /// The nullifiers to record as spent (prevents replay) + fn nullifiers(&self) -> &[[u8; 32]]; + /// Current total pool balance + fn current_total_balance(&self) -> u64; +} + +impl PenalizeShieldedPoolActionAccessorsV0 for PenalizeShieldedPoolAction { + fn penalty_amount(&self) -> u64 { + match self { + PenalizeShieldedPoolAction::V0(v0) => v0.penalty_amount, + } + } + fn nullifiers(&self) -> &[[u8; 32]] { + match self { + PenalizeShieldedPoolAction::V0(v0) => &v0.nullifiers, + } + } + fn current_total_balance(&self) -> u64 { + match self { + PenalizeShieldedPoolAction::V0(v0) => v0.current_total_balance, + } + } +} diff --git a/packages/rs-drive/src/state_transition_action/system/penalize_shielded_pool_action/v0/mod.rs b/packages/rs-drive/src/state_transition_action/system/penalize_shielded_pool_action/v0/mod.rs new file mode 100644 index 00000000000..7497050c7be --- /dev/null +++ b/packages/rs-drive/src/state_transition_action/system/penalize_shielded_pool_action/v0/mod.rs @@ -0,0 +1,12 @@ +use dpp::fee::Credits; + +/// V0 implementation of penalize shielded pool action +#[derive(Debug, Clone)] +pub struct PenalizeShieldedPoolActionV0 { + /// The penalty amount to deduct from the pool + pub penalty_amount: Credits, + /// Nullifiers to record as spent (prevents exact replay of the same invalid proof) + pub nullifiers: Vec<[u8; 32]>, + /// The current total balance of the pool before penalty + pub current_total_balance: Credits, +} diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs b/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs index ba719339216..79d817c2aae 100644 --- a/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs +++ b/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs @@ -3,6 +3,7 @@ use crate::drive::shielded::paths::{ SHIELDED_COMMITMENTS_KEY, SHIELDED_ENCRYPTED_NOTES_KEY, SHIELDED_TOTAL_BALANCE_KEY, }; use crate::drive::Drive; +use crate::error::drive::DriveError; use crate::error::Error; use crate::fees::op::LowLevelDriveOperation; use crate::fees::op::LowLevelDriveOperation::GroveOperation; @@ -74,11 +75,16 @@ impl DriveLowLevelOperationConverter for ShieldedPoolOperationType { } ShieldedPoolOperationType::UpdateTotalBalance { new_total_balance } => { let pool_path = shielded_credit_pool_path_vec(); + let balance_i64 = i64::try_from(new_total_balance).map_err(|_| { + Error::Drive(DriveError::CorruptedDriveState( + "shielded pool total balance exceeds i64::MAX".to_string(), + )) + })?; Ok(vec![GroveOperation( QualifiedGroveDbOp::insert_or_replace_op( pool_path, vec![SHIELDED_TOTAL_BALANCE_KEY], - Element::new_sum_item(new_total_balance as i64), + Element::new_sum_item(balance_i64), ), )]) } diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/mod.rs index 6711040c20e..a3d344778de 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/mod.rs @@ -11,7 +11,7 @@ impl Drive { pub fn verify_shielded_anchors( proof: &[u8], platform_version: &PlatformVersion, - ) -> Result<(RootHash, Vec>), Error> { + ) -> Result<(RootHash, Vec<[u8; 32]>), Error> { match platform_version .drive .methods diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs index 0ca67408b4a..2e08b02d4a0 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs @@ -1,5 +1,6 @@ use crate::drive::shielded::paths::shielded_anchors_credit_pool_path_vec; use crate::drive::Drive; +use crate::error::drive::DriveError; use crate::error::Error; use crate::verify::RootHash; use grovedb::{GroveDb, PathQuery, Query, SizedQuery}; @@ -9,7 +10,7 @@ impl Drive { pub(super) fn verify_shielded_anchors_v0( proof: &[u8], platform_version: &PlatformVersion, - ) -> Result<(RootHash, Vec>), Error> { + ) -> Result<(RootHash, Vec<[u8; 32]>), Error> { let path_query = PathQuery { path: shielded_anchors_credit_pool_path_vec(), query: SizedQuery { @@ -22,10 +23,15 @@ impl Drive { let (root_hash, proved_key_values) = GroveDb::verify_query(proof, &path_query, &platform_version.drive.grove_version)?; - let anchors = proved_key_values - .into_iter() - .map(|(_, key, _)| key) - .collect(); + let mut anchors = Vec::with_capacity(proved_key_values.len()); + for (_, key, _) in proved_key_values { + let anchor: [u8; 32] = key.try_into().map_err(|_: Vec| { + Error::Drive(DriveError::CorruptedElementType( + "anchor key is not 32 bytes", + )) + })?; + anchors.push(anchor); + } Ok((root_hash, anchors)) } diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs index 40039b8c0f8..f80a28d08f3 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs @@ -1,5 +1,6 @@ use crate::drive::shielded::paths::shielded_credit_pool_encrypted_notes_path_vec; use crate::drive::Drive; +use crate::error::drive::DriveError; use crate::error::Error; use crate::verify::RootHash; use grovedb::{Element, GroveDb, PathQuery, Query, SizedQuery}; @@ -39,21 +40,28 @@ impl Drive { let (root_hash, proved_key_values) = GroveDb::verify_query(proof, &path_query, &platform_version.drive.grove_version)?; - let notes = proved_key_values - .into_iter() - .filter_map(|(_, _key, maybe_element)| { - if let Some(Element::Item(value, _)) = maybe_element { + let mut notes = Vec::with_capacity(proved_key_values.len()); + for (_, _key, maybe_element) in proved_key_values { + match maybe_element { + Some(Element::Item(value, _)) => { // Value format: cmx (32 bytes) || encrypted_note (remaining bytes) - if value.len() > 32 { - Some((value[..32].to_vec(), value[32..].to_vec())) - } else { - None + if value.len() <= 32 { + return Err(Error::Drive(DriveError::CorruptedElementType( + "encrypted note value too short: expected more than 32 bytes", + ))); } - } else { - None + notes.push((value[..32].to_vec(), value[32..].to_vec())); } - }) - .collect(); + Some(_) => { + return Err(Error::Drive(DriveError::CorruptedElementType( + "expected Item element for encrypted note, got different element type", + ))); + } + None => { + // Absent elements in proof results are normal (key doesn't exist) + } + } + } Ok((root_hash, notes)) } diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/mod.rs index ed891cdaa26..9c1ec2942ba 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/mod.rs @@ -49,8 +49,10 @@ pub struct DriveStateTransitionActionConvertToHighLevelOperationsMethodVersions pub address_credit_withdrawal_transition: FeatureVersion, pub address_funding_from_asset_lock_transition: FeatureVersion, pub shield_transition: FeatureVersion, + pub shield_from_asset_lock_transition: FeatureVersion, pub shielded_transfer_transition: FeatureVersion, pub unshield_transition: FeatureVersion, + pub shielded_withdrawal_transition: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v1.rs index 73019890ee7..0a9930b133b 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v1.rs @@ -50,7 +50,9 @@ pub const DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V1: DriveStateTransitionMethodV address_credit_withdrawal_transition: 0, address_funding_from_asset_lock_transition: 0, shield_transition: 0, + shield_from_asset_lock_transition: 0, shielded_transfer_transition: 0, unshield_transition: 0, + shielded_withdrawal_transition: 0, }, }; diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v2.rs b/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v2.rs index 4e83f05bea8..7bc67bbbbde 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_state_transition_method_versions/v2.rs @@ -51,7 +51,9 @@ pub const DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V2: DriveStateTransitionMethodV address_credit_withdrawal_transition: 0, address_funding_from_asset_lock_transition: 0, shield_transition: 0, + shield_from_asset_lock_transition: 0, shielded_transfer_transition: 0, unshield_transition: 0, + shielded_withdrawal_transition: 0, }, }; diff --git a/packages/rs-sdk/src/platform/transition/shielded_transfer.rs b/packages/rs-sdk/src/platform/transition/shielded_transfer.rs index 4c46c480f54..d0c2e1cb42e 100644 --- a/packages/rs-sdk/src/platform/transition/shielded_transfer.rs +++ b/packages/rs-sdk/src/platform/transition/shielded_transfer.rs @@ -16,7 +16,7 @@ pub trait TransferShielded { &self, actions: Vec, flags: u8, - value_balance: i64, + value_balance: u64, anchor: [u8; 32], proof: Vec, binding_signature: [u8; 64], @@ -30,7 +30,7 @@ impl TransferShielded for Sdk { &self, actions: Vec, flags: u8, - value_balance: i64, + value_balance: u64, anchor: [u8; 32], proof: Vec, binding_signature: [u8; 64], diff --git a/packages/wasm-dpp/src/shielded/shield_from_asset_lock_transition.rs b/packages/wasm-dpp/src/shielded/shield_from_asset_lock_transition.rs index b17025da105..fbf31560c00 100644 --- a/packages/wasm-dpp/src/shielded/shield_from_asset_lock_transition.rs +++ b/packages/wasm-dpp/src/shielded/shield_from_asset_lock_transition.rs @@ -3,7 +3,7 @@ use wasm_bindgen::prelude::*; use crate::buffer::Buffer; use crate::utils::WithJsError; -use dpp::serialization::PlatformSerializable; +use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; use dpp::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; use dpp::state_transition::{StateTransition, StateTransitionLike}; @@ -122,6 +122,16 @@ impl ShieldFromAssetLockTransitionWasm { Ok(Buffer::from_bytes(&bytes)) } + #[wasm_bindgen(js_name = fromBuffer)] + pub fn from_buffer(buffer: Vec) -> Result { + let state_transition: StateTransition = + PlatformDeserializable::deserialize_from_bytes(&buffer).with_js_error()?; + match state_transition { + StateTransition::ShieldFromAssetLock(st) => Ok(st.into()), + _ => Err(JsValue::from_str("Invalid state transition type")), + } + } + #[wasm_bindgen(js_name = toJSON)] pub fn to_json(&self) -> Result { let json = serde_json::to_value(&self.0).map_err(|e| JsValue::from(e.to_string()))?; diff --git a/packages/wasm-dpp/src/shielded/shield_transition.rs b/packages/wasm-dpp/src/shielded/shield_transition.rs index 6f4c1b7aee1..2e8a968e737 100644 --- a/packages/wasm-dpp/src/shielded/shield_transition.rs +++ b/packages/wasm-dpp/src/shielded/shield_transition.rs @@ -3,7 +3,7 @@ use wasm_bindgen::prelude::*; use crate::buffer::Buffer; use crate::utils::WithJsError; -use dpp::serialization::PlatformSerializable; +use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; use dpp::state_transition::shield_transition::ShieldTransition; use dpp::state_transition::{StateTransition, StateTransitionLike}; @@ -131,6 +131,16 @@ impl ShieldTransitionWasm { Ok(Buffer::from_bytes(&bytes)) } + #[wasm_bindgen(js_name = fromBuffer)] + pub fn from_buffer(buffer: Vec) -> Result { + let state_transition: StateTransition = + PlatformDeserializable::deserialize_from_bytes(&buffer).with_js_error()?; + match state_transition { + StateTransition::Shield(st) => Ok(st.into()), + _ => Err(JsValue::from_str("Invalid state transition type")), + } + } + #[wasm_bindgen(js_name = toJSON)] pub fn to_json(&self) -> Result { let json = serde_json::to_value(&self.0).map_err(|e| JsValue::from(e.to_string()))?; diff --git a/packages/wasm-dpp/src/shielded/shielded_transfer_transition.rs b/packages/wasm-dpp/src/shielded/shielded_transfer_transition.rs index ec155fced0f..87f5ea656f4 100644 --- a/packages/wasm-dpp/src/shielded/shielded_transfer_transition.rs +++ b/packages/wasm-dpp/src/shielded/shielded_transfer_transition.rs @@ -3,7 +3,7 @@ use wasm_bindgen::prelude::*; use crate::buffer::Buffer; use crate::utils::WithJsError; -use dpp::serialization::PlatformSerializable; +use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; use dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition; use dpp::state_transition::{StateTransition, StateTransitionLike}; @@ -104,6 +104,16 @@ impl ShieldedTransferTransitionWasm { Ok(Buffer::from_bytes(&bytes)) } + #[wasm_bindgen(js_name = fromBuffer)] + pub fn from_buffer(buffer: Vec) -> Result { + let state_transition: StateTransition = + PlatformDeserializable::deserialize_from_bytes(&buffer).with_js_error()?; + match state_transition { + StateTransition::ShieldedTransfer(st) => Ok(st.into()), + _ => Err(JsValue::from_str("Invalid state transition type")), + } + } + #[wasm_bindgen(js_name = toJSON)] pub fn to_json(&self) -> Result { let json = serde_json::to_value(&self.0).map_err(|e| JsValue::from(e.to_string()))?; diff --git a/packages/wasm-dpp/src/shielded/shielded_withdrawal_transition.rs b/packages/wasm-dpp/src/shielded/shielded_withdrawal_transition.rs index 2b6821992a6..f2f45559b82 100644 --- a/packages/wasm-dpp/src/shielded/shielded_withdrawal_transition.rs +++ b/packages/wasm-dpp/src/shielded/shielded_withdrawal_transition.rs @@ -3,7 +3,7 @@ use wasm_bindgen::prelude::*; use crate::buffer::Buffer; use crate::utils::WithJsError; -use dpp::serialization::PlatformSerializable; +use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; use dpp::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; use dpp::state_transition::{StateTransition, StateTransitionLike}; @@ -137,6 +137,16 @@ impl ShieldedWithdrawalTransitionWasm { Ok(Buffer::from_bytes(&bytes)) } + #[wasm_bindgen(js_name = fromBuffer)] + pub fn from_buffer(buffer: Vec) -> Result { + let state_transition: StateTransition = + PlatformDeserializable::deserialize_from_bytes(&buffer).with_js_error()?; + match state_transition { + StateTransition::ShieldedWithdrawal(st) => Ok(st.into()), + _ => Err(JsValue::from_str("Invalid state transition type")), + } + } + #[wasm_bindgen(js_name = toJSON)] pub fn to_json(&self) -> Result { let json = serde_json::to_value(&self.0).map_err(|e| JsValue::from(e.to_string()))?; diff --git a/packages/wasm-dpp/src/shielded/unshield_transition.rs b/packages/wasm-dpp/src/shielded/unshield_transition.rs index 12922e5cee0..887508e640b 100644 --- a/packages/wasm-dpp/src/shielded/unshield_transition.rs +++ b/packages/wasm-dpp/src/shielded/unshield_transition.rs @@ -3,7 +3,7 @@ use wasm_bindgen::prelude::*; use crate::buffer::Buffer; use crate::utils::WithJsError; -use dpp::serialization::PlatformSerializable; +use dpp::serialization::{PlatformDeserializable, PlatformSerializable}; use dpp::state_transition::unshield_transition::UnshieldTransition; use dpp::state_transition::{StateTransition, StateTransitionLike}; @@ -120,6 +120,16 @@ impl UnshieldTransitionWasm { Ok(Buffer::from_bytes(&bytes)) } + #[wasm_bindgen(js_name = fromBuffer)] + pub fn from_buffer(buffer: Vec) -> Result { + let state_transition: StateTransition = + PlatformDeserializable::deserialize_from_bytes(&buffer).with_js_error()?; + match state_transition { + StateTransition::Unshield(st) => Ok(st.into()), + _ => Err(JsValue::from_str("Invalid state transition type")), + } + } + #[wasm_bindgen(js_name = toJSON)] pub fn to_json(&self) -> Result { let json = serde_json::to_value(&self.0).map_err(|e| JsValue::from(e.to_string()))?; From 0f5c1fe0ce1c8e9fa67c6cebceb14936153ea3c3 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Thu, 12 Feb 2026 08:01:23 +0000 Subject: [PATCH 15/40] more work --- packages/rs-dpp/src/shielded/mod.rs | 19 + .../v0/mod.rs | 49 ++ .../shielded/shield_transition/v0/mod.rs | 49 ++ .../shielded_transfer_transition/v0/mod.rs | 40 ++ .../shielded_withdrawal_transition/v0/mod.rs | 44 ++ .../shielded/unshield_transition/v0/mod.rs | 45 ++ .../query/shielded/encrypted_notes/v0/mod.rs | 7 +- .../tests/strategy_tests/execution.rs | 2 + .../tests/strategy_tests/strategy.rs | 541 +++++++++++++++++- .../test_cases/shielded_tests.rs | 419 ++++++++++++-- .../verify_state_transitions.rs | 3 +- packages/rs-drive-proof-verifier/src/proof.rs | 15 +- .../shielded/verify_shielded_anchors/mod.rs | 3 +- .../verify_shielded_anchors/v0/mod.rs | 8 +- .../verify_shielded_encrypted_notes/mod.rs | 2 + .../verify_shielded_encrypted_notes/v0/mod.rs | 15 +- .../verify_shielded_nullifiers/mod.rs | 8 +- .../verify_shielded_nullifiers/v0/mod.rs | 19 +- .../verify_shielded_pool_state/mod.rs | 5 +- .../verify_shielded_pool_state/v0/mod.rs | 19 +- .../v0/mod.rs | 2 +- .../rs-sdk/src/platform/transition/shield.rs | 42 +- .../transition/shield_from_asset_lock.rs | 23 +- .../platform/transition/shielded_transfer.rs | 23 +- .../transition/shielded_withdrawal.rs | 23 +- .../src/platform/transition/unshield.rs | 23 +- 26 files changed, 1292 insertions(+), 156 deletions(-) diff --git a/packages/rs-dpp/src/shielded/mod.rs b/packages/rs-dpp/src/shielded/mod.rs index 4b4119c1c50..ef35d1df0d3 100644 --- a/packages/rs-dpp/src/shielded/mod.rs +++ b/packages/rs-dpp/src/shielded/mod.rs @@ -51,6 +51,25 @@ pub struct ShieldedPoolParams { pub checkpoint_id_counter: u64, } +/// Common Orchard bundle parameters shared across all shielded transition types. +/// +/// Groups the fields that every shielded transition carries identically: +/// the serialized actions, bundle flags, commitment tree anchor, Halo 2 proof, +/// and RedPallas binding signature. Using this struct reduces parameter counts +/// in SDK helper functions from 10-12 down to 5-8. +pub struct OrchardBundleParams { + /// The serialized Orchard actions (spends + outputs). + pub actions: Vec, + /// Bundle flags byte. + pub flags: u8, + /// Merkle root of the commitment tree at bundle creation time (32 bytes). + pub anchor: [u8; 32], + /// Halo 2 zero-knowledge proof bytes. + pub proof: Vec, + /// RedPallas binding signature (64 bytes) over the bundle's value balance. + pub binding_signature: [u8; 64], +} + /// A serialized Orchard action extracted from a bundle. /// /// Each Orchard action structurally contains one spend and one output. The spend diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs index f9f9e0d1cde..716468a9bf0 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/mod.rs @@ -56,3 +56,52 @@ pub struct ShieldFromAssetLockTransitionV0 { #[platform_signable(exclude_from_sig_hash)] pub signature: BinaryData, } + +#[cfg(test)] +mod tests { + use super::*; + use crate::identity::state_transition::asset_lock_proof::chain::ChainAssetLockProof; + use crate::serialization::{PlatformDeserializable, PlatformSerializable}; + use dashcore::OutPoint; + use std::fmt::Debug; + + fn test_round_trip( + transition: T, + ) where + ::Error: std::fmt::Debug, + { + let serialized = T::serialize_to_bytes(&transition).expect("expected to serialize"); + let deserialized = + T::deserialize_from_bytes(serialized.as_slice()).expect("expected to deserialize"); + assert_eq!(transition, deserialized); + } + + #[test] + fn test_shield_from_asset_lock_transition_v0_serialization_round_trip() { + let chain_proof = ChainAssetLockProof { + core_chain_locked_height: 100, + out_point: OutPoint::from([11u8; 36]), + }; + + let transition = ShieldFromAssetLockTransitionV0 { + asset_lock_proof: AssetLockProof::Chain(chain_proof), + actions: vec![SerializedAction { + nullifier: [1u8; 32], + rk: [2u8; 32], + cmx: [3u8; 32], + encrypted_note: vec![4u8; 692], + cv_net: [5u8; 32], + spend_auth_sig: [6u8; 64], + }], + flags: 0u8, + value_balance: -1000i64, + anchor: [7u8; 32], + proof: vec![8u8; 100], + binding_signature: [9u8; 64], + user_fee_increase: 0u16, + signature: BinaryData::new(vec![10u8; 65]), + }; + + test_round_trip(transition); + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs index 63463a36c85..1a62c9b5595 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/mod.rs @@ -62,3 +62,52 @@ pub struct ShieldTransitionV0 { #[platform_signable(exclude_from_sig_hash)] pub input_witnesses: Vec, } + +#[cfg(test)] +mod tests { + use super::*; + use crate::serialization::{PlatformDeserializable, PlatformSerializable}; + use std::fmt::Debug; + + fn test_round_trip( + transition: T, + ) where + ::Error: std::fmt::Debug, + { + let serialized = T::serialize_to_bytes(&transition).expect("expected to serialize"); + let deserialized = + T::deserialize_from_bytes(serialized.as_slice()).expect("expected to deserialize"); + assert_eq!(transition, deserialized); + } + + #[test] + fn test_shield_transition_v0_serialization_round_trip() { + let mut inputs = BTreeMap::new(); + let address = PlatformAddress::P2pkh([ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + ]); + inputs.insert(address, (1u32, 1000u64)); // nonce, credits + + let transition = ShieldTransitionV0 { + inputs, + actions: vec![SerializedAction { + nullifier: [1u8; 32], + rk: [2u8; 32], + cmx: [3u8; 32], + encrypted_note: vec![4u8; 692], + cv_net: [5u8; 32], + spend_auth_sig: [6u8; 64], + }], + flags: 0u8, + value_balance: -1000i64, + anchor: [7u8; 32], + proof: vec![8u8; 100], + binding_signature: [9u8; 64], + fee_strategy: vec![], + user_fee_increase: 0u16, + input_witnesses: vec![], + }; + + test_round_trip(transition); + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs index 1a817ac2f60..ea7e1669adc 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs @@ -48,3 +48,43 @@ pub struct ShieldedTransferTransitionV0 { /// Fee multiplier pub user_fee_increase: UserFeeIncrease, } + +#[cfg(test)] +mod tests { + use super::*; + use crate::serialization::{PlatformDeserializable, PlatformSerializable}; + use std::fmt::Debug; + + fn test_round_trip( + transition: T, + ) where + ::Error: std::fmt::Debug, + { + let serialized = T::serialize_to_bytes(&transition).expect("expected to serialize"); + let deserialized = + T::deserialize_from_bytes(serialized.as_slice()).expect("expected to deserialize"); + assert_eq!(transition, deserialized); + } + + #[test] + fn test_shielded_transfer_transition_v0_serialization_round_trip() { + let transition = ShieldedTransferTransitionV0 { + actions: vec![SerializedAction { + nullifier: [1u8; 32], + rk: [2u8; 32], + cmx: [3u8; 32], + encrypted_note: vec![4u8; 692], + cv_net: [5u8; 32], + spend_auth_sig: [6u8; 64], + }], + flags: 0u8, + value_balance: 0u64, + anchor: [7u8; 32], + proof: vec![8u8; 100], + binding_signature: [9u8; 64], + user_fee_increase: 0u16, + }; + + test_round_trip(transition); + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs index afa629898f4..ce9157659d2 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs @@ -58,3 +58,47 @@ pub struct ShieldedWithdrawalTransitionV0 { /// Fee multiplier pub user_fee_increase: UserFeeIncrease, } + +#[cfg(test)] +mod tests { + use super::*; + use crate::serialization::{PlatformDeserializable, PlatformSerializable}; + use std::fmt::Debug; + + fn test_round_trip( + transition: T, + ) where + ::Error: std::fmt::Debug, + { + let serialized = T::serialize_to_bytes(&transition).expect("expected to serialize"); + let deserialized = + T::deserialize_from_bytes(serialized.as_slice()).expect("expected to deserialize"); + assert_eq!(transition, deserialized); + } + + #[test] + fn test_shielded_withdrawal_transition_v0_serialization_round_trip() { + let transition = ShieldedWithdrawalTransitionV0 { + amount: 500u64, + actions: vec![SerializedAction { + nullifier: [1u8; 32], + rk: [2u8; 32], + cmx: [3u8; 32], + encrypted_note: vec![4u8; 692], + cv_net: [5u8; 32], + spend_auth_sig: [6u8; 64], + }], + flags: 0u8, + value_balance: 1000i64, + anchor: [7u8; 32], + proof: vec![8u8; 100], + binding_signature: [9u8; 64], + core_fee_per_byte: 1u32, + pooling: Pooling::Never, + output_script: CoreScript::new_p2pkh([11u8; 20]), + user_fee_increase: 0u16, + }; + + test_round_trip(transition); + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs index ba27a4aadb2..590d6228cb9 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs @@ -53,3 +53,48 @@ pub struct UnshieldTransitionV0 { /// Fee multiplier pub user_fee_increase: UserFeeIncrease, } + +#[cfg(test)] +mod tests { + use super::*; + use crate::address_funds::PlatformAddress; + use crate::serialization::{PlatformDeserializable, PlatformSerializable}; + use std::fmt::Debug; + + fn test_round_trip( + transition: T, + ) where + ::Error: std::fmt::Debug, + { + let serialized = T::serialize_to_bytes(&transition).expect("expected to serialize"); + let deserialized = + T::deserialize_from_bytes(serialized.as_slice()).expect("expected to deserialize"); + assert_eq!(transition, deserialized); + } + + #[test] + fn test_unshield_transition_v0_serialization_round_trip() { + let transition = UnshieldTransitionV0 { + output_address: PlatformAddress::P2pkh([ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + ]), + amount: 500u64, + actions: vec![SerializedAction { + nullifier: [1u8; 32], + rk: [2u8; 32], + cmx: [3u8; 32], + encrypted_note: vec![4u8; 692], + cv_net: [5u8; 32], + spend_auth_sig: [6u8; 64], + }], + flags: 0u8, + value_balance: 1000i64, + anchor: [7u8; 32], + proof: vec![8u8; 100], + binding_signature: [9u8; 64], + user_fee_increase: 0u16, + }; + + test_round_trip(transition); + } +} diff --git a/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs index 0d22d4df4af..234cf187060 100644 --- a/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs @@ -30,11 +30,12 @@ impl Platform { platform_version: &PlatformVersion, ) -> Result, Error> { let max_elements = platform_version.drive_abci.query.max_returned_elements as u32; - let limit = if count == 0 || count > max_elements { - max_elements as u16 + let effective = if count == 0 || count > max_elements { + max_elements } else { - count as u16 + count }; + let limit = effective.min(u16::MAX as u32) as u16; let query = if start_index == 0 { Query::new_range_full() diff --git a/packages/rs-drive-abci/tests/strategy_tests/execution.rs b/packages/rs-drive-abci/tests/strategy_tests/execution.rs index b8c31197500..ea10c6eb6a1 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/execution.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/execution.rs @@ -975,6 +975,7 @@ pub(crate) fn continue_chain_for_strategy( let mut state_transitions_per_block = BTreeMap::new(); let mut state_transition_results_per_block = BTreeMap::new(); + let mut shielded_state: Option = None; for block_height in block_start..(block_start + block_count) { let state = platform.state.load(); @@ -1023,6 +1024,7 @@ pub(crate) fn continue_chain_for_strategy( &mut signer, &mut rng, &instant_lock_quorums, + &mut shielded_state, ); state_transitions_per_block.insert(block_height, state_transitions.clone()); diff --git a/packages/rs-drive-abci/tests/strategy_tests/strategy.rs b/packages/rs-drive-abci/tests/strategy_tests/strategy.rs index c9d7a6bc556..e6aa03a5a69 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/strategy.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/strategy.rs @@ -5,13 +5,24 @@ use dpp::dashcore::{Network, PrivateKey}; use dpp::dashcore::{ProTxHash, QuorumHash}; use dpp::shielded::{compute_platform_sighash, SerializedAction}; use dpp::state_transition::identity_topup_transition::methods::IdentityTopUpTransitionMethodsV0; +use dpp::state_transition::shield_from_asset_lock_transition::methods::ShieldFromAssetLockTransitionMethodsV0; +use dpp::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; use dpp::state_transition::shield_transition::methods::ShieldTransitionMethodsV0; use dpp::state_transition::shield_transition::ShieldTransition; +use dpp::state_transition::shielded_transfer_transition::methods::ShieldedTransferTransitionMethodsV0; +use dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition; +use dpp::state_transition::shielded_withdrawal_transition::methods::ShieldedWithdrawalTransitionMethodsV0; +use dpp::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; +use dpp::state_transition::unshield_transition::methods::UnshieldTransitionMethodsV0; +use dpp::state_transition::unshield_transition::UnshieldTransition; use dpp::ProtocolError; use grovedb_commitment_tree::{ - Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, Flags as OrchardFlags, - FullViewingKey, NoteValue, ProvingKey, Scope, SpendingKey, + new_memory_store, Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + CommitmentTree, ExtractedNoteCommitment, Flags as OrchardFlags, FullViewingKey, + MemoryCommitmentStore, MerklePath, Note, NoteValue, Position, ProvingKey, Retention, Scope, + SpendAuthorizingKey, SpendingKey, }; +use orchard::note::RandomSeed; use dpp::dashcore::secp256k1::SecretKey; use dpp::data_contract::document_type::random_document::CreateRandomDocument; @@ -134,6 +145,105 @@ fn get_proving_key() -> &'static ProvingKey { TEST_PROVING_KEY.get_or_init(ProvingKey::build) } +/// Deterministic Orchard spending key seed used throughout all shielded strategy tests. +const TEST_SK_BYTES: [u8; 32] = [0u8; 32]; + +/// Tracks shielded pool state locally for strategy tests. +/// +/// After each block, successful Shield/ShieldFromAssetLock transitions append their +/// output note commitments to this tree. Spend-based transitions (ShieldedTransfer, +/// Unshield, ShieldedWithdrawal) then pick notes from here to build spend bundles +/// with valid Merkle witnesses. +pub struct ShieldedState { + /// Local commitment tree mirroring the on-chain tree. + pub tree: CommitmentTree, + /// Spendable notes: (Note, Position in commitment tree). + /// Notes are removed once spent. + pub spendable_notes: Vec<(Note, Position)>, + /// Monotonically increasing checkpoint ID. + pub checkpoint_counter: u32, + /// Cached spending key derived from TEST_SK_BYTES. + #[allow(dead_code)] + pub sk: SpendingKey, + /// Cached full viewing key derived from sk. + pub fvk: FullViewingKey, + /// Cached spend authorizing key for signing spend bundles. + pub ask: SpendAuthorizingKey, + /// Counter for generating unique rho values for notes. + pub rho_counter: u64, +} + +impl ShieldedState { + pub fn new() -> Self { + let sk = SpendingKey::from_bytes(TEST_SK_BYTES).unwrap(); + let fvk = FullViewingKey::from(&sk); + let ask = SpendAuthorizingKey::from(&sk); + Self { + tree: CommitmentTree::new(new_memory_store(), 1000), + spendable_notes: Vec::new(), + checkpoint_counter: 0, + sk, + fvk, + ask, + rho_counter: 1, // Start at 1 to avoid zero rho + } + } + + /// Record a note that was output by a successful shield transition. + /// + /// `value` is the shielded amount in credits. + /// The note is reconstructed deterministically using the test spending key + /// and a unique rho derived from `rho_counter`. + pub fn record_shielded_note(&mut self, value: u64) { + let recipient = self.fvk.address_at(0u32, Scope::External); + + // Create a deterministic rho from the counter + let mut rho_bytes = [0u8; 32]; + rho_bytes[..8].copy_from_slice(&self.rho_counter.to_le_bytes()); + self.rho_counter += 1; + + let rho = orchard::note::Rho::from_bytes(&rho_bytes).unwrap(); + let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); + let note = Note::from_parts(recipient, NoteValue::from_raw(value), rho, rseed).unwrap(); + + // Append to commitment tree + let cmx = ExtractedNoteCommitment::from(note.commitment()); + self.tree.append(cmx, Retention::Marked).unwrap(); + + let position = self.tree.max_leaf_position().unwrap().unwrap(); + self.spendable_notes.push((note, position)); + + tracing::debug!( + value, + position = u64::from(position), + "Recorded spendable shielded note" + ); + } + + /// Create a checkpoint after processing a block. + pub fn checkpoint(&mut self) { + self.tree.checkpoint(self.checkpoint_counter).unwrap(); + self.checkpoint_counter += 1; + } + + /// Take a spendable note (removes it from the pool). + /// Returns (Note, MerklePath, Anchor) if a note is available. + pub fn take_spendable_note(&mut self) -> Option<(Note, MerklePath, Anchor)> { + if self.spendable_notes.is_empty() { + return None; + } + let (note, position) = self.spendable_notes.remove(0); + let merkle_path = self.tree.orchard_witness(position).ok()??; + let anchor = self.tree.anchor().ok()?; + Some((note, merkle_path, anchor)) + } + + /// Check if any spendable notes exist. + pub fn has_spendable_notes(&self) -> bool { + !self.spendable_notes.is_empty() + } +} + /// Decompose an authorized Orchard bundle into platform serialization fields. fn serialize_authorized_bundle( bundle: &Bundle, @@ -660,6 +770,7 @@ impl NetworkStrategy { instant_lock_quorums: &Quorums, rng: &mut StdRng, platform_version: &PlatformVersion, + shielded_state: &mut Option, ) -> (Vec, Vec) { let mut maybe_state = None; let mut operations = vec![]; @@ -1890,6 +2001,88 @@ impl NetworkStrategy { ) else { break; }; + // Record the shielded note for potential future spends. + // The value is |-value_balance| since value_balance is negative + // for shield transitions (money flowing into the pool). + if let StateTransition::Shield(ref shield) = state_transition { + let shielded_value = match shield { + ShieldTransition::V0(v0) => (-v0.value_balance) as u64, + }; + let state = shielded_state.get_or_insert_with(ShieldedState::new); + state.record_shielded_note(shielded_value); + state.checkpoint(); + } + operations.push(state_transition); + } + } + OperationType::ShieldFromAssetLock(amount_range) => { + for _i in 0..count { + let Some(state_transition) = self + .create_shield_from_asset_lock_transition( + amount_range, + rng, + instant_lock_quorums, + &platform.config, + platform_version, + ) + else { + break; + }; + // Record the shielded note for potential future spends + if let StateTransition::ShieldFromAssetLock(ref shield) = + state_transition + { + let shielded_value = match shield { + ShieldFromAssetLockTransition::V0(v0) => { + (-v0.value_balance) as u64 + } + }; + let state = shielded_state.get_or_insert_with(ShieldedState::new); + state.record_shielded_note(shielded_value); + state.checkpoint(); + } + operations.push(state_transition); + } + } + OperationType::ShieldedTransfer(amount_range) => { + for _i in 0..count { + let Some(state_transition) = self.create_shielded_transfer_transition( + amount_range, + rng, + shielded_state, + platform_version, + ) else { + break; + }; + operations.push(state_transition); + } + } + OperationType::Unshield(amount_range) => { + for _i in 0..count { + let Some(state_transition) = self.create_unshield_transition( + current_addresses_with_balance, + amount_range, + rng, + shielded_state, + platform_version, + ) else { + break; + }; + operations.push(state_transition); + } + } + OperationType::ShieldedWithdrawal(amount_range) => { + for _i in 0..count { + let Some(state_transition) = self + .create_shielded_withdrawal_transition( + amount_range, + rng, + shielded_state, + platform_version, + ) + else { + break; + }; operations.push(state_transition); } } @@ -1913,6 +2106,7 @@ impl NetworkStrategy { signer: &mut SimpleSigner, rng: &mut StdRng, instant_lock_quorums: &Quorums, + shielded_state: &mut Option, ) -> (Vec, Vec) { let mut finalize_block_operations = vec![]; let platform_state = platform.state.load(); @@ -1967,6 +2161,7 @@ impl NetworkStrategy { instant_lock_quorums, rng, platform_version, + shielded_state, ); finalize_block_operations.append(&mut add_to_finalize_block_operations); state_transitions.append(&mut operation_based_state_transitions); @@ -2604,6 +2799,348 @@ impl NetworkStrategy { Some(shield_transition) } + + /// Build a ShieldFromAssetLock state transition (core asset lock -> shielded pool). + /// + /// Like Shield, this is output-only (no spends). The funds come from a core + /// asset lock proof rather than platform address inputs. + fn create_shield_from_asset_lock_transition( + &mut self, + amount_range: &AmountRange, + rng: &mut StdRng, + instant_lock_quorums: &Quorums, + platform_config: &PlatformConfig, + platform_version: &PlatformVersion, + ) -> Option { + // 1. Create asset lock proof + let (asset_lock_proof, asset_lock_private_key, funded_amount) = self + .create_asset_lock_proof_with_amount( + rng, + amount_range, + instant_lock_quorums, + platform_config, + platform_version, + ); + + tracing::debug!(funded_amount, "Preparing shield from asset lock transition"); + + // 2. Create deterministic Orchard recipient + let sk = SpendingKey::from_bytes(TEST_SK_BYTES).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + + // 3. Build output-only Orchard bundle (same as Shield) + let anchor = Anchor::empty_tree(); + let mut builder = Builder::new( + BundleType::Transactional { + flags: OrchardFlags::SPENDS_DISABLED, + bundle_required: false, + }, + anchor, + ); + + builder + .add_output( + None, + recipient, + NoteValue::from_raw(funded_amount), + [0u8; 512], + ) + .expect("expected to add output"); + + // 4. Build -> prove -> sign + let pk = get_proving_key(); + let mut bundle_rng = rand::rngs::OsRng; + let (unauthorized, _) = builder + .build::(&mut bundle_rng) + .expect("expected to build bundle") + .expect("expected bundle to be present"); + + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &[]); + let proven = unauthorized + .create_proof(pk, &mut bundle_rng) + .expect("expected to create proof"); + let bundle = proven + .apply_signatures(bundle_rng, sighash, &[]) + .expect("expected to apply signatures"); + + // 5. Decompose bundle + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + + // 6. Build ShieldFromAssetLockTransition + let transition = ShieldFromAssetLockTransition::try_from_asset_lock_with_bundle( + asset_lock_proof, + asset_lock_private_key.as_slice(), + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + 0, + platform_version, + ) + .expect("expected to create shield from asset lock transition"); + + tracing::debug!("ShieldFromAssetLock transition successfully built and signed"); + + Some(transition) + } + + /// Build a ShieldedTransfer state transition (shielded pool -> shielded pool). + /// + /// Spends an existing note and creates a new note with the same value. + /// Requires notes from prior Shield or ShieldFromAssetLock transitions. + fn create_shielded_transfer_transition( + &mut self, + _amount_range: &AmountRange, + _rng: &mut StdRng, + shielded_state: &mut Option, + platform_version: &PlatformVersion, + ) -> Option { + let state = shielded_state.as_mut()?; + if !state.has_spendable_notes() { + tracing::debug!("No spendable notes available for shielded transfer"); + return None; + } + + let (note, merkle_path, anchor) = state.take_spendable_note()?; + let note_value = note.value().inner(); + + tracing::debug!(note_value, "Building shielded transfer bundle"); + + let fvk = state.fvk.clone(); + let ask = state.ask.clone(); + let recipient = fvk.address_at(0u32, Scope::External); + + // Build bundle: spend note -> output same value (value_balance = 0) + let mut builder = Builder::new(BundleType::DEFAULT, anchor); + builder + .add_spend(fvk, note, merkle_path) + .expect("expected to add spend"); + builder + .add_output(None, recipient, NoteValue::from_raw(note_value), [0u8; 512]) + .expect("expected to add output"); + + let pk = get_proving_key(); + let mut bundle_rng = rand::rngs::OsRng; + let (unauthorized, _) = builder + .build::(&mut bundle_rng) + .expect("expected to build bundle") + .expect("expected bundle to be present"); + + // Shielded transfer has no extra_data in sighash + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &[]); + let proven = unauthorized + .create_proof(pk, &mut bundle_rng) + .expect("expected to create proof"); + let bundle = proven + .apply_signatures(bundle_rng, sighash, &[ask]) + .expect("expected to apply signatures"); + + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + + // value_balance should be 0 (all value stays in pool) + // Cast i64 to u64 for the ShieldedTransferTransition API + let transition = ShieldedTransferTransition::try_from_bundle( + actions, + flags, + value_balance as u64, + anchor_bytes, + proof_bytes, + binding_sig, + 0, + platform_version, + ) + .expect("expected to create shielded transfer transition"); + + tracing::debug!("ShieldedTransfer transition successfully built"); + + Some(transition) + } + + /// Build an Unshield state transition (shielded pool -> platform address). + /// + /// Spends an existing note and sends the value to a platform address. + /// Requires notes from prior Shield or ShieldFromAssetLock transitions. + fn create_unshield_transition( + &mut self, + _current_addresses_with_balance: &mut AddressesWithBalance, + _amount_range: &AmountRange, + _rng: &mut StdRng, + shielded_state: &mut Option, + platform_version: &PlatformVersion, + ) -> Option { + let state = shielded_state.as_mut()?; + if !state.has_spendable_notes() { + tracing::debug!("No spendable notes available for unshield"); + return None; + } + + let (note, merkle_path, anchor) = state.take_spendable_note()?; + let note_value = note.value().inner(); + + tracing::debug!(note_value, "Building unshield bundle"); + + let fvk = state.fvk.clone(); + let ask = state.ask.clone(); + let recipient = fvk.address_at(0u32, Scope::External); + + // Spend full note, output half back to pool, unshield the other half + let unshield_amount = note_value / 2; + let change_amount = note_value - unshield_amount; + + // Build bundle: spend note -> output change (value_balance = unshield_amount) + let mut builder = Builder::new(BundleType::DEFAULT, anchor); + builder + .add_spend(fvk, note, merkle_path) + .expect("expected to add spend"); + builder + .add_output( + None, + recipient, + NoteValue::from_raw(change_amount), + [0u8; 512], + ) + .expect("expected to add output"); + + let pk = get_proving_key(); + let mut bundle_rng = rand::rngs::OsRng; + let (unauthorized, _) = builder + .build::(&mut bundle_rng) + .expect("expected to build bundle") + .expect("expected bundle to be present"); + + // Unshield extra_data = output_address.to_bytes() || amount.to_le_bytes() + let output_address = PlatformAddress::P2pkh([42u8; 20]); + let amount = unshield_amount; + let mut extra_sighash_data = output_address.to_bytes(); + extra_sighash_data.extend_from_slice(&amount.to_le_bytes()); + + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &extra_sighash_data); + let proven = unauthorized + .create_proof(pk, &mut bundle_rng) + .expect("expected to create proof"); + let bundle = proven + .apply_signatures(bundle_rng, sighash, &[ask]) + .expect("expected to apply signatures"); + + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + + let transition = UnshieldTransition::try_from_bundle( + output_address, + amount, + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + 0, + platform_version, + ) + .expect("expected to create unshield transition"); + + tracing::debug!(amount, "Unshield transition successfully built"); + + Some(transition) + } + + /// Build a ShieldedWithdrawal state transition (shielded pool -> core L1 address). + /// + /// Spends an existing note and withdraws the value to a core script. + /// Requires notes from prior Shield or ShieldFromAssetLock transitions. + fn create_shielded_withdrawal_transition( + &mut self, + _amount_range: &AmountRange, + _rng: &mut StdRng, + shielded_state: &mut Option, + platform_version: &PlatformVersion, + ) -> Option { + let state = shielded_state.as_mut()?; + if !state.has_spendable_notes() { + tracing::debug!("No spendable notes available for shielded withdrawal"); + return None; + } + + let (note, merkle_path, anchor) = state.take_spendable_note()?; + let note_value = note.value().inner(); + + tracing::debug!(note_value, "Building shielded withdrawal bundle"); + + let fvk = state.fvk.clone(); + let ask = state.ask.clone(); + let recipient = fvk.address_at(0u32, Scope::External); + + // Spend full note, output half back to pool, withdraw the other half + let withdrawal_amount = note_value / 2; + let change_amount = note_value - withdrawal_amount; + + // Build bundle: spend note -> output change (value_balance = withdrawal_amount) + let mut builder = Builder::new(BundleType::DEFAULT, anchor); + builder + .add_spend(fvk, note, merkle_path) + .expect("expected to add spend"); + builder + .add_output( + None, + recipient, + NoteValue::from_raw(change_amount), + [0u8; 512], + ) + .expect("expected to add output"); + + let pk = get_proving_key(); + let mut bundle_rng = rand::rngs::OsRng; + let (unauthorized, _) = builder + .build::(&mut bundle_rng) + .expect("expected to build bundle") + .expect("expected bundle to be present"); + + // ShieldedWithdrawal extra_data = output_script.as_bytes() || amount.to_le_bytes() + let output_script = CoreScript::new_p2pkh([7u8; 20]); + let amount = withdrawal_amount; + let mut extra_sighash_data = output_script.as_bytes().to_vec(); + extra_sighash_data.extend_from_slice(&amount.to_le_bytes()); + + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &extra_sighash_data); + let proven = unauthorized + .create_proof(pk, &mut bundle_rng) + .expect("expected to create proof"); + let bundle = proven + .apply_signatures(bundle_rng, sighash, &[ask]) + .expect("expected to apply signatures"); + + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + + let transition = ShieldedWithdrawalTransition::try_from_bundle( + amount, + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + 1, // core_fee_per_byte + Pooling::Never, + output_script, + 0, + platform_version, + ) + .expect("expected to create shielded withdrawal transition"); + + tracing::debug!(amount, "ShieldedWithdrawal transition successfully built"); + + Some(transition) + } } pub enum StrategyRandomness { diff --git a/packages/rs-drive-abci/tests/strategy_tests/test_cases/shielded_tests.rs b/packages/rs-drive-abci/tests/strategy_tests/test_cases/shielded_tests.rs index eafef099e7e..2bb1f7475dd 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/test_cases/shielded_tests.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/test_cases/shielded_tests.rs @@ -15,44 +15,28 @@ mod tests { use strategy_tests::operations::{Operation, OperationType}; use strategy_tests::{IdentityInsertInfo, StartAddresses, StartIdentities, Strategy}; - /// Strategy test that funds addresses via asset locks and then shields funds - /// into the shielded credit pool through the multi-block execution pipeline. - /// - /// This exercises the full Shield transition lifecycle: - /// 1. Orchard bundle building (output-only, no spends) - /// 2. Halo 2 ZK proof generation (via cached ProvingKey) - /// 3. Address input witness signing - /// 4. Platform validation (structure + state + ZK proof verification) - /// 5. Storage operations (commitment tree, encrypted notes, pool balance) - /// - /// Note: The first run takes ~30s to build the ProvingKey (cached via OnceLock). - #[test] - fn run_chain_shield_transitions() { - drive_abci::logging::init_for_tests(LogLevel::Debug); + /// Helper: create a standard platform config for shielded tests. + fn shielded_test_config() -> PlatformConfig { + PlatformConfig { + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), + execution: ExecutionConfig { + verify_sum_trees: true, + ..Default::default() + }, + block_spacing_ms: 3000, + testing_configs: PlatformTestConfig::default_minimal_verifications(), + ..Default::default() + } + } - let strategy = NetworkStrategy { + /// Helper: create a base NetworkStrategy with common settings for shielded tests. + fn shielded_base_strategy(operations: Vec) -> NetworkStrategy { + NetworkStrategy { strategy: Strategy { start_contracts: vec![], - operations: vec![ - // Fund addresses first (every block, 2-3 asset locks of 20 DASH each) - Operation { - op_type: OperationType::AddressFundingFromCoreAssetLock( - dash_to_credits!(20)..=dash_to_credits!(20), - ), - frequency: Frequency { - times_per_block_range: 2..4, - chance_per_block: None, - }, - }, - // Shield funds from funded addresses (1 per block, 1-5 DASH) - Operation { - op_type: OperationType::Shield(dash_to_credits!(1)..=dash_to_credits!(5)), - frequency: Frequency { - times_per_block_range: 1..2, - chance_per_block: None, - }, - }, - ], + operations, start_identities: StartIdentities::default(), start_addresses: StartAddresses::default(), identity_inserts: IdentityInsertInfo::default(), @@ -64,29 +48,53 @@ mod tests { 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, - // Shield proof verification is implemented but we keep this simple verify_state_transition_results: false, sign_instant_locks: true, ..Default::default() - }; + } + } - let config = PlatformConfig { - validator_set: ValidatorSetConfig::default_100_67(), - chain_lock: ChainLockConfig::default_100_67(), - instant_lock: InstantLockConfig::default_100_67(), - execution: ExecutionConfig { - verify_sum_trees: true, - ..Default::default() + /// Strategy test that funds addresses via asset locks and then shields funds + /// into the shielded credit pool through the multi-block execution pipeline. + /// + /// This exercises the full Shield transition lifecycle: + /// 1. Orchard bundle building (output-only, no spends) + /// 2. Halo 2 ZK proof generation (via cached ProvingKey) + /// 3. Address input witness signing + /// 4. Platform validation (structure + state + ZK proof verification) + /// 5. Storage operations (commitment tree, encrypted notes, pool balance) + /// + /// Note: The first run takes ~30s to build the ProvingKey (cached via OnceLock). + #[test] + fn run_chain_shield_transitions() { + drive_abci::logging::init_for_tests(LogLevel::Debug); + + let strategy = shielded_base_strategy(vec![ + // Fund addresses first (every block, 2-3 asset locks of 20 DASH each) + Operation { + op_type: OperationType::AddressFundingFromCoreAssetLock( + dash_to_credits!(20)..=dash_to_credits!(20), + ), + frequency: Frequency { + times_per_block_range: 2..4, + chance_per_block: None, + }, }, - block_spacing_ms: 3000, - testing_configs: PlatformTestConfig::default_minimal_verifications(), - ..Default::default() - }; + // Shield funds from funded addresses (1 per block, 1-5 DASH) + Operation { + op_type: OperationType::Shield(dash_to_credits!(1)..=dash_to_credits!(5)), + frequency: Frequency { + times_per_block_range: 1..2, + chance_per_block: None, + }, + }, + ]); + + let config = shielded_test_config(); let mut platform = TestPlatformBuilder::new() .with_config(config.clone()) @@ -110,4 +118,317 @@ mod tests { tracing::info!(shield_count, "Shield strategy test completed successfully"); } + + /// Strategy test that shields funds directly from core asset lock proofs + /// into the shielded credit pool. + /// + /// This exercises the ShieldFromAssetLock transition lifecycle: + /// 1. Asset lock proof creation and signing + /// 2. Orchard bundle building (output-only, no spends) + /// 3. Halo 2 ZK proof generation + /// 4. ECDSA signing of the transition with asset lock private key + /// 5. Platform validation and storage + #[test] + fn run_chain_shield_from_asset_lock_transitions() { + drive_abci::logging::init_for_tests(LogLevel::Debug); + + let strategy = shielded_base_strategy(vec![ + // Shield directly from asset locks (1-2 per block, 5-10 DASH each) + Operation { + op_type: OperationType::ShieldFromAssetLock( + dash_to_credits!(5)..=dash_to_credits!(10), + ), + frequency: Frequency { + times_per_block_range: 1..3, + chance_per_block: None, + }, + }, + ]); + + let config = shielded_test_config(); + + let mut platform = TestPlatformBuilder::new() + .with_config(config.clone()) + .build_with_mock_rpc(); + + let outcome = + run_chain_for_strategy(&mut platform, 5, strategy, config, 15, &mut None, &mut None); + + let shield_from_asset_lock_count = outcome + .state_transition_results_per_block + .values() + .flat_map(|results| results.iter()) + .filter(|(st, result)| { + matches!(st, StateTransition::ShieldFromAssetLock(_)) && result.code == 0 + }) + .count(); + + assert!( + shield_from_asset_lock_count > 0, + "expected at least one successful ShieldFromAssetLock transition across 5 blocks" + ); + + tracing::info!( + shield_from_asset_lock_count, + "ShieldFromAssetLock strategy test completed successfully" + ); + } + + /// Strategy test that first shields funds, then transfers within the shielded pool. + /// + /// This exercises the ShieldedTransfer transition lifecycle: + /// 1. Shield funds first to create spendable notes + /// 2. Build spend bundles consuming previous notes + /// 3. Halo 2 ZK proof generation for spend+output + /// 4. RedPallas spend authorization signing + /// 5. Platform validation (anchor, nullifiers, ZK proof) + /// + /// The first few blocks only shield (to create spendable notes). The + /// ShieldedTransfer operations only succeed once notes become available + /// in the tracked shielded state. + #[test] + fn run_chain_shielded_transfer_transitions() { + drive_abci::logging::init_for_tests(LogLevel::Debug); + + let strategy = shielded_base_strategy(vec![ + // Fund addresses first + Operation { + op_type: OperationType::AddressFundingFromCoreAssetLock( + dash_to_credits!(20)..=dash_to_credits!(20), + ), + frequency: Frequency { + times_per_block_range: 2..4, + chance_per_block: None, + }, + }, + // Shield funds to create spendable notes + Operation { + op_type: OperationType::Shield(dash_to_credits!(5)..=dash_to_credits!(10)), + frequency: Frequency { + times_per_block_range: 1..3, + chance_per_block: None, + }, + }, + // Transfer within shielded pool (will only work once notes are available) + Operation { + op_type: OperationType::ShieldedTransfer(dash_to_credits!(1)..=dash_to_credits!(5)), + frequency: Frequency { + times_per_block_range: 1..2, + chance_per_block: None, + }, + }, + ]); + + let config = shielded_test_config(); + + let mut platform = TestPlatformBuilder::new() + .with_config(config.clone()) + .build_with_mock_rpc(); + + let outcome = + run_chain_for_strategy(&mut platform, 8, strategy, config, 15, &mut None, &mut None); + + // Count all shielded transitions + let shield_count = outcome + .state_transition_results_per_block + .values() + .flat_map(|results| results.iter()) + .filter(|(st, result)| matches!(st, StateTransition::Shield(_)) && result.code == 0) + .count(); + + let transfer_count = outcome + .state_transition_results_per_block + .values() + .flat_map(|results| results.iter()) + .filter(|(st, result)| { + matches!(st, StateTransition::ShieldedTransfer(_)) && result.code == 0 + }) + .count(); + + tracing::info!( + shield_count, + transfer_count, + "ShieldedTransfer strategy test completed" + ); + + assert!( + shield_count > 0, + "expected at least one successful Shield transition" + ); + + // ShieldedTransfer may or may not succeed depending on timing (notes need to be + // available and anchors need to be in state). We just verify the test runs + // without panicking. If transfers succeed, that's a bonus. + tracing::info!( + transfer_count, + "ShieldedTransfer transitions that succeeded" + ); + } + + /// Strategy test that first shields funds, then unshields to platform addresses. + /// + /// This exercises the Unshield transition lifecycle: + /// 1. Shield funds first to create spendable notes + /// 2. Build spend bundles with extra_data binding output_address + amount + /// 3. Halo 2 ZK proof generation for spend+output + /// 4. RedPallas spend authorization signing + /// 5. Platform validation (anchor, nullifiers, ZK proof, pool balance) + #[test] + fn run_chain_unshield_transitions() { + drive_abci::logging::init_for_tests(LogLevel::Debug); + + let strategy = shielded_base_strategy(vec![ + // Fund addresses first + Operation { + op_type: OperationType::AddressFundingFromCoreAssetLock( + dash_to_credits!(20)..=dash_to_credits!(20), + ), + frequency: Frequency { + times_per_block_range: 2..4, + chance_per_block: None, + }, + }, + // Shield funds to create spendable notes + Operation { + op_type: OperationType::Shield(dash_to_credits!(5)..=dash_to_credits!(10)), + frequency: Frequency { + times_per_block_range: 1..3, + chance_per_block: None, + }, + }, + // Unshield from pool to platform address + Operation { + op_type: OperationType::Unshield(dash_to_credits!(1)..=dash_to_credits!(5)), + frequency: Frequency { + times_per_block_range: 1..2, + chance_per_block: None, + }, + }, + ]); + + let config = shielded_test_config(); + + let mut platform = TestPlatformBuilder::new() + .with_config(config.clone()) + .build_with_mock_rpc(); + + let outcome = + run_chain_for_strategy(&mut platform, 8, strategy, config, 15, &mut None, &mut None); + + let shield_count = outcome + .state_transition_results_per_block + .values() + .flat_map(|results| results.iter()) + .filter(|(st, result)| matches!(st, StateTransition::Shield(_)) && result.code == 0) + .count(); + + let unshield_count = outcome + .state_transition_results_per_block + .values() + .flat_map(|results| results.iter()) + .filter(|(st, result)| matches!(st, StateTransition::Unshield(_)) && result.code == 0) + .count(); + + tracing::info!( + shield_count, + unshield_count, + "Unshield strategy test completed" + ); + + assert!( + shield_count > 0, + "expected at least one successful Shield transition" + ); + + // Like ShieldedTransfer, unshield may not succeed on every run due to + // timing constraints (notes + anchors in state). + tracing::info!(unshield_count, "Unshield transitions that succeeded"); + } + + /// Strategy test that first shields funds, then withdraws to a core (L1) address. + /// + /// This exercises the ShieldedWithdrawal transition lifecycle: + /// 1. Shield funds first to create spendable notes + /// 2. Build spend bundles with extra_data binding output_script + amount + /// 3. Halo 2 ZK proof generation for spend+output + /// 4. RedPallas spend authorization signing + /// 5. Platform validation (anchor, nullifiers, ZK proof, pool balance, withdrawal queue) + #[test] + fn run_chain_shielded_withdrawal_transitions() { + drive_abci::logging::init_for_tests(LogLevel::Debug); + + let strategy = shielded_base_strategy(vec![ + // Fund addresses first + Operation { + op_type: OperationType::AddressFundingFromCoreAssetLock( + dash_to_credits!(20)..=dash_to_credits!(20), + ), + frequency: Frequency { + times_per_block_range: 2..4, + chance_per_block: None, + }, + }, + // Shield funds to create spendable notes + Operation { + op_type: OperationType::Shield(dash_to_credits!(5)..=dash_to_credits!(10)), + frequency: Frequency { + times_per_block_range: 1..3, + chance_per_block: None, + }, + }, + // Withdraw from pool to core address + Operation { + op_type: OperationType::ShieldedWithdrawal( + dash_to_credits!(1)..=dash_to_credits!(5), + ), + frequency: Frequency { + times_per_block_range: 1..2, + chance_per_block: None, + }, + }, + ]); + + let config = shielded_test_config(); + + let mut platform = TestPlatformBuilder::new() + .with_config(config.clone()) + .build_with_mock_rpc(); + + let outcome = + run_chain_for_strategy(&mut platform, 8, strategy, config, 15, &mut None, &mut None); + + let shield_count = outcome + .state_transition_results_per_block + .values() + .flat_map(|results| results.iter()) + .filter(|(st, result)| matches!(st, StateTransition::Shield(_)) && result.code == 0) + .count(); + + let withdrawal_count = outcome + .state_transition_results_per_block + .values() + .flat_map(|results| results.iter()) + .filter(|(st, result)| { + matches!(st, StateTransition::ShieldedWithdrawal(_)) && result.code == 0 + }) + .count(); + + tracing::info!( + shield_count, + withdrawal_count, + "ShieldedWithdrawal strategy test completed" + ); + + assert!( + shield_count > 0, + "expected at least one successful Shield transition" + ); + + // Like the other spend-based transitions, withdrawal may not succeed on + // every run due to timing constraints. + tracing::info!( + withdrawal_count, + "ShieldedWithdrawal transitions that succeeded" + ); + } } diff --git a/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs b/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs index d894e6ec1cf..746c4979bb7 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/verify_state_transitions.rs @@ -1449,7 +1449,8 @@ pub(crate) fn verify_state_transitions_were_or_were_not_executed( | StateTransitionAction::ShieldedTransferAction(_) | StateTransitionAction::UnshieldAction(_) | StateTransitionAction::ShieldFromAssetLockAction(_) - | StateTransitionAction::ShieldedWithdrawalAction(_) => { + | StateTransitionAction::ShieldedWithdrawalAction(_) + | StateTransitionAction::PenalizeShieldedPoolAction(_) => { // Shielded transitions don't support proof verification yet } } diff --git a/packages/rs-drive-proof-verifier/src/proof.rs b/packages/rs-drive-proof-verifier/src/proof.rs index e930c2e23d2..48829762e51 100644 --- a/packages/rs-drive-proof-verifier/src/proof.rs +++ b/packages/rs-drive-proof-verifier/src/proof.rs @@ -2300,7 +2300,7 @@ impl FromProof for ShieldedPoolState { let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?; let (root_hash, maybe_balance) = - Drive::verify_shielded_pool_state(&proof.grovedb_proof, platform_version) + Drive::verify_shielded_pool_state(&proof.grovedb_proof, false, platform_version) .map_drive_error(proof, mtd)?; verify_tenderdash_proof(proof, mtd, &root_hash, provider)?; @@ -2332,7 +2332,7 @@ impl FromProof for ShieldedAnchors { let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?; let (root_hash, anchors) = - Drive::verify_shielded_anchors(&proof.grovedb_proof, platform_version) + Drive::verify_shielded_anchors(&proof.grovedb_proof, false, platform_version) .map_drive_error(proof, mtd)?; verify_tenderdash_proof(proof, mtd, &root_hash, provider)?; @@ -2379,6 +2379,7 @@ impl FromProof for ShieldedEncrypted start_index, count, max_elements, + false, platform_version, ) .map_drive_error(proof, mtd)?; @@ -2428,9 +2429,13 @@ impl FromProof for ShieldedNullifierStat get_shielded_nullifiers_request::Version::V0(v0) => v0.nullifiers, }; - let (root_hash, statuses) = - Drive::verify_shielded_nullifiers(&proof.grovedb_proof, &nullifiers, platform_version) - .map_drive_error(proof, mtd)?; + let (root_hash, statuses) = Drive::verify_shielded_nullifiers( + &proof.grovedb_proof, + &nullifiers, + false, + platform_version, + ) + .map_drive_error(proof, mtd)?; verify_tenderdash_proof(proof, mtd, &root_hash, provider)?; diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/mod.rs index a3d344778de..bd6d2a53294 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/mod.rs @@ -10,6 +10,7 @@ impl Drive { /// Verifies a proof for the valid shielded anchors. pub fn verify_shielded_anchors( proof: &[u8], + verify_subset_of_proof: bool, platform_version: &PlatformVersion, ) -> Result<(RootHash, Vec<[u8; 32]>), Error> { match platform_version @@ -19,7 +20,7 @@ impl Drive { .shielded .verify_shielded_anchors { - 0 => Self::verify_shielded_anchors_v0(proof, platform_version), + 0 => Self::verify_shielded_anchors_v0(proof, verify_subset_of_proof, platform_version), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { method: "verify_shielded_anchors".to_string(), known_versions: vec![0], diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs index 2e08b02d4a0..1d0687ce7a9 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs @@ -9,6 +9,7 @@ use platform_version::version::PlatformVersion; impl Drive { pub(super) fn verify_shielded_anchors_v0( proof: &[u8], + verify_subset_of_proof: bool, platform_version: &PlatformVersion, ) -> Result<(RootHash, Vec<[u8; 32]>), Error> { let path_query = PathQuery { @@ -20,8 +21,11 @@ impl Drive { }, }; - let (root_hash, proved_key_values) = - GroveDb::verify_query(proof, &path_query, &platform_version.drive.grove_version)?; + let (root_hash, proved_key_values) = if verify_subset_of_proof { + GroveDb::verify_subset_query(proof, &path_query, &platform_version.drive.grove_version)? + } else { + GroveDb::verify_query(proof, &path_query, &platform_version.drive.grove_version)? + }; let mut anchors = Vec::with_capacity(proved_key_values.len()); for (_, key, _) in proved_key_values { diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/mod.rs index e558567a9ae..9cb4beca969 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/mod.rs @@ -13,6 +13,7 @@ impl Drive { start_index: u64, count: u32, max_elements: u32, + verify_subset_of_proof: bool, platform_version: &PlatformVersion, ) -> Result<(RootHash, Vec<(Vec, Vec)>), Error> { match platform_version @@ -27,6 +28,7 @@ impl Drive { start_index, count, max_elements, + verify_subset_of_proof, platform_version, ), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs index f80a28d08f3..e41efc22ab7 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs @@ -12,13 +12,15 @@ impl Drive { start_index: u64, count: u32, max_elements: u32, + verify_subset_of_proof: bool, platform_version: &PlatformVersion, ) -> Result<(RootHash, Vec<(Vec, Vec)>), Error> { - let limit = if count == 0 || count > max_elements { - max_elements as u16 + let effective = if count == 0 || count > max_elements { + max_elements } else { - count as u16 + count }; + let limit = effective.min(u16::MAX as u32) as u16; let query = if start_index == 0 { Query::new_range_full() @@ -37,8 +39,11 @@ impl Drive { }, }; - let (root_hash, proved_key_values) = - GroveDb::verify_query(proof, &path_query, &platform_version.drive.grove_version)?; + let (root_hash, proved_key_values) = if verify_subset_of_proof { + GroveDb::verify_subset_query(proof, &path_query, &platform_version.drive.grove_version)? + } else { + GroveDb::verify_query(proof, &path_query, &platform_version.drive.grove_version)? + }; let mut notes = Vec::with_capacity(proved_key_values.len()); for (_, _key, maybe_element) in proved_key_values { diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/mod.rs index a15cdff5cd4..b8c0795c26f 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/mod.rs @@ -11,6 +11,7 @@ impl Drive { pub fn verify_shielded_nullifiers( proof: &[u8], nullifiers: &[Vec], + verify_subset_of_proof: bool, platform_version: &PlatformVersion, ) -> Result<(RootHash, Vec<(Vec, bool)>), Error> { match platform_version @@ -20,7 +21,12 @@ impl Drive { .shielded .verify_shielded_nullifiers { - 0 => Self::verify_shielded_nullifiers_v0(proof, nullifiers, platform_version), + 0 => Self::verify_shielded_nullifiers_v0( + proof, + nullifiers, + verify_subset_of_proof, + platform_version, + ), version => Err(Error::Drive(DriveError::UnknownVersionMismatch { method: "verify_shielded_nullifiers".to_string(), known_versions: vec![0], diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/v0/mod.rs index 5afac90dcb9..289a14606fc 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/v0/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/v0/mod.rs @@ -9,6 +9,7 @@ impl Drive { pub(super) fn verify_shielded_nullifiers_v0( proof: &[u8], nullifiers: &[Vec], + verify_subset_of_proof: bool, platform_version: &PlatformVersion, ) -> Result<(RootHash, Vec<(Vec, bool)>), Error> { let mut query = Query::new(); @@ -23,11 +24,19 @@ impl Drive { }, }; - let (root_hash, proved_key_values) = GroveDb::verify_query_with_absence_proof( - proof, - &path_query, - &platform_version.drive.grove_version, - )?; + let (root_hash, proved_key_values) = if verify_subset_of_proof { + GroveDb::verify_subset_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )? + } else { + GroveDb::verify_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )? + }; // Map each proved entry: if element is Some, nullifier is spent; if None, not spent let statuses = proved_key_values diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_pool_state/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_pool_state/mod.rs index a515650ea12..184ad457add 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_pool_state/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_pool_state/mod.rs @@ -10,6 +10,7 @@ impl Drive { /// Verifies a proof for the shielded pool total balance. pub fn verify_shielded_pool_state( proof: &[u8], + verify_subset_of_proof: bool, platform_version: &PlatformVersion, ) -> Result<(RootHash, Option), Error> { match platform_version @@ -19,7 +20,9 @@ impl Drive { .shielded .verify_shielded_pool_state { - 0 => Self::verify_shielded_pool_state_v0(proof, platform_version), + 0 => { + Self::verify_shielded_pool_state_v0(proof, verify_subset_of_proof, platform_version) + } version => Err(Error::Drive(DriveError::UnknownVersionMismatch { method: "verify_shielded_pool_state".to_string(), known_versions: vec![0], diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_pool_state/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_pool_state/v0/mod.rs index 39809d6096d..756d27c4aee 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_pool_state/v0/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_pool_state/v0/mod.rs @@ -9,6 +9,7 @@ use platform_version::version::PlatformVersion; impl Drive { pub(super) fn verify_shielded_pool_state_v0( proof: &[u8], + verify_subset_of_proof: bool, platform_version: &PlatformVersion, ) -> Result<(RootHash, Option), Error> { let path_query = PathQuery { @@ -20,11 +21,19 @@ impl Drive { }, }; - let (root_hash, mut proved_key_values) = GroveDb::verify_query_with_absence_proof( - proof, - &path_query, - &platform_version.drive.grove_version, - )?; + let (root_hash, mut proved_key_values) = if verify_subset_of_proof { + GroveDb::verify_subset_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )? + } else { + GroveDb::verify_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )? + }; if proved_key_values.len() > 1 { return Err(Error::Proof(ProofError::TooManyElements( diff --git a/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs b/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs index acca12740f9..4cae37f729c 100644 --- a/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs +++ b/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs @@ -1148,7 +1148,7 @@ impl Drive { | StateTransition::ShieldFromAssetLock(_) | StateTransition::ShieldedWithdrawal(_) => { let (root_hash, pool_balance) = - Drive::verify_shielded_pool_state(proof, platform_version)?; + Drive::verify_shielded_pool_state(proof, false, platform_version)?; Ok((root_hash, VerifiedShieldedPoolState(pool_balance))) } } diff --git a/packages/rs-sdk/src/platform/transition/shield.rs b/packages/rs-sdk/src/platform/transition/shield.rs index 91b05d2cdb0..0146647b315 100644 --- a/packages/rs-sdk/src/platform/transition/shield.rs +++ b/packages/rs-sdk/src/platform/transition/shield.rs @@ -9,7 +9,7 @@ use dpp::address_funds::{AddressFundsFeeStrategy, PlatformAddress}; use dpp::fee::Credits; use dpp::identity::signer::Signer; use dpp::prelude::AddressNonce; -use dpp::shielded::SerializedAction; +use dpp::shielded::OrchardBundleParams; use dpp::state_transition::shield_transition::methods::ShieldTransitionMethodsV0; use dpp::state_transition::shield_transition::ShieldTransition; @@ -18,32 +18,22 @@ use dpp::state_transition::shield_transition::ShieldTransition; pub trait ShieldFunds> { /// Shield funds from platform addresses into the shielded pool. /// Address nonces are fetched automatically. - #[allow(clippy::too_many_arguments)] async fn shield_funds( &self, inputs: BTreeMap, - actions: Vec, - flags: u8, + bundle: OrchardBundleParams, value_balance: i64, - anchor: [u8; 32], - proof: Vec, - binding_signature: [u8; 64], fee_strategy: AddressFundsFeeStrategy, signer: &S, settings: Option, ) -> Result<(), Error>; /// Shield funds with explicitly provided address nonces. - #[allow(clippy::too_many_arguments)] async fn shield_funds_with_nonce( &self, inputs: BTreeMap, - actions: Vec, - flags: u8, + bundle: OrchardBundleParams, value_balance: i64, - anchor: [u8; 32], - proof: Vec, - binding_signature: [u8; 64], fee_strategy: AddressFundsFeeStrategy, signer: &S, settings: Option, @@ -55,12 +45,8 @@ impl> ShieldFunds for Sdk { async fn shield_funds( &self, inputs: BTreeMap, - actions: Vec, - flags: u8, + bundle: OrchardBundleParams, value_balance: i64, - anchor: [u8; 32], - proof: Vec, - binding_signature: [u8; 64], fee_strategy: AddressFundsFeeStrategy, signer: &S, settings: Option, @@ -68,12 +54,8 @@ impl> ShieldFunds for Sdk { let inputs_with_nonce = nonce_inc(fetch_inputs_with_nonce(self, &inputs).await?); self.shield_funds_with_nonce( inputs_with_nonce, - actions, - flags, + bundle, value_balance, - anchor, - proof, - binding_signature, fee_strategy, signer, settings, @@ -84,12 +66,8 @@ impl> ShieldFunds for Sdk { async fn shield_funds_with_nonce( &self, inputs: BTreeMap, - actions: Vec, - flags: u8, + bundle: OrchardBundleParams, value_balance: i64, - anchor: [u8; 32], - proof: Vec, - binding_signature: [u8; 64], fee_strategy: AddressFundsFeeStrategy, signer: &S, settings: Option, @@ -99,6 +77,14 @@ impl> ShieldFunds for Sdk { .and_then(|s| s.user_fee_increase) .unwrap_or_default(); + let OrchardBundleParams { + actions, + flags, + anchor, + proof, + binding_signature, + } = bundle; + let state_transition = ShieldTransition::try_from_bundle_with_signer( inputs, actions, diff --git a/packages/rs-sdk/src/platform/transition/shield_from_asset_lock.rs b/packages/rs-sdk/src/platform/transition/shield_from_asset_lock.rs index 0629f3b3606..c888d582812 100644 --- a/packages/rs-sdk/src/platform/transition/shield_from_asset_lock.rs +++ b/packages/rs-sdk/src/platform/transition/shield_from_asset_lock.rs @@ -3,7 +3,7 @@ use super::put_settings::PutSettings; use super::validation::ensure_valid_state_transition_structure; use crate::{Error, Sdk}; use dpp::prelude::AssetLockProof; -use dpp::shielded::SerializedAction; +use dpp::shielded::OrchardBundleParams; use dpp::state_transition::shield_from_asset_lock_transition::methods::ShieldFromAssetLockTransitionMethodsV0; use dpp::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; @@ -13,17 +13,12 @@ pub trait ShieldFromAssetLock { /// Shield funds from an L1 asset lock into the shielded pool. /// The asset lock proof proves ownership of L1 funds, and the ECDSA signature /// binds those funds to this specific Orchard bundle. - #[allow(clippy::too_many_arguments)] async fn shield_from_asset_lock( &self, asset_lock_proof: AssetLockProof, asset_lock_proof_private_key: &[u8], - actions: Vec, - flags: u8, + bundle: OrchardBundleParams, value_balance: i64, - anchor: [u8; 32], - proof: Vec, - binding_signature: [u8; 64], settings: Option, ) -> Result<(), Error>; } @@ -34,12 +29,8 @@ impl ShieldFromAssetLock for Sdk { &self, asset_lock_proof: AssetLockProof, asset_lock_proof_private_key: &[u8], - actions: Vec, - flags: u8, + bundle: OrchardBundleParams, value_balance: i64, - anchor: [u8; 32], - proof: Vec, - binding_signature: [u8; 64], settings: Option, ) -> Result<(), Error> { let user_fee_increase = settings @@ -47,6 +38,14 @@ impl ShieldFromAssetLock for Sdk { .and_then(|s| s.user_fee_increase) .unwrap_or_default(); + let OrchardBundleParams { + actions, + flags, + anchor, + proof, + binding_signature, + } = bundle; + let state_transition = ShieldFromAssetLockTransition::try_from_asset_lock_with_bundle( asset_lock_proof, asset_lock_proof_private_key, diff --git a/packages/rs-sdk/src/platform/transition/shielded_transfer.rs b/packages/rs-sdk/src/platform/transition/shielded_transfer.rs index d0c2e1cb42e..e5b48029fe3 100644 --- a/packages/rs-sdk/src/platform/transition/shielded_transfer.rs +++ b/packages/rs-sdk/src/platform/transition/shielded_transfer.rs @@ -2,7 +2,7 @@ use super::broadcast::BroadcastStateTransition; use super::put_settings::PutSettings; use super::validation::ensure_valid_state_transition_structure; use crate::{Error, Sdk}; -use dpp::shielded::SerializedAction; +use dpp::shielded::OrchardBundleParams; use dpp::state_transition::shielded_transfer_transition::methods::ShieldedTransferTransitionMethodsV0; use dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition; @@ -11,15 +11,10 @@ use dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransit pub trait TransferShielded { /// Transfer funds within the shielded pool. /// Authentication is via Orchard spend authorization signatures in the bundle actions. - #[allow(clippy::too_many_arguments)] async fn transfer_shielded( &self, - actions: Vec, - flags: u8, + bundle: OrchardBundleParams, value_balance: u64, - anchor: [u8; 32], - proof: Vec, - binding_signature: [u8; 64], settings: Option, ) -> Result<(), Error>; } @@ -28,12 +23,8 @@ pub trait TransferShielded { impl TransferShielded for Sdk { async fn transfer_shielded( &self, - actions: Vec, - flags: u8, + bundle: OrchardBundleParams, value_balance: u64, - anchor: [u8; 32], - proof: Vec, - binding_signature: [u8; 64], settings: Option, ) -> Result<(), Error> { let user_fee_increase = settings @@ -41,6 +32,14 @@ impl TransferShielded for Sdk { .and_then(|s| s.user_fee_increase) .unwrap_or_default(); + let OrchardBundleParams { + actions, + flags, + anchor, + proof, + binding_signature, + } = bundle; + let state_transition = ShieldedTransferTransition::try_from_bundle( actions, flags, diff --git a/packages/rs-sdk/src/platform/transition/shielded_withdrawal.rs b/packages/rs-sdk/src/platform/transition/shielded_withdrawal.rs index 063bcabaa2f..af105038fc1 100644 --- a/packages/rs-sdk/src/platform/transition/shielded_withdrawal.rs +++ b/packages/rs-sdk/src/platform/transition/shielded_withdrawal.rs @@ -3,7 +3,7 @@ use super::put_settings::PutSettings; use super::validation::ensure_valid_state_transition_structure; use crate::{Error, Sdk}; use dpp::identity::core_script::CoreScript; -use dpp::shielded::SerializedAction; +use dpp::shielded::OrchardBundleParams; use dpp::state_transition::shielded_withdrawal_transition::methods::ShieldedWithdrawalTransitionMethodsV0; use dpp::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; use dpp::withdrawal::Pooling; @@ -17,12 +17,8 @@ pub trait WithdrawShielded { async fn withdraw_shielded( &self, amount: u64, - actions: Vec, - flags: u8, + bundle: OrchardBundleParams, value_balance: i64, - anchor: [u8; 32], - proof: Vec, - binding_signature: [u8; 64], core_fee_per_byte: u32, pooling: Pooling, output_script: CoreScript, @@ -32,15 +28,12 @@ pub trait WithdrawShielded { #[async_trait::async_trait] impl WithdrawShielded for Sdk { + #[allow(clippy::too_many_arguments)] async fn withdraw_shielded( &self, amount: u64, - actions: Vec, - flags: u8, + bundle: OrchardBundleParams, value_balance: i64, - anchor: [u8; 32], - proof: Vec, - binding_signature: [u8; 64], core_fee_per_byte: u32, pooling: Pooling, output_script: CoreScript, @@ -51,6 +44,14 @@ impl WithdrawShielded for Sdk { .and_then(|s| s.user_fee_increase) .unwrap_or_default(); + let OrchardBundleParams { + actions, + flags, + anchor, + proof, + binding_signature, + } = bundle; + let state_transition = ShieldedWithdrawalTransition::try_from_bundle( amount, actions, diff --git a/packages/rs-sdk/src/platform/transition/unshield.rs b/packages/rs-sdk/src/platform/transition/unshield.rs index 07cc28a025d..4a09f40dea4 100644 --- a/packages/rs-sdk/src/platform/transition/unshield.rs +++ b/packages/rs-sdk/src/platform/transition/unshield.rs @@ -3,7 +3,7 @@ use super::put_settings::PutSettings; use super::validation::ensure_valid_state_transition_structure; use crate::{Error, Sdk}; use dpp::address_funds::PlatformAddress; -use dpp::shielded::SerializedAction; +use dpp::shielded::OrchardBundleParams; use dpp::state_transition::unshield_transition::methods::UnshieldTransitionMethodsV0; use dpp::state_transition::unshield_transition::UnshieldTransition; @@ -12,17 +12,12 @@ use dpp::state_transition::unshield_transition::UnshieldTransition; pub trait UnshieldFunds { /// Unshield funds from the shielded pool to a platform address. /// Authentication is via Orchard spend authorization signatures in the bundle actions. - #[allow(clippy::too_many_arguments)] async fn unshield_funds( &self, output_address: PlatformAddress, amount: u64, - actions: Vec, - flags: u8, + bundle: OrchardBundleParams, value_balance: i64, - anchor: [u8; 32], - proof: Vec, - binding_signature: [u8; 64], settings: Option, ) -> Result<(), Error>; } @@ -33,12 +28,8 @@ impl UnshieldFunds for Sdk { &self, output_address: PlatformAddress, amount: u64, - actions: Vec, - flags: u8, + bundle: OrchardBundleParams, value_balance: i64, - anchor: [u8; 32], - proof: Vec, - binding_signature: [u8; 64], settings: Option, ) -> Result<(), Error> { let user_fee_increase = settings @@ -46,6 +37,14 @@ impl UnshieldFunds for Sdk { .and_then(|s| s.user_fee_increase) .unwrap_or_default(); + let OrchardBundleParams { + actions, + flags, + anchor, + proof, + binding_signature, + } = bundle; + let state_transition = UnshieldTransition::try_from_bundle( output_address, amount, From 404891d2df13cf6cc6e3ef38c04465f24186d579 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Mon, 16 Feb 2026 01:24:11 +0000 Subject: [PATCH 16/40] more work --- Cargo.lock | 45 +++++- packages/rs-dpp/src/shielded/mod.rs | 7 - .../methods/mod.rs | 3 - .../methods/v0/mod.rs | 4 +- .../state_transition_like.rs | 12 +- .../shielded_transfer_transition/v0/mod.rs | 4 - .../v0/state_transition_like.rs | 6 +- .../v0/v0_methods.rs | 4 +- .../methods/mod.rs | 3 - .../methods/v0/mod.rs | 3 +- .../state_transition_like.rs | 12 +- .../shielded_withdrawal_transition/v0/mod.rs | 4 - .../v0/state_transition_like.rs | 9 +- .../v0/v0_methods.rs | 4 +- .../unshield_transition/methods/mod.rs | 3 - .../unshield_transition/methods/v0/mod.rs | 3 +- .../state_transition_like.rs | 12 +- .../shielded/unshield_transition/v0/mod.rs | 4 - .../v0/state_transition_like.rs | 9 +- .../unshield_transition/v0/v0_methods.rs | 4 +- packages/rs-drive-abci/Cargo.toml | 1 + .../engine/run_block_proposal/v0/mod.rs | 9 ++ .../block_processing_end_events/mod.rs | 1 + .../record_shielded_pool_anchor/mod.rs | 109 +++++++++++++++ .../v0/mod.rs | 52 ++----- .../execute_event/v0/mod.rs | 33 ++++- .../validate_fees_of_event/v0/mod.rs | 45 ++++++ .../execution/types/execution_event/mod.rs | 32 +++-- .../check_tx_verification/v0/mod.rs | 14 ++ .../state_transition/processor/traits/mod.rs | 1 + .../processor/traits/shielded_proof.rs | 130 ++++++++++++++++++ .../state_transition/processor/v0/mod.rs | 12 ++ .../state_transitions/shield/tests.rs | 25 ++-- .../shield/transform_into_action/v0/mod.rs | 51 +------ .../shield_from_asset_lock/tests.rs | 12 +- .../state_transitions/shielded_common/mod.rs | 56 ++++++-- .../shielded_transfer/tests.rs | 57 ++++---- .../transform_into_action/v0/mod.rs | 49 +------ .../shielded_withdrawal/tests.rs | 71 ++++------ .../transform_into_action/v0/mod.rs | 67 +-------- .../state_transitions/test_helpers.rs | 56 +++++--- .../state_transitions/unshield/tests.rs | 63 ++++----- .../unshield/transform_into_action/v0/mod.rs | 69 +--------- .../src/query/shielded/anchors/v0/mod.rs | 7 +- .../query/shielded/encrypted_notes/v0/mod.rs | 4 +- .../tests/strategy_tests/strategy.rs | 19 ++- .../v0/mod.rs | 1 + .../v0/mod.rs | 1 + .../src/drive/initialization/v3/mod.rs | 38 +---- .../src/drive/shielded/estimated_costs.rs | 127 +++++++++-------- packages/rs-drive/src/drive/shielded/paths.rs | 95 ++++--------- packages/rs-drive/src/fees/op.rs | 10 ++ .../shielded/mod.rs | 57 ++------ .../shield_from_asset_lock_transition.rs | 13 +- .../shielded/shield_transition.rs | 13 +- .../shielded/shielded_transfer_transition.rs | 16 +-- .../shielded_withdrawal_transition.rs | 31 +++-- .../shielded/unshield_transition.rs | 27 ++-- .../src/state_transition_action/mod.rs | 12 +- .../shielded/shielded_transfer/mod.rs | 7 - .../shielded/shielded_transfer/v0/mod.rs | 3 - .../shielded_transfer/v0/transformer.rs | 3 +- .../shielded/shielded_withdrawal/mod.rs | 7 +- .../shielded/shielded_withdrawal/v0/mod.rs | 5 +- .../shielded_withdrawal/v0/transformer.rs | 5 +- .../shielded/unshield/mod.rs | 7 +- .../shielded/unshield/v0/mod.rs | 5 +- .../shielded/unshield/v0/transformer.rs | 5 +- .../batch/drive_op_batch/finalize_task.rs | 122 +--------------- .../src/util/batch/drive_op_batch/shielded.rs | 45 +++--- .../grove_insert_empty_tree/v0/mod.rs | 3 + .../v0/mod.rs | 1 + .../v0/mod.rs | 46 +++++-- .../verify_shielded_anchors/v0/mod.rs | 30 ++-- .../verify_shielded_encrypted_notes/v0/mod.rs | 4 +- .../drive_abci_validation_versions/mod.rs | 1 + .../drive_abci_validation_versions/v1.rs | 1 + .../drive_abci_validation_versions/v2.rs | 1 + .../drive_abci_validation_versions/v3.rs | 1 + .../drive_abci_validation_versions/v4.rs | 1 + .../drive_abci_validation_versions/v5.rs | 1 + .../drive_abci_validation_versions/v6.rs | 1 + .../drive_abci_validation_versions/v7.rs | 1 + .../src/version/fee/hashing/mod.rs | 2 + .../src/version/fee/hashing/v1.rs | 1 + .../src/system/queries/path_elements.rs | 17 ++- .../platform/transition/shielded_transfer.rs | 6 - .../transition/shielded_withdrawal.rs | 6 - .../src/platform/transition/unshield.rs | 6 - .../shielded/shielded_transfer_transition.rs | 10 +- .../shielded_withdrawal_transition.rs | 6 +- .../src/shielded/unshield_transition.rs | 5 +- 92 files changed, 970 insertions(+), 1036 deletions(-) create mode 100644 packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/record_shielded_pool_anchor/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/shielded_proof.rs diff --git a/Cargo.lock b/Cargo.lock index 23d7c0ec3d0..9f9e869f4ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -992,6 +992,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ckb-merkle-mountain-range" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327c468ff2702c0a2b7ad26728a180611da22244882959b8b2e85c79bf56bcea" +dependencies = [ + "cfg-if", +] + [[package]] name = "clang-sys" version = "1.8.1" @@ -2591,10 +2600,14 @@ dependencies = [ "bincode", "bincode_derive", "blake3", + "ckb-merkle-mountain-range", + "grovedb-bulk-append-tree", "grovedb-commitment-tree", "grovedb-costs", + "grovedb-dense-fixed-sized-merkle-tree", "grovedb-element", "grovedb-merk", + "grovedb-mmr", "grovedb-path", "grovedb-storage", "grovedb-version", @@ -2616,13 +2629,24 @@ dependencies = [ "zip-extensions", ] +[[package]] +name = "grovedb-bulk-append-tree" +version = "4.0.0" +dependencies = [ + "bincode", + "blake3", + "grovedb-dense-fixed-sized-merkle-tree", + "grovedb-mmr", + "hex", + "thiserror 2.0.17", +] + [[package]] name = "grovedb-commitment-tree" version = "4.0.0" dependencies = [ "incrementalmerkletree", "orchard", - "pasta_curves", "shardtree", "thiserror 2.0.17", ] @@ -2636,6 +2660,15 @@ dependencies = [ "thiserror 2.0.17", ] +[[package]] +name = "grovedb-dense-fixed-sized-merkle-tree" +version = "4.0.0" +dependencies = [ + "bincode", + "blake3", + "thiserror 2.0.17", +] + [[package]] name = "grovedb-element" version = "4.0.0" @@ -2685,6 +2718,16 @@ dependencies = [ "thiserror 2.0.17", ] +[[package]] +name = "grovedb-mmr" +version = "4.0.0" +dependencies = [ + "bincode", + "blake3", + "ckb-merkle-mountain-range", + "thiserror 2.0.17", +] + [[package]] name = "grovedb-path" version = "4.0.0" diff --git a/packages/rs-dpp/src/shielded/mod.rs b/packages/rs-dpp/src/shielded/mod.rs index ef35d1df0d3..78d244e79d1 100644 --- a/packages/rs-dpp/src/shielded/mod.rs +++ b/packages/rs-dpp/src/shielded/mod.rs @@ -44,13 +44,6 @@ pub(crate) mod serde_bytes_64 { } } -/// Parameters for a shielded pool, stored as an Item in the pool's subtree -#[derive(Debug, Clone, Encode, Decode, Default, PartialEq)] -pub struct ShieldedPoolParams { - /// Counter for commitment tree checkpoint IDs (monotonically increasing) - pub checkpoint_id_counter: u64, -} - /// Common Orchard bundle parameters shared across all shielded transition types. /// /// Groups the fields that every shielded transition carries identically: diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/mod.rs index b0af25fa28a..9e31072690d 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/mod.rs @@ -7,7 +7,6 @@ use crate::shielded::SerializedAction; use crate::state_transition::shielded_transfer_transition::ShieldedTransferTransition; #[cfg(feature = "state-transition-signing")] use crate::{ - prelude::UserFeeIncrease, state_transition::{ shielded_transfer_transition::v0::ShieldedTransferTransitionV0, StateTransition, }, @@ -25,7 +24,6 @@ impl ShieldedTransferTransitionMethodsV0 for ShieldedTransferTransition { anchor: [u8; 32], proof: Vec, binding_signature: [u8; 64], - user_fee_increase: UserFeeIncrease, platform_version: &PlatformVersion, ) -> Result { match platform_version @@ -41,7 +39,6 @@ impl ShieldedTransferTransitionMethodsV0 for ShieldedTransferTransition { anchor, proof, binding_signature, - user_fee_increase, platform_version, ), version => Err(ProtocolError::UnknownVersionMismatch { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/v0/mod.rs index 45dfda02a85..25a726a6182 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/methods/v0/mod.rs @@ -2,13 +2,12 @@ use crate::shielded::SerializedAction; use crate::state_transition::StateTransitionType; #[cfg(feature = "state-transition-signing")] -use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; +use crate::{state_transition::StateTransition, ProtocolError}; #[cfg(feature = "state-transition-signing")] use platform_version::version::PlatformVersion; pub trait ShieldedTransferTransitionMethodsV0 { #[cfg(feature = "state-transition-signing")] - #[allow(clippy::too_many_arguments)] fn try_from_bundle( actions: Vec, flags: u8, @@ -16,7 +15,6 @@ pub trait ShieldedTransferTransitionMethodsV0 { anchor: [u8; 32], proof: Vec, binding_signature: [u8; 64], - user_fee_increase: UserFeeIncrease, platform_version: &PlatformVersion, ) -> Result; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/state_transition_like.rs index be107d7b6d9..a6f2fa9fa74 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/state_transition_like.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/state_transition_like.rs @@ -26,17 +26,11 @@ impl StateTransitionLike for ShieldedTransferTransition { /// returns the fee multiplier fn user_fee_increase(&self) -> UserFeeIncrease { - match self { - ShieldedTransferTransition::V0(transition) => transition.user_fee_increase(), - } + 0 } /// set a fee multiplier - fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { - match self { - ShieldedTransferTransition::V0(transition) => { - transition.set_user_fee_increase(user_fee_increase) - } - } + fn set_user_fee_increase(&mut self, _user_fee_increase: UserFeeIncrease) { + // No-op: fee is cryptographically locked by the Orchard binding signature } fn unique_identifiers(&self) -> Vec { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs index ea7e1669adc..4d1a846b89c 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/mod.rs @@ -4,7 +4,6 @@ mod types; pub(super) mod v0_methods; mod version; -use crate::prelude::UserFeeIncrease; use crate::shielded::SerializedAction; use crate::ProtocolError; use bincode::{Decode, Encode}; @@ -45,8 +44,6 @@ pub struct ShieldedTransferTransitionV0 { serde(with = "crate::shielded::serde_bytes_64") )] pub binding_signature: [u8; 64], - /// Fee multiplier - pub user_fee_increase: UserFeeIncrease, } #[cfg(test)] @@ -82,7 +79,6 @@ mod tests { anchor: [7u8; 32], proof: vec![8u8; 100], binding_signature: [9u8; 64], - user_fee_increase: 0u16, }; test_round_trip(transition); diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_like.rs index aa27728f8d6..8e6088c3bf5 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_like.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_like.rs @@ -42,10 +42,10 @@ impl StateTransitionLike for ShieldedTransferTransitionV0 { } fn user_fee_increase(&self) -> UserFeeIncrease { - self.user_fee_increase + 0 } - fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { - self.user_fee_increase = user_fee_increase + fn set_user_fee_increase(&mut self, _user_fee_increase: UserFeeIncrease) { + // No-op: fee is cryptographically locked by the Orchard binding signature } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/v0_methods.rs index 4447d14f1f2..225d520c81f 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/v0_methods.rs @@ -3,7 +3,7 @@ use crate::shielded::SerializedAction; use crate::state_transition::shielded_transfer_transition::methods::ShieldedTransferTransitionMethodsV0; use crate::state_transition::shielded_transfer_transition::v0::ShieldedTransferTransitionV0; #[cfg(feature = "state-transition-signing")] -use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; +use crate::{state_transition::StateTransition, ProtocolError}; #[cfg(feature = "state-transition-signing")] use platform_version::version::PlatformVersion; @@ -16,7 +16,6 @@ impl ShieldedTransferTransitionMethodsV0 for ShieldedTransferTransitionV0 { anchor: [u8; 32], proof: Vec, binding_signature: [u8; 64], - user_fee_increase: UserFeeIncrease, _platform_version: &PlatformVersion, ) -> Result { let transition = ShieldedTransferTransitionV0 { @@ -26,7 +25,6 @@ impl ShieldedTransferTransitionMethodsV0 for ShieldedTransferTransitionV0 { anchor, proof, binding_signature, - user_fee_increase, }; Ok(transition.into()) } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/mod.rs index 84b2153623c..ba8da275dbf 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/mod.rs @@ -11,7 +11,6 @@ use crate::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalT use crate::withdrawal::Pooling; #[cfg(feature = "state-transition-signing")] use crate::{ - prelude::UserFeeIncrease, state_transition::{ shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0, StateTransition, }, @@ -33,7 +32,6 @@ impl ShieldedWithdrawalTransitionMethodsV0 for ShieldedWithdrawalTransition { core_fee_per_byte: u32, pooling: Pooling, output_script: CoreScript, - user_fee_increase: UserFeeIncrease, platform_version: &PlatformVersion, ) -> Result { match platform_version @@ -53,7 +51,6 @@ impl ShieldedWithdrawalTransitionMethodsV0 for ShieldedWithdrawalTransition { core_fee_per_byte, pooling, output_script, - user_fee_increase, platform_version, ), version => Err(ProtocolError::UnknownVersionMismatch { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/v0/mod.rs index 75e62fd4fb6..53f33aca6f1 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/methods/v0/mod.rs @@ -6,7 +6,7 @@ use crate::state_transition::StateTransitionType; #[cfg(feature = "state-transition-signing")] use crate::withdrawal::Pooling; #[cfg(feature = "state-transition-signing")] -use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; +use crate::{state_transition::StateTransition, ProtocolError}; #[cfg(feature = "state-transition-signing")] use platform_version::version::PlatformVersion; @@ -24,7 +24,6 @@ pub trait ShieldedWithdrawalTransitionMethodsV0 { core_fee_per_byte: u32, pooling: Pooling, output_script: CoreScript, - user_fee_increase: UserFeeIncrease, platform_version: &PlatformVersion, ) -> Result; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/state_transition_like.rs index 34496b07cc1..fda27be8a1c 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/state_transition_like.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/state_transition_like.rs @@ -26,17 +26,11 @@ impl StateTransitionLike for ShieldedWithdrawalTransition { /// returns the fee multiplier fn user_fee_increase(&self) -> UserFeeIncrease { - match self { - ShieldedWithdrawalTransition::V0(transition) => transition.user_fee_increase(), - } + 0 } /// set a fee multiplier - fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { - match self { - ShieldedWithdrawalTransition::V0(transition) => { - transition.set_user_fee_increase(user_fee_increase) - } - } + fn set_user_fee_increase(&mut self, _user_fee_increase: UserFeeIncrease) { + // No-op: shielded withdrawal fees are cryptographically locked by the Orchard binding signature } fn unique_identifiers(&self) -> Vec { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs index ce9157659d2..086cad5f132 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/mod.rs @@ -5,7 +5,6 @@ pub(super) mod v0_methods; mod version; use crate::identity::core_script::CoreScript; -use crate::prelude::UserFeeIncrease; use crate::shielded::SerializedAction; use crate::withdrawal::Pooling; use crate::ProtocolError; @@ -55,8 +54,6 @@ pub struct ShieldedWithdrawalTransitionV0 { pub pooling: Pooling, /// Core address receiving withdrawn funds pub output_script: CoreScript, - /// Fee multiplier - pub user_fee_increase: UserFeeIncrease, } #[cfg(test)] @@ -96,7 +93,6 @@ mod tests { core_fee_per_byte: 1u32, pooling: Pooling::Never, output_script: CoreScript::new_p2pkh([11u8; 20]), - user_fee_increase: 0u16, }; test_round_trip(transition); diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_like.rs index ea62fb381dc..3f53fe84490 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_like.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_like.rs @@ -1,8 +1,7 @@ -use crate::prelude::UserFeeIncrease; use crate::state_transition::shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0; use crate::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; use crate::{ - prelude::Identifier, + prelude::{Identifier, UserFeeIncrease}, state_transition::{StateTransitionLike, StateTransitionType}, }; @@ -42,10 +41,10 @@ impl StateTransitionLike for ShieldedWithdrawalTransitionV0 { } fn user_fee_increase(&self) -> UserFeeIncrease { - self.user_fee_increase + 0 } - fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { - self.user_fee_increase = user_fee_increase + fn set_user_fee_increase(&mut self, _user_fee_increase: UserFeeIncrease) { + // No-op: shielded withdrawal fees are cryptographically locked by the Orchard binding signature } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/v0_methods.rs index 28095dbf0de..a3767b3bb73 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/v0_methods.rs @@ -7,7 +7,7 @@ use crate::state_transition::shielded_withdrawal_transition::v0::ShieldedWithdra #[cfg(feature = "state-transition-signing")] use crate::withdrawal::Pooling; #[cfg(feature = "state-transition-signing")] -use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; +use crate::{state_transition::StateTransition, ProtocolError}; #[cfg(feature = "state-transition-signing")] use platform_version::version::PlatformVersion; @@ -24,7 +24,6 @@ impl ShieldedWithdrawalTransitionMethodsV0 for ShieldedWithdrawalTransitionV0 { core_fee_per_byte: u32, pooling: Pooling, output_script: CoreScript, - user_fee_increase: UserFeeIncrease, _platform_version: &PlatformVersion, ) -> Result { let transition = ShieldedWithdrawalTransitionV0 { @@ -38,7 +37,6 @@ impl ShieldedWithdrawalTransitionMethodsV0 for ShieldedWithdrawalTransitionV0 { core_fee_per_byte, pooling, output_script, - user_fee_increase, }; Ok(transition.into()) } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/mod.rs index 224f5542171..816dc13c9bd 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/mod.rs @@ -9,7 +9,6 @@ use crate::shielded::SerializedAction; use crate::state_transition::unshield_transition::UnshieldTransition; #[cfg(feature = "state-transition-signing")] use crate::{ - prelude::UserFeeIncrease, state_transition::{unshield_transition::v0::UnshieldTransitionV0, StateTransition}, ProtocolError, }; @@ -27,7 +26,6 @@ impl UnshieldTransitionMethodsV0 for UnshieldTransition { anchor: [u8; 32], proof: Vec, binding_signature: [u8; 64], - user_fee_increase: UserFeeIncrease, platform_version: &PlatformVersion, ) -> Result { match platform_version @@ -45,7 +43,6 @@ impl UnshieldTransitionMethodsV0 for UnshieldTransition { anchor, proof, binding_signature, - user_fee_increase, platform_version, ), version => Err(ProtocolError::UnknownVersionMismatch { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/v0/mod.rs index 7bf750ac53b..0842fdd09a4 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/methods/v0/mod.rs @@ -4,7 +4,7 @@ use crate::address_funds::PlatformAddress; use crate::shielded::SerializedAction; use crate::state_transition::StateTransitionType; #[cfg(feature = "state-transition-signing")] -use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; +use crate::{state_transition::StateTransition, ProtocolError}; #[cfg(feature = "state-transition-signing")] use platform_version::version::PlatformVersion; @@ -20,7 +20,6 @@ pub trait UnshieldTransitionMethodsV0 { anchor: [u8; 32], proof: Vec, binding_signature: [u8; 64], - user_fee_increase: UserFeeIncrease, platform_version: &PlatformVersion, ) -> Result; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/state_transition_like.rs index 67b3c5fb3f6..658cd5aeb7a 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/state_transition_like.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/state_transition_like.rs @@ -26,17 +26,11 @@ impl StateTransitionLike for UnshieldTransition { /// returns the fee multiplier fn user_fee_increase(&self) -> UserFeeIncrease { - match self { - UnshieldTransition::V0(transition) => transition.user_fee_increase(), - } + 0 } /// set a fee multiplier - fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { - match self { - UnshieldTransition::V0(transition) => { - transition.set_user_fee_increase(user_fee_increase) - } - } + fn set_user_fee_increase(&mut self, _user_fee_increase: UserFeeIncrease) { + // No-op: fee is cryptographically locked by the Orchard binding signature } fn unique_identifiers(&self) -> Vec { diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs index 590d6228cb9..989643bf2f6 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/mod.rs @@ -5,7 +5,6 @@ pub(super) mod v0_methods; mod version; use crate::address_funds::PlatformAddress; -use crate::prelude::UserFeeIncrease; use crate::shielded::SerializedAction; use crate::ProtocolError; use bincode::{Decode, Encode}; @@ -50,8 +49,6 @@ pub struct UnshieldTransitionV0 { serde(with = "crate::shielded::serde_bytes_64") )] pub binding_signature: [u8; 64], - /// Fee multiplier - pub user_fee_increase: UserFeeIncrease, } #[cfg(test)] @@ -92,7 +89,6 @@ mod tests { anchor: [7u8; 32], proof: vec![8u8; 100], binding_signature: [9u8; 64], - user_fee_increase: 0u16, }; test_round_trip(transition); diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_like.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_like.rs index 85423c358bf..a4120d242bb 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_like.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_like.rs @@ -1,8 +1,7 @@ -use crate::prelude::UserFeeIncrease; use crate::state_transition::unshield_transition::v0::UnshieldTransitionV0; use crate::state_transition::unshield_transition::UnshieldTransition; use crate::{ - prelude::Identifier, + prelude::{Identifier, UserFeeIncrease}, state_transition::{StateTransitionLike, StateTransitionType}, }; @@ -42,10 +41,10 @@ impl StateTransitionLike for UnshieldTransitionV0 { } fn user_fee_increase(&self) -> UserFeeIncrease { - self.user_fee_increase + 0 } - fn set_user_fee_increase(&mut self, user_fee_increase: UserFeeIncrease) { - self.user_fee_increase = user_fee_increase + fn set_user_fee_increase(&mut self, _user_fee_increase: UserFeeIncrease) { + // No-op: fee is cryptographically locked by the Orchard binding signature } } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/v0_methods.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/v0_methods.rs index ff4d97d10b9..e8b1714de4c 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/v0_methods.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/v0_methods.rs @@ -5,7 +5,7 @@ use crate::shielded::SerializedAction; use crate::state_transition::unshield_transition::methods::UnshieldTransitionMethodsV0; use crate::state_transition::unshield_transition::v0::UnshieldTransitionV0; #[cfg(feature = "state-transition-signing")] -use crate::{prelude::UserFeeIncrease, state_transition::StateTransition, ProtocolError}; +use crate::{state_transition::StateTransition, ProtocolError}; #[cfg(feature = "state-transition-signing")] use platform_version::version::PlatformVersion; @@ -20,7 +20,6 @@ impl UnshieldTransitionMethodsV0 for UnshieldTransitionV0 { anchor: [u8; 32], proof: Vec, binding_signature: [u8; 64], - user_fee_increase: UserFeeIncrease, _platform_version: &PlatformVersion, ) -> Result { let transition = UnshieldTransitionV0 { @@ -32,7 +31,6 @@ impl UnshieldTransitionMethodsV0 for UnshieldTransitionV0 { anchor, proof, binding_signature, - user_fee_increase, }; Ok(transition.into()) } diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index b1ae6974d6e..5b5fe4dcd11 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -106,6 +106,7 @@ dpp = { path = "../rs-dpp", default-features = false, features = [ drive = { path = "../rs-drive", features = ["fixtures-and-mocks"] } drive-proof-verifier = { path = "../rs-drive-proof-verifier" } strategy-tests = { path = "../strategy-tests" } +grovedb-commitment-tree = { path = "../../../grovedb/grovedb-commitment-tree", features = ["client"] } assert_matches = "1.5.0" drive-abci = { path = ".", features = ["testing-config", "mocks"] } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f" } 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 e6042456b00..41a01c2d8eb 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 @@ -344,6 +344,15 @@ where platform_version, )?; + // Record shielded pool anchor if the commitment tree changed this block. + // This stores block_height → anchor_bytes so shielded transactions can + // reference a recent anchor for spend authorization. + self.record_shielded_pool_anchor_if_changed( + block_proposal.height, + transaction, + platform_version, + )?; + // Pool withdrawals into transactions queue // Takes queued withdrawals, creates untiled withdrawal transaction payload, saves them to queue diff --git a/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/mod.rs index 03c783e1dd9..d1f4c5eb18e 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/mod.rs @@ -1,5 +1,6 @@ mod add_process_epoch_change_operations; pub mod process_block_fees_and_validate_sum_trees; +mod record_shielded_pool_anchor; #[cfg(test)] mod tests; diff --git a/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/record_shielded_pool_anchor/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/record_shielded_pool_anchor/mod.rs new file mode 100644 index 00000000000..1cd9f874cb3 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/block_processing_end_events/record_shielded_pool_anchor/mod.rs @@ -0,0 +1,109 @@ +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::rpc::core::CoreRPCLike; +use dpp::version::PlatformVersion; +use drive::drive::shielded::paths::{ + shielded_credit_pool_anchors_path, shielded_credit_pool_path, SHIELDED_NOTES_KEY, +}; +use drive::grovedb::query_result_type::QueryResultType; +use drive::grovedb::{Element, PathQuery, Query, QueryItem, SizedQuery, Transaction}; + +impl Platform +where + C: CoreRPCLike, +{ + /// Records the current shielded pool anchor if the commitment tree changed this block. + /// + /// After all state transitions are processed, reads the current Sinsemilla anchor + /// from the CommitmentTree at [AddressBalances, "s", [1]]. If it differs from the + /// most recently stored anchor (or no anchor exists yet), inserts + /// `block_height.to_be_bytes() → anchor_bytes` into the anchors tree at + /// [AddressBalances, "s", [6]]. + /// + /// This ensures anchors are only recorded once per block (not per-transaction), + /// and only when the commitment tree actually changed. + pub(in crate::execution) fn record_shielded_pool_anchor_if_changed( + &self, + block_height: u64, + transaction: &Transaction, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let grove_version = &platform_version.drive.grove_version; + let pool_path = shielded_credit_pool_path(); + + // 1. Read current anchor from CommitmentTree + let current_anchor = self + .drive + .grove + .commitment_tree_anchor( + &pool_path, + &[SHIELDED_NOTES_KEY], + Some(transaction), + grove_version, + ) + .unwrap() + .map_err(|e| Error::Drive(drive::error::Error::from(e)))?; + + let current_anchor_bytes: [u8; 32] = current_anchor.to_bytes(); + + // 2. Query latest stored anchor (descending, limit 1) + let anchors_path = shielded_credit_pool_anchors_path(); + let mut query = Query::new(); + query.insert_item(QueryItem::RangeFull(..)); + let path_query = PathQuery { + path: anchors_path.iter().map(|p| p.to_vec()).collect(), + query: SizedQuery { + query, + limit: Some(1), + offset: None, + }, + }; + + let (results, _) = self.drive.grove_get_raw_path_query( + &path_query, + Some(transaction), + QueryResultType::QueryKeyElementPairResultType, + &mut vec![], + &platform_version.drive, + )?; + + let latest_stored_anchor: Option<[u8; 32]> = results + .to_key_elements() + .into_iter() + .last() + .and_then(|(_key, element)| { + if let Element::Item(value, _) = element { + value.try_into().ok() + } else { + None + } + }); + + // 3. Only store if different (or none stored yet) + let should_store = match latest_stored_anchor { + None => { + // No anchors stored yet — only store if the tree has notes + // (an empty tree has a zero anchor which isn't useful) + current_anchor_bytes != [0u8; 32] + } + Some(stored) => stored != current_anchor_bytes, + }; + + if should_store { + self.drive + .grove + .insert( + &anchors_path, + &block_height.to_be_bytes(), + Element::new_item(current_anchor_bytes.to_vec()), + None, + Some(transaction), + grove_version, + ) + .unwrap() + .map_err(|e| Error::Drive(drive::error::Error::from(e)))?; + } + + Ok(()) + } +} 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 34cd630efa9..1f839c4843b 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 @@ -28,10 +28,8 @@ use drive::drive::saved_block_transactions::{ COMPACTED_ADDRESS_BALANCES_KEY_U8, }; use drive::drive::shielded::paths::{ - shielded_anchors_path, shielded_credit_pool_path, SHIELDED_ANCHORS_KEY_U8, - SHIELDED_COMMITMENTS_KEY, SHIELDED_CREDIT_POOL_KEY, SHIELDED_CREDIT_POOL_KEY_U8, - SHIELDED_ENCRYPTED_NOTES_KEY, SHIELDED_NULLIFIERS_KEY, SHIELDED_PARAMS_KEY, - SHIELDED_TOTAL_BALANCE_KEY, + shielded_credit_pool_path, SHIELDED_ANCHORS_IN_POOL_KEY, SHIELDED_CREDIT_POOL_KEY_U8, + SHIELDED_NOTES_KEY, SHIELDED_NULLIFIERS_KEY, SHIELDED_TOTAL_BALANCE_KEY, }; use drive::drive::system::misc_path; use drive::drive::tokens::paths::{ @@ -627,11 +625,12 @@ impl Platform { &platform_version.drive, )?; - // Commitments tree (CommitmentTree): [AddressBalances, "s"] / [1] + // Notes tree (CommitmentTree = CountTree items + Sinsemilla Frontier): + // [AddressBalances, "s"] / [1] let shielded_pool_path = shielded_credit_pool_path(); self.drive.grove_insert_if_not_exists( (&shielded_pool_path).into(), - &[SHIELDED_COMMITMENTS_KEY], + &[SHIELDED_NOTES_KEY], Element::empty_commitment_tree(), Some(transaction), None, @@ -648,29 +647,6 @@ impl Platform { &platform_version.drive, )?; - // Encrypted notes tree (NormalTree): [AddressBalances, "s"] / [3] - self.drive.grove_insert_if_not_exists( - (&shielded_pool_path).into(), - &[SHIELDED_ENCRYPTED_NOTES_KEY], - Element::empty_tree(), - Some(transaction), - None, - &platform_version.drive, - )?; - - // Params item: [AddressBalances, "s"] / [4] - let initial_params = dpp::shielded::ShieldedPoolParams::default(); - let encoded_params = bincode::encode_to_vec(&initial_params, bincode::config::standard()) - .expect("expected to encode default shielded pool params"); - self.drive.grove_insert_if_not_exists( - (&shielded_pool_path).into(), - &[SHIELDED_PARAMS_KEY], - Element::new_item(encoded_params), - Some(transaction), - None, - &platform_version.drive, - )?; - // Total balance SumItem(0): [AddressBalances, "s"] / [5] self.drive.grove_insert_if_not_exists( (&shielded_pool_path).into(), @@ -681,21 +657,11 @@ impl Platform { &platform_version.drive, )?; - // Anchors tree (NormalTree) under AddressBalances: [AddressBalances] / "a" - self.drive.grove_insert_if_not_exists( - addresses_path.as_slice().into(), - &[SHIELDED_ANCHORS_KEY_U8], - Element::empty_tree(), - Some(transaction), - None, - &platform_version.drive, - )?; - - // Credit pool anchors tree: [AddressBalances, "a"] / "s" - let anchors_path = shielded_anchors_path(); + // Anchors tree (NormalTree) inside pool: [AddressBalances, "s"] / [6] + // Stores block_height_be → anchor_bytes self.drive.grove_insert_if_not_exists( - (&anchors_path).into(), - SHIELDED_CREDIT_POOL_KEY, + (&shielded_pool_path).into(), + &[SHIELDED_ANCHORS_IN_POOL_KEY], Element::empty_tree(), Some(transaction), None, diff --git a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs index b153dad9394..1008df6c18b 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs @@ -334,7 +334,8 @@ where let maybe_fee_validation_result = match event { ExecutionEvent::PaidFromAssetLock { .. } | ExecutionEvent::Paid { .. } - | ExecutionEvent::PaidFromAddressInputs { .. } => Some(self.validate_fees_of_event( + | ExecutionEvent::PaidFromAddressInputs { .. } + | ExecutionEvent::PaidFromAssetLockToPool { .. } => Some(self.validate_fees_of_event( &event, block_info, Some(transaction), @@ -508,6 +509,36 @@ where Ok(UnpaidConsensusExecutionError(consensus_errors)) } } + ExecutionEvent::PaidFromAssetLockToPool { + fees_to_add_to_pool, + operations, + .. + } => { + let fee_validation_result = maybe_fee_validation_result + .expect("fee validation result must exist for PaidFromAssetLockToPool"); + let mut all_errors = fee_validation_result.errors; + all_errors.extend(consensus_errors); + + if all_errors.is_empty() { + self.drive + .apply_drive_operations( + operations, + true, + block_info, + Some(transaction), + platform_version, + Some(previous_fee_versions), + ) + .map_err(Error::Drive)?; + + Ok(SuccessfulPaidExecution( + None, + FeeResult::default_with_fees(0, fees_to_add_to_pool), + )) + } else { + Ok(UnpaidConsensusExecutionError(all_errors)) + } + } ExecutionEvent::Free { operations } => { self.drive .apply_drive_operations( diff --git a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/validate_fees_of_event/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/validate_fees_of_event/v0/mod.rs index a35bba60a2e..5e1ac125c69 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/validate_fees_of_event/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/validate_fees_of_event/v0/mod.rs @@ -8,6 +8,7 @@ use dpp::address_funds::fee_strategy::deduct_fee_from_inputs_and_outputs::deduct use dpp::block::block_info::BlockInfo; use dpp::consensus::state::address_funds::AddressesNotEnoughFundsError; use dpp::consensus::state::identity::IdentityInsufficientBalanceError; +use dpp::consensus::state::shielded::invalid_shielded_proof_error::InvalidShieldedProofError; use dpp::consensus::state::state_error::StateError; use dpp::fee::default_costs::CachedEpochIndexFeeVersions; use dpp::fee::fee_result::FeeResult; @@ -222,6 +223,50 @@ where )) } } + ExecutionEvent::PaidFromAssetLockToPool { + fees_to_add_to_pool, + operations, + execution_operations, + user_fee_increase, + } => { + let mut estimated_fee_result = self + .drive + .apply_drive_operations( + operations.clone(), + false, + block_info, + transaction, + platform_version, + Some(previous_fee_versions), + ) + .map_err(Error::Drive)?; + + ValidationOperation::add_many_to_fee_result( + execution_operations, + &mut estimated_fee_result, + platform_version, + )?; + + estimated_fee_result.apply_user_fee_increase(*user_fee_increase); + + let required_fee = estimated_fee_result.total_base_fee(); + if *fees_to_add_to_pool >= required_fee { + Ok(ConsensusValidationResult::new_with_data( + estimated_fee_result, + )) + } else { + Ok(ConsensusValidationResult::new_with_data_and_errors( + estimated_fee_result, + vec![StateError::InvalidShieldedProofError( + InvalidShieldedProofError::new(format!( + "shield_from_asset_lock fee insufficient: provided {} but minimum required {}", + fees_to_add_to_pool, required_fee + )), + ) + .into()], + )) + } + } ExecutionEvent::PaidFixedCost { .. } | ExecutionEvent::Free { .. } | ExecutionEvent::PaidFromAssetLockWithoutIdentity { .. } => Ok( diff --git a/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs b/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs index 82ee1ae10ce..c342a1ad6f5 100644 --- a/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs +++ b/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs @@ -19,9 +19,6 @@ use crate::execution::types::state_transition_execution_context::{ StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0, }; use drive::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; -use drive::state_transition_action::shielded::shield::ShieldTransitionAction; -use drive::state_transition_action::shielded::shielded_transfer::ShieldedTransferTransitionAction; -use drive::state_transition_action::shielded::unshield::UnshieldTransitionAction; use drive::state_transition_action::system::bump_address_input_nonces_action::BumpAddressInputNonceActionAccessorsV0; use drive::state_transition_action::system::partially_use_asset_lock_action::PartiallyUseAssetLockActionAccessorsV0; use drive::state_transition_action::system::penalize_shielded_pool_action::PenalizeShieldedPoolActionAccessorsV0; @@ -91,6 +88,17 @@ pub(in crate::execution) enum ExecutionEvent<'a> { /// the operations that should be performed operations: Vec>, }, + /// A drive event paid from an asset lock with funds going to the shielded pool (with fee validation) + PaidFromAssetLockToPool { + /// Fee (asset_lock_value - shield_amount) to add to the fee pool + fees_to_add_to_pool: Credits, + /// the operations that should be performed + operations: Vec>, + /// the execution operations that we must also pay for + execution_operations: Vec, + /// the fee multiplier that the user agreed to, 0 means 100% of the base fee, 1 means 101% + user_fee_increase: UserFeeIncrease, + }, /// A drive event that is free #[allow(dead_code)] // TODO investigate why `variant `Free` is never constructed` Free { @@ -472,33 +480,37 @@ impl ExecutionEvent<'_> { fees_to_add_to_pool: fee_amount, }) } - StateTransitionAction::UnshieldAction(_unshield_action) => { + StateTransitionAction::UnshieldAction(ref unshield_action) => { + let fee_amount = unshield_action.fee_amount(); let operations = action.into_high_level_drive_operations(epoch, platform_version)?; Ok(ExecutionEvent::PaidFixedCost { operations, - fees_to_add_to_pool: 0, + fees_to_add_to_pool: fee_amount, }) } StateTransitionAction::ShieldFromAssetLockAction(ref shield_from_asset_lock_action) => { // Fee = asset_lock_value - shield_amount (excess from asset lock) + let user_fee_increase = shield_from_asset_lock_action.user_fee_increase(); let fee_amount = shield_from_asset_lock_action .asset_lock_value_to_be_consumed() .saturating_sub(shield_from_asset_lock_action.shield_amount()); let operations = action.into_high_level_drive_operations(epoch, platform_version)?; - Ok(ExecutionEvent::PaidFixedCost { - operations, + Ok(ExecutionEvent::PaidFromAssetLockToPool { fees_to_add_to_pool: fee_amount, + operations, + execution_operations: execution_context.operations_consume(), + user_fee_increase, }) } - StateTransitionAction::ShieldedWithdrawalAction(_shielded_withdrawal_action) => { - // Fee = value_balance - amount (stays in pool, same pattern as Unshield) + StateTransitionAction::ShieldedWithdrawalAction(ref shielded_withdrawal_action) => { + let fee_amount = shielded_withdrawal_action.fee_amount(); let operations = action.into_high_level_drive_operations(epoch, platform_version)?; Ok(ExecutionEvent::PaidFixedCost { operations, - fees_to_add_to_pool: 0, + fees_to_add_to_pool: fee_amount, }) } StateTransitionAction::PenalizeShieldedPoolAction(ref penalize_action) => { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/check_tx_verification/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/check_tx_verification/v0/mod.rs index fe0fc422559..5cfb4e4f63b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/check_tx_verification/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/check_tx_verification/v0/mod.rs @@ -16,6 +16,7 @@ use crate::execution::check_tx::CheckTxLevel; use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext; use crate::execution::validation::state_transition::common::asset_lock::proof::verify_is_not_spent::AssetLockProofVerifyIsNotSpent; use crate::execution::validation::state_transition::processor::address_witnesses::{StateTransitionAddressWitnessValidationV0, StateTransitionHasAddressWitnessValidationV0}; +use crate::execution::validation::state_transition::processor::traits::shielded_proof::{StateTransitionHasShieldedProofValidationV0, StateTransitionShieldedProofValidationV0}; use crate::execution::validation::state_transition::processor::addresses_minimum_balance::StateTransitionAddressesMinimumBalanceValidationV0; use crate::execution::validation::state_transition::processor::advanced_structure_with_state::StateTransitionStructureKnownInStateValidationV0; use crate::execution::validation::state_transition::processor::basic_structure::StateTransitionBasicStructureValidationV0; @@ -132,6 +133,19 @@ pub(super) fn state_transition_to_execution_event_for_check_tx_v0<'a, C: CoreRPC } } + // Verify ZK proof for shielded transitions (stateless, like signature verification). + // This happens before any state reads to reject invalid proofs cheaply. + if state_transition.has_shielded_proof_validation() { + let result = state_transition.validate_shielded_proof(platform_version)?; + if !result.is_valid() { + return Ok( + ConsensusValidationResult::>::new_with_errors( + result.errors, + ), + ); + } + } + // Only identity create does not use identity in state validation, because it doesn't yet have the identity in state let mut maybe_identity = if state_transition.uses_identity_in_state() { // Validating signature for identity based state transitions (all those except identity create and identity top up) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/mod.rs index d23d32c3e06..b4767c7ee9d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/mod.rs @@ -10,4 +10,5 @@ pub(crate) mod identity_based_signature; pub(crate) mod identity_nonces; pub(crate) mod is_allowed; pub(crate) mod prefunded_specialized_balance; +pub(crate) mod shielded_proof; pub(crate) mod state; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/shielded_proof.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/shielded_proof.rs new file mode 100644 index 00000000000..006b9457b13 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/shielded_proof.rs @@ -0,0 +1,130 @@ +use crate::error::execution::ExecutionError; +use crate::error::Error; +use crate::execution::validation::state_transition::state_transitions::shielded_common::reconstruct_and_verify_bundle; +use dpp::consensus::state::state_error::StateError; +use dpp::state_transition::StateTransition; +use dpp::validation::SimpleConsensusValidationResult; +use dpp::version::PlatformVersion; + +/// A trait for checking whether a state transition requires shielded ZK proof validation. +pub(crate) trait StateTransitionHasShieldedProofValidationV0 { + /// Returns true if this state transition has a ZK proof that must be verified + /// before any state reads. + fn has_shielded_proof_validation(&self) -> bool; +} + +/// A trait for validating the ZK proof of a shielded state transition. +/// +/// This is a stateless check — it only uses data from the transition itself +/// (actions, flags, value_balance, anchor bytes, proof, binding_signature). +/// No GroveDB reads are needed. +pub(crate) trait StateTransitionShieldedProofValidationV0 { + fn validate_shielded_proof( + &self, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl StateTransitionHasShieldedProofValidationV0 for StateTransition { + fn has_shielded_proof_validation(&self) -> bool { + matches!( + self, + StateTransition::Shield(_) + | StateTransition::ShieldedTransfer(_) + | StateTransition::Unshield(_) + | StateTransition::ShieldedWithdrawal(_) + ) + } +} + +impl StateTransitionShieldedProofValidationV0 for StateTransition { + fn validate_shielded_proof( + &self, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .validate_shielded_proof + { + 0 => { + let result = match self { + StateTransition::Shield(st) => match st { + dpp::state_transition::shield_transition::ShieldTransition::V0(v0) => { + reconstruct_and_verify_bundle( + &v0.actions, + v0.flags, + v0.value_balance, + &v0.anchor, + v0.proof.as_slice(), + &v0.binding_signature, + &[], // No transparent fields for shield + ) + } + }, + StateTransition::ShieldedTransfer(st) => match st { + dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition::V0(v0) => { + reconstruct_and_verify_bundle( + &v0.actions, + v0.flags, + v0.value_balance as i64, + &v0.anchor, + v0.proof.as_slice(), + &v0.binding_signature, + &[], // No transparent fields for shielded transfer + ) + } + }, + StateTransition::Unshield(st) => match st { + dpp::state_transition::unshield_transition::UnshieldTransition::V0(v0) => { + let mut extra_sighash_data = v0.output_address.to_bytes(); + extra_sighash_data + .extend_from_slice(&v0.amount.to_le_bytes()); + reconstruct_and_verify_bundle( + &v0.actions, + v0.flags, + v0.value_balance, + &v0.anchor, + v0.proof.as_slice(), + &v0.binding_signature, + &extra_sighash_data, + ) + } + }, + StateTransition::ShieldedWithdrawal(st) => match st { + dpp::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition::V0(v0) => { + let mut extra_sighash_data = + v0.output_script.as_bytes().to_vec(); + extra_sighash_data + .extend_from_slice(&v0.amount.to_le_bytes()); + reconstruct_and_verify_bundle( + &v0.actions, + v0.flags, + v0.value_balance, + &v0.anchor, + v0.proof.as_slice(), + &v0.binding_signature, + &extra_sighash_data, + ) + } + }, + // ShieldFromAssetLock retains proof verification in transform_into_action + // (penalty comes from the asset lock, which is safe) + _ => return Ok(SimpleConsensusValidationResult::new()), + }; + + match result { + Ok(()) => Ok(SimpleConsensusValidationResult::new()), + Err(e) => Ok(SimpleConsensusValidationResult::new_with_error( + StateError::InvalidShieldedProofError(e).into(), + )), + } + } + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "StateTransition::validate_shielded_proof".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs index 8765733d5eb..f6e63d312df 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs @@ -17,6 +17,9 @@ use crate::execution::validation::state_transition::processor::identity_nonces:: use crate::execution::validation::state_transition::processor::is_allowed::StateTransitionIsAllowedValidationV0; use crate::execution::validation::state_transition::processor::prefunded_specialized_balance::StateTransitionPrefundedSpecializedBalanceValidationV0; use crate::execution::validation::state_transition::processor::state::StateTransitionStateValidation; +use crate::execution::validation::state_transition::processor::traits::shielded_proof::{ + StateTransitionHasShieldedProofValidationV0, StateTransitionShieldedProofValidationV0, +}; use crate::execution::validation::state_transition::transformer::StateTransitionActionTransformer; use crate::execution::validation::state_transition::ValidationMode; use crate::platform_types::platform::PlatformRef; @@ -159,6 +162,15 @@ pub(super) fn process_state_transition_v0<'a, C: CoreRPCLike>( } } + // Verify ZK proof for shielded transitions (stateless, like signature verification). + // This happens before any state reads to reject invalid proofs cheaply. + if state_transition.has_shielded_proof_validation() { + let result = state_transition.validate_shielded_proof(platform_version)?; + if !result.is_valid() { + return Ok(ConsensusValidationResult::::new_with_errors(result.errors)); + } + } + // For identity credit withdrawal and identity credit transfers we have a balance pre-check that includes a // processing amount and the transfer amount. // For other state transitions we only check a min balance for an amount set per version. diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs index 6c93c77a546..ab650c6ca4a 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs @@ -83,7 +83,7 @@ mod tests { actions, flags, value_balance, - anchor: [0u8; 32], + anchor: [42u8; 32], proof, binding_signature, fee_strategy, @@ -765,10 +765,9 @@ mod tests { // at the actual proof verification step. assert_matches!( processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::PaidConsensusError { - error: ConsensusError::StateError(StateError::InvalidShieldedProofError(_)), - .. - }] + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] ); } @@ -899,13 +898,12 @@ mod tests { let processing_result = process_transition(&platform, transition, platform_version); // The encrypted_note size check happens in reconstruct_and_verify_bundle, - // which runs during transform_into_action after all prior validations pass. + // which now runs at the processor level before state validation. assert_matches!( processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::PaidConsensusError { - error: ConsensusError::StateError(StateError::InvalidShieldedProofError(_)), - .. - }] + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] ); } } @@ -1054,10 +1052,9 @@ mod tests { // Mutated value_balance changes the sighash, causing signature verification to fail. assert_matches!( processing_result.execution_results().as_slice(), - [StateTransitionExecutionResult::PaidConsensusError { - error: ConsensusError::StateError(StateError::InvalidShieldedProofError(_)), - .. - }] + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) + )] ); } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs index 8514137d2da..790ac30b2ec 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs @@ -3,9 +3,7 @@ use crate::execution::types::execution_operation::ValidationOperation; use crate::execution::types::state_transition_execution_context::{ StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0, }; -use crate::execution::validation::state_transition::state_transitions::shielded_common::{ - read_pool_total_balance, reconstruct_and_verify_bundle, -}; +use crate::execution::validation::state_transition::state_transitions::shielded_common::read_pool_total_balance; use dpp::address_funds::PlatformAddress; use dpp::block::block_info::BlockInfo; use dpp::consensus::state::shielded::invalid_shielded_proof_error::InvalidShieldedProofError; @@ -17,7 +15,6 @@ use dpp::version::PlatformVersion; use drive::drive::Drive; use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::shield::ShieldTransitionAction; -use drive::state_transition_action::system::bump_address_input_nonces_action::BumpAddressInputNoncesAction; use drive::state_transition_action::StateTransitionAction; use std::collections::BTreeMap; @@ -98,52 +95,6 @@ impl ShieldStateTransitionTransformIntoActionValidationV0 for ShieldTransition { )?; execution_context.add_operation(ValidationOperation::PrecalculatedOperation(fee)); - // Verify the ZK proof - let (actions, flags, value_balance, anchor, proof, binding_signature) = match self { - ShieldTransition::V0(v0) => ( - &v0.actions, - v0.flags, - v0.value_balance, - &v0.anchor, - v0.proof.as_slice(), - &v0.binding_signature, - ), - }; - - if let Err(e) = reconstruct_and_verify_bundle( - actions, - flags, - value_balance, - anchor, - proof, - binding_signature, - &[], // No transparent fields to bind for shield - ) { - let penalty = platform_version - .drive_abci - .validation_and_processing - .penalties - .shielded_proof_verification_failure; - - let (fee_strategy, user_fee_increase) = match self { - ShieldTransition::V0(v0) => (&v0.fee_strategy, v0.user_fee_increase), - }; - - let bump_action = StateTransitionAction::BumpAddressInputNoncesAction( - BumpAddressInputNoncesAction::from_inputs_with_remaining_balance( - &inputs_with_remaining_balance, - fee_strategy, - penalty, - user_fee_increase, - ), - ); - - return Ok(ConsensusValidationResult::new_with_data_and_errors( - bump_action, - vec![StateError::InvalidShieldedProofError(e).into()], - )); - } - let result = ShieldTransitionAction::try_from_transition( self, inputs_with_remaining_balance, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs index 4af3906a2c9..b5e3c34f1bd 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs @@ -323,9 +323,9 @@ mod tests { vec![create_dummy_serialized_action()], 0x03, // spends_enabled | outputs_enabled value_balance, - [0u8; 32], // dummy anchor + [42u8; 32], // non-zero anchor (won't match any stored anchor, but proof check is first) vec![0u8; 100], // dummy proof bytes - [0u8; 64], // dummy binding signature + [0u8; 64], // dummy binding signature 0, ); @@ -365,7 +365,7 @@ mod tests { actions: vec![create_dummy_serialized_action()], flags: 0x03, value_balance: -5000, - anchor: [0u8; 32], + anchor: [42u8; 32], proof: vec![0u8; 100], binding_signature: [0u8; 64], user_fee_increase: 0, @@ -407,7 +407,7 @@ mod tests { vec![create_dummy_serialized_action()], 0x03, -5000, - [0u8; 32], + [42u8; 32], vec![0u8; 100], [0u8; 64], 0, @@ -519,7 +519,7 @@ mod tests { vec![create_dummy_serialized_action()], 0x03, -5000, - [0u8; 32], + [42u8; 32], vec![0u8; 100], // random proof data [0u8; 64], 0, @@ -569,7 +569,7 @@ mod tests { vec![create_dummy_serialized_action()], 0x03, i64::MIN, // -9223372036854775808 -- would overflow on negation - [0u8; 32], + [42u8; 32], vec![0u8; 100], [0u8; 64], 0, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs index 7b2ebc75b7e..f999208ec22 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs @@ -10,8 +10,8 @@ pub use dpp::shielded::compute_platform_sighash; use dpp::shielded::SerializedAction; use dpp::version::PlatformVersion; use drive::drive::shielded::paths::{ - shielded_anchors_credit_pool_path, shielded_credit_pool_nullifiers_path, - shielded_credit_pool_path, SHIELDED_ENCRYPTED_NOTES_KEY, SHIELDED_TOTAL_BALANCE_KEY, + shielded_credit_pool_anchors_path, shielded_credit_pool_nullifiers_path, + shielded_credit_pool_path, SHIELDED_NOTES_KEY, SHIELDED_TOTAL_BALANCE_KEY, }; use drive::drive::Drive; use drive::fees::op::LowLevelDriveOperation; @@ -201,24 +201,52 @@ pub fn read_pool_total_balance( } /// Verify that the anchor exists in the recorded anchors tree. +/// Anchors are stored as block_height_be → anchor_bytes in [AddressBalances, "s", [6]]. /// Returns a consensus error if the anchor is not found. pub fn validate_anchor_exists( drive: &Drive, anchor: &[u8; 32], transaction: TransactionArg, - drive_operations: &mut Vec, + _drive_operations: &mut Vec, platform_version: &PlatformVersion, ) -> Result>, Error> { - let anchors_path = shielded_anchors_credit_pool_path(); - let anchor_exists = drive.grove_has_raw( - (&anchors_path).into(), - anchor, - DirectQueryType::StatefulDirectQuery, - transaction, - drive_operations, - &platform_version.drive, - )?; - if !anchor_exists { + use drive::grovedb::query_result_type::QueryResultType; + use drive::grovedb::{Element, PathQuery, Query, SizedQuery}; + + let anchors_path = shielded_credit_pool_anchors_path(); + let path_query = PathQuery { + path: anchors_path.iter().map(|p| p.to_vec()).collect(), + query: SizedQuery { + query: Query::new_range_full(), + limit: None, + offset: None, + }, + }; + + let grove_version = &platform_version.drive.grove_version; + let results = drive + .grove + .query_raw( + &path_query, + true, + true, + true, + QueryResultType::QueryKeyElementPairResultType, + transaction, + grove_version, + ) + .unwrap() + .map_err(drive::error::Error::from)?; + + let found = results.0.to_key_elements().into_iter().any(|(_, element)| { + if let Element::Item(value, _) = element { + value.as_slice() == anchor + } else { + false + } + }); + + if !found { Ok(Some(ConsensusValidationResult::new_with_error( StateError::InvalidAnchorError(InvalidAnchorError::new(*anchor)).into(), ))) @@ -284,7 +312,7 @@ pub fn validate_minimum_pool_notes( let encrypted_notes_count = drive .grove_get_raw_optional( (&pool_path).into(), - &[SHIELDED_ENCRYPTED_NOTES_KEY], + &[SHIELDED_NOTES_KEY], DirectQueryType::StatefulDirectQuery, transaction, drive_operations, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs index 1f272ada3c2..e41c06a00a7 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs @@ -29,7 +29,6 @@ mod tests { anchor: [u8; 32], proof: Vec, binding_signature: [u8; 64], - user_fee_increase: u16, ) -> StateTransition { StateTransition::ShieldedTransfer(ShieldedTransferTransition::V0( ShieldedTransferTransitionV0 { @@ -39,7 +38,6 @@ mod tests { anchor, proof, binding_signature, - user_fee_increase, }, )) } @@ -54,7 +52,6 @@ mod tests { [42u8; 32], // non-zero anchor vec![0u8; 100], // dummy proof bytes [0u8; 64], // dummy binding signature - 0, ) } @@ -77,7 +74,6 @@ mod tests { [42u8; 32], vec![0u8; 100], [0u8; 64], - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -102,7 +98,6 @@ mod tests { [42u8; 32], vec![0u8; 100], [0u8; 64], - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -127,7 +122,6 @@ mod tests { [42u8; 32], vec![], // Empty proof — invalid [0u8; 64], - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -152,7 +146,6 @@ mod tests { [0u8; 32], // All zeros — invalid vec![0u8; 100], [0u8; 64], - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -183,10 +176,12 @@ mod tests { let processing_result = process_transition(&platform, transition, platform_version); + // Proof verification now runs before anchor validation, so the + // dummy proof data is rejected before the anchor check is reached. assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::StateError(StateError::InvalidAnchorError(_)) + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) )] ); } @@ -217,10 +212,12 @@ mod tests { let processing_result = process_transition(&platform, transition, platform_version); + // Proof verification now runs before nullifier validation, so the + // dummy proof data is rejected before the nullifier check is reached. assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::StateError(StateError::NullifierAlreadySpentError(_)) + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) )] ); } @@ -233,9 +230,10 @@ mod tests { mod proof_verification { use super::*; use grovedb_commitment_tree::{ - new_memory_store, Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - CommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, NoteValue, - Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + ClientCommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, + NoteValue, Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, + SpendingKey, }; use orchard::note::RandomSeed; use rand::rngs::OsRng; @@ -327,11 +325,11 @@ mod tests { // --- Build commitment tree and get anchor + merkle path --- let cmx = ExtractedNoteCommitment::from(note.commitment()); - let mut tree = CommitmentTree::new(new_memory_store(), 100); - tree.append(cmx, Retention::Marked).unwrap(); + let mut tree = ClientCommitmentTree::new(100); + tree.append(cmx.to_bytes(), Retention::Marked).unwrap(); tree.checkpoint(0u32).unwrap(); let anchor = tree.anchor().unwrap(); - let merkle_path = tree.orchard_witness(Position::from(0u64)).unwrap().unwrap(); + let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); // --- Build bundle: spend 10_000 → output 10_000 (value_balance = 0) --- let mut builder = Builder::new(BundleType::DEFAULT, anchor); @@ -364,7 +362,6 @@ mod tests { anchor_bytes, proof_bytes, binding_sig, - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -396,7 +393,6 @@ mod tests { anchor, vec![0u8; 100], [0u8; 64], - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -422,9 +418,10 @@ mod tests { mod security_audit { use super::*; use grovedb_commitment_tree::{ - new_memory_store, Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - CommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, NoteValue, - Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + ClientCommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, + NoteValue, Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, + SpendingKey, }; use orchard::note::RandomSeed; use rand::rngs::OsRng; @@ -488,11 +485,11 @@ mod tests { Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); let cmx = ExtractedNoteCommitment::from(note.commitment()); - let mut tree = CommitmentTree::new(new_memory_store(), 100); - tree.append(cmx, Retention::Marked).unwrap(); + let mut tree = ClientCommitmentTree::new(100); + tree.append(cmx.to_bytes(), Retention::Marked).unwrap(); tree.checkpoint(0u32).unwrap(); let anchor = tree.anchor().unwrap(); - let merkle_path = tree.orchard_witness(Position::from(0u64)).unwrap().unwrap(); + let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); let mut builder = Builder::new(BundleType::DEFAULT, anchor); builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); @@ -541,7 +538,6 @@ mod tests { anchor_bytes, proof_bytes, binding_sig, - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -578,7 +574,6 @@ mod tests { anchor_bytes, proof_bytes, [0u8; 64], // ZEROED binding signature - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -621,7 +616,6 @@ mod tests { anchor_bytes, proof_bytes, binding_sig, - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -635,8 +629,9 @@ mod tests { ); } - /// Duplicate nullifiers within the same bundle are caught by the - /// intra-bundle dedup check before reaching proof verification. + /// Duplicate nullifiers within the same bundle — proof verification now + /// runs before the intra-bundle dedup check, so the invalid proof is + /// rejected first. #[test] fn test_duplicate_nullifiers_in_same_bundle() { let platform_version = PlatformVersion::latest(); @@ -657,16 +652,16 @@ mod tests { anchor, vec![0u8; 100], [0u8; 64], - 0, ); let processing_result = process_transition(&platform, transition, platform_version); - // Intra-bundle duplicate nullifier check catches this before proof verification + // Proof verification now runs before nullifier dedup, so the + // dummy proof data is rejected first. assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::StateError(StateError::NullifierAlreadySpentError(_)) + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) )] ); } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs index b1380522c76..c739b8eff42 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs @@ -4,8 +4,7 @@ use crate::execution::types::state_transition_execution_context::{ StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0, }; use crate::execution::validation::state_transition::state_transitions::shielded_common::{ - read_pool_total_balance, reconstruct_and_verify_bundle, validate_anchor_exists, - validate_nullifiers, + read_pool_total_balance, validate_anchor_exists, validate_nullifiers, }; use dpp::block::block_info::BlockInfo; use dpp::consensus::state::state_error::StateError; @@ -16,8 +15,6 @@ use dpp::version::PlatformVersion; use drive::drive::Drive; use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::shielded_transfer::ShieldedTransferTransitionAction; -use drive::state_transition_action::system::penalize_shielded_pool_action::v0::PenalizeShieldedPoolActionV0; -use drive::state_transition_action::system::penalize_shielded_pool_action::PenalizeShieldedPoolAction; use drive::state_transition_action::StateTransitionAction; pub(in crate::execution::validation::state_transition::state_transitions::shielded_transfer) trait ShieldedTransferStateTransitionTransformIntoActionValidationV0 @@ -119,50 +116,6 @@ impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 for Shielded )?; execution_context.add_operation(ValidationOperation::PrecalculatedOperation(fee)); - // Verify the ZK proof - // Cast value_balance to i64 for Orchard protocol — safe because structure - // validation already verified value_balance <= i64::MAX - let (st_actions, st_flags, st_value_balance, st_proof, st_binding_sig) = match self { - ShieldedTransferTransition::V0(v0) => ( - &v0.actions, - v0.flags, - v0.value_balance as i64, - v0.proof.as_slice(), - &v0.binding_signature, - ), - }; - - if let Err(e) = reconstruct_and_verify_bundle( - st_actions, - st_flags, - st_value_balance, - &anchor, - st_proof, - st_binding_sig, - &[], // No transparent fields to bind for shielded transfer - ) { - let penalty = platform_version - .drive_abci - .validation_and_processing - .penalties - .shielded_proof_verification_failure; - - let penalty_amount = std::cmp::min(penalty, current_total_balance); - - let penalize_action = StateTransitionAction::PenalizeShieldedPoolAction( - PenalizeShieldedPoolAction::from(PenalizeShieldedPoolActionV0 { - penalty_amount, - nullifiers: nullifiers.clone(), - current_total_balance, - }), - ); - - return Ok(ConsensusValidationResult::new_with_data_and_errors( - penalize_action, - vec![StateError::InvalidShieldedProofError(e).into()], - )); - } - let result = ShieldedTransferTransitionAction::try_from_transition( self, nullifiers, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs index 1ae4bb36a1d..a33cc839399 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs @@ -41,7 +41,6 @@ mod tests { core_fee_per_byte: u32, pooling: Pooling, output_script: CoreScript, - user_fee_increase: u16, ) -> StateTransition { StateTransition::ShieldedWithdrawal(ShieldedWithdrawalTransition::V0( ShieldedWithdrawalTransitionV0 { @@ -55,7 +54,6 @@ mod tests { core_fee_per_byte, pooling, output_script, - user_fee_increase, }, )) } @@ -75,7 +73,6 @@ mod tests { 1, // core_fee_per_byte Pooling::Never, // pooling strategy create_output_script(), // P2PKH output script - 0, // user_fee_increase ) } @@ -102,7 +99,6 @@ mod tests { 1, Pooling::Never, create_output_script(), - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -131,7 +127,6 @@ mod tests { 1, Pooling::Never, create_output_script(), - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -160,7 +155,6 @@ mod tests { 1, Pooling::Never, create_output_script(), - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -189,7 +183,6 @@ mod tests { 1, Pooling::Never, create_output_script(), - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -218,7 +211,6 @@ mod tests { 1, Pooling::Never, create_output_script(), - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -247,7 +239,6 @@ mod tests { 1, Pooling::Never, create_output_script(), - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -276,7 +267,6 @@ mod tests { 1, Pooling::Never, create_output_script(), - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -313,10 +303,12 @@ mod tests { let processing_result = process_transition(&platform, transition, platform_version); + // Proof verification now runs before pool notes check, so the + // dummy proof data is rejected first. assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::StateError(StateError::InsufficientPoolNotesError(_)) + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) )] ); } @@ -327,15 +319,20 @@ mod tests { let platform = setup_platform(); insert_dummy_encrypted_notes(&platform, 250); + // Set pool balance so the balance check passes before anchor validation + set_pool_total_balance(&platform, 10_000); + // Non-zero anchor that doesn't exist in state let transition = create_default_shielded_withdrawal_transition(); let processing_result = process_transition(&platform, transition, platform_version); + // Proof verification now runs before anchor validation, so the + // dummy proof data is rejected first. assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::StateError(StateError::InvalidAnchorError(_)) + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) )] ); } @@ -370,10 +367,12 @@ mod tests { let processing_result = process_transition(&platform, transition, platform_version); + // Proof verification now runs before nullifier validation, so the + // dummy proof data is rejected before the nullifier check is reached. assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::StateError(StateError::NullifierAlreadySpentError(_)) + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) )] ); } @@ -386,9 +385,9 @@ mod tests { mod proof_verification { use super::*; use grovedb_commitment_tree::{ - new_memory_store, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - CommitmentTree, ExtractedNoteCommitment, FullViewingKey, Note, NoteValue, Position, - ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, + Authorized as OrchardAuthorized, Builder, Bundle, BundleType, ClientCommitmentTree, + ExtractedNoteCommitment, FullViewingKey, Note, NoteValue, Position, ProvingKey, + Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, }; use orchard::note::RandomSeed; use rand::rngs::OsRng; @@ -485,11 +484,11 @@ mod tests { // --- Build commitment tree and get anchor + merkle path --- let cmx = ExtractedNoteCommitment::from(note.commitment()); - let mut tree = CommitmentTree::new(new_memory_store(), 100); - tree.append(cmx, Retention::Marked).unwrap(); + let mut tree = ClientCommitmentTree::new(100); + tree.append(cmx.to_bytes(), Retention::Marked).unwrap(); tree.checkpoint(0u32).unwrap(); let anchor = tree.anchor().unwrap(); - let merkle_path = tree.orchard_witness(Position::from(0u64)).unwrap().unwrap(); + let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); // --- Build bundle: spend 10,000 -> output 5,000 (value_balance = 5,000) --- let mut builder = Builder::new(BundleType::DEFAULT, anchor); @@ -537,7 +536,6 @@ mod tests { 1, // core_fee_per_byte Pooling::Never, // pooling strategy output_script, - 0, // user_fee_increase ); let processing_result = process_transition(&platform, transition, platform_version); @@ -577,7 +575,6 @@ mod tests { 1, Pooling::Never, create_output_script(), - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -603,9 +600,9 @@ mod tests { mod security_audit { use super::*; use grovedb_commitment_tree::{ - new_memory_store, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - CommitmentTree, ExtractedNoteCommitment, FullViewingKey, Note, NoteValue, Position, - ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, + Authorized as OrchardAuthorized, Builder, Bundle, BundleType, ClientCommitmentTree, + ExtractedNoteCommitment, FullViewingKey, Note, NoteValue, Position, ProvingKey, + Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, }; use orchard::note::RandomSeed; use rand::rngs::OsRng; @@ -673,11 +670,11 @@ mod tests { Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); let cmx = ExtractedNoteCommitment::from(note.commitment()); - let mut tree = CommitmentTree::new(new_memory_store(), 100); - tree.append(cmx, Retention::Marked).unwrap(); + let mut tree = ClientCommitmentTree::new(100); + tree.append(cmx.to_bytes(), Retention::Marked).unwrap(); tree.checkpoint(0u32).unwrap(); let anchor = tree.anchor().unwrap(); - let merkle_path = tree.orchard_witness(Position::from(0u64)).unwrap().unwrap(); + let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); // Spend 10,000 -> output 5,000 -> value_balance = 5,000 let mut builder = Builder::new(BundleType::DEFAULT, anchor); @@ -719,7 +716,6 @@ mod tests { 1, Pooling::Never, create_output_script(), - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -766,7 +762,6 @@ mod tests { 1, Pooling::Never, output_script, - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -820,7 +815,6 @@ mod tests { 1, Pooling::Never, output_script, - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -872,7 +866,6 @@ mod tests { 1, Pooling::Never, attacker_script, // ATTACKER's script, not the original - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -924,7 +917,6 @@ mod tests { 1, Pooling::Never, output_script, - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -939,14 +931,9 @@ mod tests { ); } - /// AUDIT FINDING: No intra-bundle duplicate nullifier check. - /// - /// Same as the shielded_transfer and unshield findings. The nullifier - /// check only queries state, not checking for duplicates within the - /// bundle itself. Mitigated by ZK proof verification (fabricated data - /// with duplicate nullifiers produces an invalid proof). - /// - /// Severity: LOW (defense-in-depth gap, caught by ZK proof verification) + /// Duplicate nullifiers within the same bundle — proof verification now + /// runs before the intra-bundle dedup check, so the invalid proof is + /// rejected first. #[test] fn test_duplicate_nullifiers_in_same_bundle() { let platform_version = PlatformVersion::latest(); @@ -972,12 +959,12 @@ mod tests { 1, Pooling::Never, create_output_script(), - 0, ); let processing_result = process_transition(&platform, transition, platform_version); - // Caught by proof verification, not by application-level dedup + // Proof verification now runs before nullifier dedup, so the + // dummy proof data is rejected first. assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs index 35a41d49128..3a24403ce4e 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs @@ -4,8 +4,8 @@ use crate::execution::types::state_transition_execution_context::{ StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0, }; use crate::execution::validation::state_transition::state_transitions::shielded_common::{ - read_pool_total_balance, reconstruct_and_verify_bundle, validate_anchor_exists, - validate_minimum_pool_notes, validate_nullifiers, + read_pool_total_balance, validate_anchor_exists, validate_minimum_pool_notes, + validate_nullifiers, }; use dpp::block::block_info::BlockInfo; use dpp::consensus::state::state_error::StateError; @@ -15,8 +15,6 @@ use dpp::version::PlatformVersion; use drive::drive::Drive; use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::shielded_withdrawal::ShieldedWithdrawalTransitionAction; -use drive::state_transition_action::system::penalize_shielded_pool_action::v0::PenalizeShieldedPoolActionV0; -use drive::state_transition_action::system::penalize_shielded_pool_action::PenalizeShieldedPoolAction; use drive::state_transition_action::StateTransitionAction; pub(in crate::execution::validation::state_transition::state_transitions::shielded_withdrawal) trait ShieldedWithdrawalStateTransitionTransformIntoActionValidationV0 @@ -134,67 +132,6 @@ impl ShieldedWithdrawalStateTransitionTransformIntoActionValidationV0 )?; execution_context.add_operation(ValidationOperation::PrecalculatedOperation(fee)); - // Verify the Orchard ZK proof, binding transparent fields to the sighash. - // For shielded withdrawal, the extra_sighash_data binds the withdrawal - // destination (output_script) and amount, preventing an attacker from - // substituting a different output_script or amount while reusing a valid - // Orchard bundle. - let ( - st_actions, - st_flags, - st_value_balance, - st_proof, - st_binding_sig, - output_script, - amount, - ) = match self { - ShieldedWithdrawalTransition::V0(v0) => ( - &v0.actions, - v0.flags, - v0.value_balance, - v0.proof.as_slice(), - &v0.binding_signature, - &v0.output_script, - v0.amount, - ), - }; - - // Serialize transparent fields to bind them to the Orchard sighash. - // output_script.as_bytes() || amount.to_le_bytes() - let mut extra_sighash_data = output_script.as_bytes().to_vec(); - extra_sighash_data.extend_from_slice(&amount.to_le_bytes()); - - if let Err(e) = reconstruct_and_verify_bundle( - st_actions, - st_flags, - st_value_balance, - &anchor, - st_proof, - st_binding_sig, - &extra_sighash_data, - ) { - let penalty = platform_version - .drive_abci - .validation_and_processing - .penalties - .shielded_proof_verification_failure; - - let penalty_amount = std::cmp::min(penalty, current_total_balance); - - let penalize_action = StateTransitionAction::PenalizeShieldedPoolAction( - PenalizeShieldedPoolAction::from(PenalizeShieldedPoolActionV0 { - penalty_amount, - nullifiers: nullifiers.clone(), - current_total_balance, - }), - ); - - return Ok(ConsensusValidationResult::new_with_data_and_errors( - penalize_action, - vec![StateError::InvalidShieldedProofError(e).into()], - )); - } - // Build the action, which includes creating the withdrawal document let creation_time_ms = block_info.time_ms; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/test_helpers.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/test_helpers.rs index a124daeec57..2d523c926f3 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/test_helpers.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/test_helpers.rs @@ -22,8 +22,9 @@ use dpp::shielded::SerializedAction; use dpp::state_transition::StateTransition; use dpp::ProtocolError; use drive::drive::shielded::paths::{ - shielded_anchors_credit_pool_path, shielded_credit_pool_encrypted_notes_path, - shielded_credit_pool_nullifiers_path, shielded_credit_pool_path, SHIELDED_TOTAL_BALANCE_KEY, + shielded_credit_pool_anchors_path, shielded_credit_pool_notes_path, + shielded_credit_pool_nullifiers_path, shielded_credit_pool_path, SHIELDED_NOTES_KEY, + SHIELDED_TOTAL_BALANCE_KEY, }; use drive::grovedb::Element; use platform_version::version::PlatformVersion; @@ -460,19 +461,20 @@ pub fn process_transition( } /// Insert a fake anchor into the shielded anchors tree via GroveDB. +/// Anchors are stored as block_height_be → anchor_bytes in [AddressBalances, "s", [6]]. pub fn insert_anchor_into_state(platform: &TempPlatform, anchor: &[u8; 32]) { let platform_version = PlatformVersion::latest(); let grove_version = &platform_version.drive.grove_version; let transaction = platform.drive.grove.start_transaction(); - let anchors_path = shielded_anchors_credit_pool_path(); + let anchors_path = shielded_credit_pool_anchors_path(); platform .drive .grove .insert( &anchors_path, - anchor, - Element::Item(vec![], None), + &0u64.to_be_bytes(), + Element::new_item(anchor.to_vec()), None, Some(&transaction), grove_version, @@ -538,6 +540,13 @@ pub fn set_pool_total_balance(platform: &TempPlatform, balance: .unwrap() .expect("should set total balance"); + // The shielded pool is part of total system credits, so ensure system credits + // cover the pool balance (needed for RemoveFromSystemCredits in withdrawals). + platform + .drive + .add_to_system_credits(balance, Some(&transaction), platform_version) + .expect("should add to system credits"); + platform .drive .grove @@ -546,34 +555,41 @@ pub fn set_pool_total_balance(platform: &TempPlatform, balance: .expect("should commit transaction"); } -/// Insert dummy encrypted notes into the shielded pool to meet the minimum +/// Insert dummy notes into the CommitmentTree to meet the minimum /// notes threshold for outgoing transitions. +/// Uses `commitment_tree_insert` to properly update the Sinsemilla frontier. pub fn insert_dummy_encrypted_notes(platform: &TempPlatform, count: u64) { let platform_version = PlatformVersion::latest(); let grove_version = &platform_version.drive.grove_version; - let transaction = platform.drive.grove.start_transaction(); - let notes_path = shielded_credit_pool_encrypted_notes_path(); + let pool_path = shielded_credit_pool_path(); for i in 0..count { + // Generate a deterministic dummy cmx from the index. + // Use a valid Pallas base field element (just set it to a small value). + let mut cmx = [0u8; 32]; + cmx[..8].copy_from_slice(&(i + 1).to_le_bytes()); + let dummy_payload = vec![0u8; 32]; // minimal dummy payload + + let transaction = platform.drive.grove.start_transaction(); platform .drive .grove - .insert( - ¬es_path, - &i.to_be_bytes(), - Element::Item(vec![0], None), - None, + .commitment_tree_insert( + &pool_path, + &[SHIELDED_NOTES_KEY], + cmx, + dummy_payload, Some(&transaction), grove_version, ) .unwrap() .expect("should insert dummy note"); - } - platform - .drive - .grove - .commit_transaction(transaction) - .unwrap() - .expect("should commit transaction"); + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("should commit transaction"); + } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs index 5eda2c34e78..635d8c9393b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs @@ -40,7 +40,6 @@ mod tests { anchor: [u8; 32], proof: Vec, binding_signature: [u8; 64], - user_fee_increase: u16, ) -> StateTransition { StateTransition::Unshield(UnshieldTransition::V0(UnshieldTransitionV0 { output_address, @@ -51,7 +50,6 @@ mod tests { anchor, proof, binding_signature, - user_fee_increase, })) } @@ -67,7 +65,6 @@ mod tests { [42u8; 32], // non-zero anchor vec![0u8; 100], // dummy proof bytes [0u8; 64], // dummy binding signature - 0, ) } @@ -92,7 +89,6 @@ mod tests { [42u8; 32], vec![0u8; 100], [0u8; 64], - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -119,7 +115,6 @@ mod tests { [42u8; 32], vec![0u8; 100], [0u8; 64], - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -146,7 +141,6 @@ mod tests { [42u8; 32], vec![0u8; 100], [0u8; 64], - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -173,7 +167,6 @@ mod tests { [42u8; 32], vec![0u8; 100], [0u8; 64], - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -200,7 +193,6 @@ mod tests { [42u8; 32], vec![0u8; 100], [0u8; 64], - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -227,7 +219,6 @@ mod tests { [42u8; 32], vec![], // Empty proof — invalid [0u8; 64], - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -254,7 +245,6 @@ mod tests { [0u8; 32], // All zeros — invalid vec![0u8; 100], [0u8; 64], - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -288,10 +278,12 @@ mod tests { let processing_result = process_transition(&platform, transition, platform_version); + // Proof verification now runs before pool notes check, so the + // dummy proof data is rejected first. assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::StateError(StateError::InsufficientPoolNotesError(_)) + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) )] ); } @@ -307,10 +299,12 @@ mod tests { let processing_result = process_transition(&platform, transition, platform_version); + // Proof verification now runs before anchor validation, so the + // dummy proof data is rejected first. assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::StateError(StateError::InvalidAnchorError(_)) + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) )] ); } @@ -342,10 +336,12 @@ mod tests { let processing_result = process_transition(&platform, transition, platform_version); + // Proof verification now runs before nullifier validation, so the + // dummy proof data is rejected before the nullifier check is reached. assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::StateError(StateError::NullifierAlreadySpentError(_)) + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) )] ); } @@ -358,9 +354,10 @@ mod tests { mod proof_verification { use super::*; use grovedb_commitment_tree::{ - new_memory_store, Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - CommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, NoteValue, - Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + ClientCommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, + NoteValue, Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, + SpendingKey, }; use orchard::note::RandomSeed; use rand::rngs::OsRng; @@ -454,11 +451,11 @@ mod tests { // --- Build commitment tree and get anchor + merkle path --- let cmx = ExtractedNoteCommitment::from(note.commitment()); - let mut tree = CommitmentTree::new(new_memory_store(), 100); - tree.append(cmx, Retention::Marked).unwrap(); + let mut tree = ClientCommitmentTree::new(100); + tree.append(cmx.to_bytes(), Retention::Marked).unwrap(); tree.checkpoint(0u32).unwrap(); let anchor = tree.anchor().unwrap(); - let merkle_path = tree.orchard_witness(Position::from(0u64)).unwrap().unwrap(); + let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); // --- Build bundle: spend 10,000 → output 5,000 (value_balance = 5,000) --- let mut builder = Builder::new(BundleType::DEFAULT, anchor); @@ -505,7 +502,6 @@ mod tests { anchor_bytes, proof_bytes, binding_sig, - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -540,7 +536,6 @@ mod tests { anchor, vec![0u8; 100], [0u8; 64], - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -561,9 +556,10 @@ mod tests { mod security_audit { use super::*; use grovedb_commitment_tree::{ - new_memory_store, Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - CommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, NoteValue, - Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + ClientCommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, + NoteValue, Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, + SpendingKey, }; use orchard::note::RandomSeed; use rand::rngs::OsRng; @@ -631,11 +627,11 @@ mod tests { Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); let cmx = ExtractedNoteCommitment::from(note.commitment()); - let mut tree = CommitmentTree::new(new_memory_store(), 100); - tree.append(cmx, Retention::Marked).unwrap(); + let mut tree = ClientCommitmentTree::new(100); + tree.append(cmx.to_bytes(), Retention::Marked).unwrap(); tree.checkpoint(0u32).unwrap(); let anchor = tree.anchor().unwrap(); - let merkle_path = tree.orchard_witness(Position::from(0u64)).unwrap().unwrap(); + let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); // Spend 10,000 → output 5,000 → value_balance = 5,000 let mut builder = Builder::new(BundleType::DEFAULT, anchor); @@ -696,7 +692,6 @@ mod tests { anchor_bytes, proof_bytes, binding_sig, - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -747,7 +742,6 @@ mod tests { anchor_bytes, proof_bytes, binding_sig, - 0, ); let processing_result = process_transition(&platform, transition, platform_version); @@ -763,8 +757,9 @@ mod tests { ); } - /// Duplicate nullifiers within the same bundle are caught by the - /// intra-bundle dedup check before reaching proof verification. + /// Duplicate nullifiers within the same bundle — proof verification now + /// runs before the intra-bundle dedup check, so the invalid proof is + /// rejected first. #[test] fn test_duplicate_nullifiers_in_same_bundle() { let platform_version = PlatformVersion::latest(); @@ -788,16 +783,16 @@ mod tests { anchor, vec![0u8; 100], [0u8; 64], - 0, ); let processing_result = process_transition(&platform, transition, platform_version); - // Intra-bundle duplicate nullifier check catches this before proof verification + // Proof verification now runs before nullifier dedup, so the + // dummy proof data is rejected first. assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( - ConsensusError::StateError(StateError::NullifierAlreadySpentError(_)) + ConsensusError::StateError(StateError::InvalidShieldedProofError(_)) )] ); } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs index 5c7351ca738..aacf924805e 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs @@ -4,19 +4,16 @@ use crate::execution::types::state_transition_execution_context::{ StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0, }; use crate::execution::validation::state_transition::state_transitions::shielded_common::{ - read_pool_total_balance, reconstruct_and_verify_bundle, validate_anchor_exists, - validate_minimum_pool_notes, validate_nullifiers, + read_pool_total_balance, validate_anchor_exists, validate_minimum_pool_notes, + validate_nullifiers, }; use dpp::block::block_info::BlockInfo; -use dpp::consensus::state::state_error::StateError; use dpp::prelude::ConsensusValidationResult; use dpp::state_transition::unshield_transition::UnshieldTransition; use dpp::version::PlatformVersion; use drive::drive::Drive; use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::unshield::UnshieldTransitionAction; -use drive::state_transition_action::system::penalize_shielded_pool_action::v0::PenalizeShieldedPoolActionV0; -use drive::state_transition_action::system::penalize_shielded_pool_action::PenalizeShieldedPoolAction; use drive::state_transition_action::StateTransitionAction; pub(in crate::execution::validation::state_transition::state_transitions::unshield) trait UnshieldStateTransitionTransformIntoActionValidationV0 @@ -108,31 +105,14 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti )?; execution_context.add_operation(ValidationOperation::PrecalculatedOperation(fee)); - // Verify the ZK proof, binding transparent fields to the sighash - let ( - st_actions, - st_flags, - st_value_balance, - st_proof, - st_binding_sig, - output_address, - amount, - ) = match self { - UnshieldTransition::V0(v0) => ( - &v0.actions, - v0.flags, - v0.value_balance, - v0.proof.as_slice(), - &v0.binding_signature, - v0.output_address, - v0.amount, - ), + // Verify the pool has sufficient balance for the unshield amount + let amount = match self { + UnshieldTransition::V0(v0) => v0.amount, }; - // Verify the pool has sufficient balance for the unshield amount if current_total_balance < amount { return Ok(ConsensusValidationResult::new_with_error( - StateError::InvalidShieldedProofError( + dpp::consensus::state::state_error::StateError::InvalidShieldedProofError( dpp::consensus::state::shielded::invalid_shielded_proof_error::InvalidShieldedProofError::new( format!( "shielded pool has insufficient balance: pool has {} but unshield requires {}", @@ -144,43 +124,6 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti )); } - // Serialize transparent fields to bind them to the Orchard sighash. - // This prevents an attacker from substituting a different output_address - // or amount while reusing a valid Orchard bundle. - let mut extra_sighash_data = output_address.to_bytes(); - extra_sighash_data.extend_from_slice(&amount.to_le_bytes()); - - if let Err(e) = reconstruct_and_verify_bundle( - st_actions, - st_flags, - st_value_balance, - &anchor, - st_proof, - st_binding_sig, - &extra_sighash_data, - ) { - let penalty = platform_version - .drive_abci - .validation_and_processing - .penalties - .shielded_proof_verification_failure; - - let penalty_amount = std::cmp::min(penalty, current_total_balance); - - let penalize_action = StateTransitionAction::PenalizeShieldedPoolAction( - PenalizeShieldedPoolAction::from(PenalizeShieldedPoolActionV0 { - penalty_amount, - nullifiers: nullifiers.clone(), - current_total_balance, - }), - ); - - return Ok(ConsensusValidationResult::new_with_data_and_errors( - penalize_action, - vec![StateError::InvalidShieldedProofError(e).into()], - )); - } - let result = UnshieldTransitionAction::try_from_transition( self, nullifiers, diff --git a/packages/rs-drive-abci/src/query/shielded/anchors/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/anchors/v0/mod.rs index de8f9b6bb18..1d8c739db44 100644 --- a/packages/rs-drive-abci/src/query/shielded/anchors/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/shielded/anchors/v0/mod.rs @@ -11,7 +11,7 @@ use dapi_grpc::platform::v0::get_shielded_anchors_response::{ use dpp::check_validation_result_with_data; use dpp::validation::ValidationResult; use dpp::version::PlatformVersion; -use drive::drive::shielded::paths::shielded_anchors_credit_pool_path_vec; +use drive::drive::shielded::paths::shielded_credit_pool_anchors_path_vec; use drive::grovedb::query_result_type::QueryResultType; use drive::grovedb::{PathQuery, Query, SizedQuery}; use drive::util::grove_operations::GroveDBToUse; @@ -24,7 +24,7 @@ impl Platform { platform_version: &PlatformVersion, ) -> Result, Error> { let path_query = PathQuery { - path: shielded_anchors_credit_pool_path_vec(), + path: shielded_credit_pool_anchors_path_vec(), query: SizedQuery { query: Query::new_range_full(), limit: None, @@ -56,10 +56,11 @@ impl Platform { &platform_version.drive, )?; + // Anchors are stored as block_height_be → anchor_bytes; extract values let anchors: Vec> = results .to_key_elements() .into_iter() - .map(|(key, _element)| key) + .filter_map(|(_key, element)| element.into_item_bytes().ok()) .collect(); GetShieldedAnchorsResponseV0 { diff --git a/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs index 234cf187060..1c048fa9960 100644 --- a/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs @@ -13,7 +13,7 @@ use dapi_grpc::platform::v0::get_shielded_encrypted_notes_response::{ use dpp::check_validation_result_with_data; use dpp::validation::ValidationResult; use dpp::version::PlatformVersion; -use drive::drive::shielded::paths::shielded_credit_pool_encrypted_notes_path_vec; +use drive::drive::shielded::paths::shielded_credit_pool_notes_path_vec; use drive::grovedb::query_result_type::QueryResultType; use drive::grovedb::{PathQuery, Query, SizedQuery}; use drive::util::grove_operations::GroveDBToUse; @@ -46,7 +46,7 @@ impl Platform { }; let path_query = PathQuery { - path: shielded_credit_pool_encrypted_notes_path_vec(), + path: shielded_credit_pool_notes_path_vec(), query: SizedQuery { query, limit: Some(limit), diff --git a/packages/rs-drive-abci/tests/strategy_tests/strategy.rs b/packages/rs-drive-abci/tests/strategy_tests/strategy.rs index e6aa03a5a69..0c91649e13e 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/strategy.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/strategy.rs @@ -17,10 +17,9 @@ use dpp::state_transition::unshield_transition::methods::UnshieldTransitionMetho use dpp::state_transition::unshield_transition::UnshieldTransition; use dpp::ProtocolError; use grovedb_commitment_tree::{ - new_memory_store, Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - CommitmentTree, ExtractedNoteCommitment, Flags as OrchardFlags, FullViewingKey, - MemoryCommitmentStore, MerklePath, Note, NoteValue, Position, ProvingKey, Retention, Scope, - SpendAuthorizingKey, SpendingKey, + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, ClientCommitmentTree, + ExtractedNoteCommitment, Flags as OrchardFlags, FullViewingKey, MerklePath, Note, NoteValue, + Position, ProvingKey, Retention, Scope, SpendAuthorizingKey, SpendingKey, }; use orchard::note::RandomSeed; @@ -156,7 +155,7 @@ const TEST_SK_BYTES: [u8; 32] = [0u8; 32]; /// with valid Merkle witnesses. pub struct ShieldedState { /// Local commitment tree mirroring the on-chain tree. - pub tree: CommitmentTree, + pub tree: ClientCommitmentTree, /// Spendable notes: (Note, Position in commitment tree). /// Notes are removed once spent. pub spendable_notes: Vec<(Note, Position)>, @@ -179,7 +178,7 @@ impl ShieldedState { let fvk = FullViewingKey::from(&sk); let ask = SpendAuthorizingKey::from(&sk); Self { - tree: CommitmentTree::new(new_memory_store(), 1000), + tree: ClientCommitmentTree::new(1000), spendable_notes: Vec::new(), checkpoint_counter: 0, sk, @@ -208,7 +207,8 @@ impl ShieldedState { // Append to commitment tree let cmx = ExtractedNoteCommitment::from(note.commitment()); - self.tree.append(cmx, Retention::Marked).unwrap(); + let cmx_bytes: [u8; 32] = cmx.to_bytes(); + self.tree.append(cmx_bytes, Retention::Marked).unwrap(); let position = self.tree.max_leaf_position().unwrap().unwrap(); self.spendable_notes.push((note, position)); @@ -233,7 +233,7 @@ impl ShieldedState { return None; } let (note, position) = self.spendable_notes.remove(0); - let merkle_path = self.tree.orchard_witness(position).ok()??; + let merkle_path = self.tree.witness(position, 0).ok()??; let anchor = self.tree.anchor().ok()?; Some((note, merkle_path, anchor)) } @@ -2953,7 +2953,6 @@ impl NetworkStrategy { anchor_bytes, proof_bytes, binding_sig, - 0, platform_version, ) .expect("expected to create shielded transfer transition"); @@ -3042,7 +3041,6 @@ impl NetworkStrategy { anchor_bytes, proof_bytes, binding_sig, - 0, platform_version, ) .expect("expected to create unshield transition"); @@ -3132,7 +3130,6 @@ impl NetworkStrategy { 1, // core_fee_per_byte Pooling::Never, output_script, - 0, platform_version, ) .expect("expected to create shielded withdrawal transition"); diff --git a/packages/rs-drive/src/drive/identity/contract_info/keys/add_potential_contract_info_for_contract_bounded_key/v0/mod.rs b/packages/rs-drive/src/drive/identity/contract_info/keys/add_potential_contract_info_for_contract_bounded_key/v0/mod.rs index 55fc9ba8013..a8b2a949f83 100644 --- a/packages/rs-drive/src/drive/identity/contract_info/keys/add_potential_contract_info_for_contract_bounded_key/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/contract_info/keys/add_potential_contract_info_for_contract_bounded_key/v0/mod.rs @@ -142,6 +142,7 @@ impl Drive { storage_cost: Default::default(), storage_loaded_bytes: 100, hash_node_calls: 0, + sinsemilla_hash_calls: 0, }, )); None diff --git a/packages/rs-drive/src/drive/identity/contract_info/keys/refresh_potential_contract_info_key_references/v0/mod.rs b/packages/rs-drive/src/drive/identity/contract_info/keys/refresh_potential_contract_info_key_references/v0/mod.rs index 25f20f62385..eddd0c9f029 100644 --- a/packages/rs-drive/src/drive/identity/contract_info/keys/refresh_potential_contract_info_key_references/v0/mod.rs +++ b/packages/rs-drive/src/drive/identity/contract_info/keys/refresh_potential_contract_info_key_references/v0/mod.rs @@ -113,6 +113,7 @@ impl Drive { storage_cost: Default::default(), storage_loaded_bytes: 100, hash_node_calls: 0, + sinsemilla_hash_calls: 0, }, )); None diff --git a/packages/rs-drive/src/drive/initialization/v3/mod.rs b/packages/rs-drive/src/drive/initialization/v3/mod.rs index fc45ad87db3..89fe1742269 100644 --- a/packages/rs-drive/src/drive/initialization/v3/mod.rs +++ b/packages/rs-drive/src/drive/initialization/v3/mod.rs @@ -5,7 +5,6 @@ use crate::drive::{Drive, RootTree}; use crate::error::Error; use crate::util::batch::grovedb_op_batch::GroveDbOpBatchV0Methods; use crate::util::batch::GroveDbOpBatch; -use dpp::shielded::ShieldedPoolParams; use dpp::version::PlatformVersion; use grovedb::{Element, TransactionArg, TreeType}; use grovedb_path::SubtreePath; @@ -79,10 +78,10 @@ impl Drive { Element::empty_sum_tree(), ); - // 2. Commitments tree (CommitmentTree) + // 2. Notes tree (CommitmentTree = CountTree items + Sinsemilla Frontier) batch.add_insert( shielded_credit_pool_path_vec(), - vec![SHIELDED_COMMITMENTS_KEY], + vec![SHIELDED_NOTES_KEY], Element::empty_commitment_tree(), ); @@ -93,42 +92,17 @@ impl Drive { Element::empty_tree(), ); - // 4. Encrypted notes tree (CountTree — count tracks the next sequential index) - batch.add_insert( - shielded_credit_pool_path_vec(), - vec![SHIELDED_ENCRYPTED_NOTES_KEY], - Element::empty_count_tree(), - ); - - // 5. Params item - let initial_params = ShieldedPoolParams::default(); - batch.add_insert( - shielded_credit_pool_path_vec(), - vec![SHIELDED_PARAMS_KEY], - Element::new_item( - bincode::encode_to_vec(&initial_params, bincode::config::standard()) - .expect("expected to encode"), - ), - ); - - // 6. Total balance SumItem(0) + // 4. Total balance SumItem(0) batch.add_insert( shielded_credit_pool_path_vec(), vec![SHIELDED_TOTAL_BALANCE_KEY], Element::new_sum_item(0), ); - // 7. Anchors tree (NormalTree) under AddressBalances + // 5. Anchors tree (NormalTree) inside pool: block_height_be → anchor_bytes batch.add_insert( - vec![vec![RootTree::AddressBalances as u8]], - vec![SHIELDED_ANCHORS_KEY_U8], - Element::empty_tree(), - ); - - // 8. Credit pool anchors tree - batch.add_insert( - shielded_anchors_path_vec(), - SHIELDED_CREDIT_POOL_KEY.to_vec(), + shielded_credit_pool_path_vec(), + vec![SHIELDED_ANCHORS_IN_POOL_KEY], Element::empty_tree(), ); diff --git a/packages/rs-drive/src/drive/shielded/estimated_costs.rs b/packages/rs-drive/src/drive/shielded/estimated_costs.rs index 1337f7f6d08..435767de497 100644 --- a/packages/rs-drive/src/drive/shielded/estimated_costs.rs +++ b/packages/rs-drive/src/drive/shielded/estimated_costs.rs @@ -1,119 +1,134 @@ use crate::drive::shielded::paths::{ - shielded_anchors_credit_pool_path, shielded_anchors_path, - shielded_credit_pool_commitments_path, shielded_credit_pool_encrypted_notes_path, + shielded_credit_pool_anchors_path, shielded_credit_pool_notes_path, shielded_credit_pool_nullifiers_path, shielded_credit_pool_path, }; -use crate::drive::Drive; +use crate::drive::{Drive, RootTree}; use grovedb::batch::KeyInfoPath; use grovedb::EstimatedLayerCount::EstimatedLevel; use grovedb::EstimatedLayerSizes::{AllItems, AllSubtrees, Mix}; -use grovedb::EstimatedSumTrees::{NoSumTrees, SomeSumTrees}; +use grovedb::EstimatedSumTrees::SomeSumTrees; use grovedb::{EstimatedLayerInformation, TreeType}; use std::collections::HashMap; -/// Average size of an encrypted note value: 32 cmx + 216 encrypted note = 248 bytes -const AVERAGE_ENCRYPTED_NOTE_VALUE_SIZE: u32 = 248; +/// Average size of a note value: 32 cmx + 692 encrypted note = 724 bytes +const AVERAGE_NOTE_VALUE_SIZE: u32 = 724; -/// Size of a commitment or nullifier key (32 bytes) -const COMMITMENT_KEY_SIZE: u8 = 32; +/// Size of a nullifier key (32 bytes) +const NULLIFIER_KEY_SIZE: u8 = 32; -/// Size of an encrypted notes index key (u64 big-endian = 8 bytes) -const ENCRYPTED_NOTE_INDEX_KEY_SIZE: u8 = 8; +/// Size of an anchor block height key (u64 big-endian = 8 bytes) +const ANCHOR_KEY_SIZE: u8 = 8; -/// Size of an anchor key (32 bytes) -const ANCHOR_KEY_SIZE: u8 = 32; +/// Size of an anchor value (32 bytes) +const ANCHOR_VALUE_SIZE: u32 = 32; impl Drive { /// Adds estimation costs for shielded pool operations. /// /// Registers all shielded pool tree paths in the estimation cache so that /// the fee estimation system can calculate costs for shielded operations. + /// Also registers parent paths (root and AddressBalances) needed by the + /// GroveDB cost estimation system. pub(crate) fn add_estimation_costs_for_shielded_pool_operations( estimated_costs_only_with_layer_info: &mut HashMap, ) { + // Root level: [] — needed so GroveDB can estimate traversal to AddressBalances + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_path([]), + EstimatedLayerInformation { + tree_type: TreeType::NormalTree, + estimated_layer_count: EstimatedLevel(3, false), + estimated_layer_sizes: AllSubtrees( + 1, + SomeSumTrees { + sum_trees_weight: 2, + big_sum_trees_weight: 0, + count_trees_weight: 0, + count_sum_trees_weight: 0, + non_sum_trees_weight: 2, + }, + None, + ), + }, + ); + + // AddressBalances level: [[56]] — parent of shielded pool subtree + estimated_costs_only_with_layer_info.insert( + KeyInfoPath::from_known_owned_path(vec![vec![RootTree::AddressBalances as u8]]), + EstimatedLayerInformation { + tree_type: TreeType::SumTree, + estimated_layer_count: EstimatedLevel(2, false), + estimated_layer_sizes: AllSubtrees( + 1, + SomeSumTrees { + sum_trees_weight: 1, + big_sum_trees_weight: 0, + count_trees_weight: 0, + count_sum_trees_weight: 1, + non_sum_trees_weight: 0, + }, + None, + ), + }, + ); + // Shielded credit pool: [AddressBalances, "s"] - // SumTree containing: commitments tree (CommitmentTree), nullifiers tree (NormalTree), - // encrypted notes tree (NormalTree), params item, total balance sum item + // SumTree containing: notes (CommitmentTree), nullifiers (NormalTree), + // total balance (SumItem), anchors (NormalTree) estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(shielded_credit_pool_path()), EstimatedLayerInformation { tree_type: TreeType::SumTree, - estimated_layer_count: EstimatedLevel(5, false), + estimated_layer_count: EstimatedLevel(4, false), estimated_layer_sizes: Mix { subtrees_size: Some(( 1, SomeSumTrees { sum_trees_weight: 0, big_sum_trees_weight: 0, - count_trees_weight: 1, + count_trees_weight: 0, count_sum_trees_weight: 0, - non_sum_trees_weight: 2, + non_sum_trees_weight: 2, // nullifiers + anchors }, None, - 3, // 3 subtrees: commitments, nullifiers, encrypted notes + 3, // 3 subtrees: notes (CommitmentTree), nullifiers, anchors )), - items_size: Some((1, 100, None, 2)), // 2 items: params and total balance + items_size: Some((1, 8, None, 1)), // 1 item: total balance references_size: None, }, }, ); - // Commitments tree: [AddressBalances, "s", 1] - // CommitmentTree - stores Orchard note commitments + // Notes tree: [AddressBalances, "s", 1] + // CommitmentTree - stores notes (cmx||encrypted_note items + Sinsemilla frontier) estimated_costs_only_with_layer_info.insert( - KeyInfoPath::from_known_path(shielded_credit_pool_commitments_path()), + KeyInfoPath::from_known_path(shielded_credit_pool_notes_path()), EstimatedLayerInformation { tree_type: TreeType::CommitmentTree, estimated_layer_count: EstimatedLevel(10, false), - estimated_layer_sizes: AllItems(COMMITMENT_KEY_SIZE, 32, None), + estimated_layer_sizes: AllItems(8, AVERAGE_NOTE_VALUE_SIZE, None), }, ); // Nullifiers tree: [AddressBalances, "s", 2] - // NormalTree - stores spent nullifiers (32-byte key → empty item) + // NormalTree - stores spent nullifiers (32-byte key -> empty item) estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(shielded_credit_pool_nullifiers_path()), EstimatedLayerInformation { tree_type: TreeType::NormalTree, estimated_layer_count: EstimatedLevel(10, false), - estimated_layer_sizes: AllItems(COMMITMENT_KEY_SIZE, 0, None), + estimated_layer_sizes: AllItems(NULLIFIER_KEY_SIZE, 0, None), }, ); - // Encrypted notes tree: [AddressBalances, "s", 3] - // CountTree - stores encrypted notes (8-byte u64 index key → 248-byte cmx+encrypted_note) + // Anchors tree: [AddressBalances, "s", 6] + // NormalTree - stores block_height_be -> anchor_bytes estimated_costs_only_with_layer_info.insert( - KeyInfoPath::from_known_path(shielded_credit_pool_encrypted_notes_path()), - EstimatedLayerInformation { - tree_type: TreeType::CountTree, - estimated_layer_count: EstimatedLevel(10, false), - estimated_layer_sizes: AllItems( - ENCRYPTED_NOTE_INDEX_KEY_SIZE, - AVERAGE_ENCRYPTED_NOTE_VALUE_SIZE, - None, - ), - }, - ); - - // Anchors tree: [AddressBalances, "a"] - // NormalTree - contains subtrees per pool type - estimated_costs_only_with_layer_info.insert( - KeyInfoPath::from_known_path(shielded_anchors_path()), + KeyInfoPath::from_known_path(shielded_credit_pool_anchors_path()), EstimatedLayerInformation { tree_type: TreeType::NormalTree, - estimated_layer_count: EstimatedLevel(1, false), - estimated_layer_sizes: AllSubtrees(1, NoSumTrees, None), - }, - ); - - // Anchors credit pool tree: [AddressBalances, "a", "s"] - // NormalTree - stores anchor hashes (32-byte key → empty item) - estimated_costs_only_with_layer_info.insert( - KeyInfoPath::from_known_path(shielded_anchors_credit_pool_path()), - EstimatedLayerInformation { - tree_type: TreeType::NormalTree, - estimated_layer_count: EstimatedLevel(10, false), - estimated_layer_sizes: AllItems(ANCHOR_KEY_SIZE, 0, None), + estimated_layer_count: EstimatedLevel(7, false), + estimated_layer_sizes: AllItems(ANCHOR_KEY_SIZE, ANCHOR_VALUE_SIZE, None), }, ); } diff --git a/packages/rs-drive/src/drive/shielded/paths.rs b/packages/rs-drive/src/drive/shielded/paths.rs index 8318179042c..dabe5d37eee 100644 --- a/packages/rs-drive/src/drive/shielded/paths.rs +++ b/packages/rs-drive/src/drive/shielded/paths.rs @@ -6,27 +6,18 @@ pub const SHIELDED_CREDIT_POOL_KEY: &[u8; 1] = b"s"; /// The subtree key for the shielded credit pool as a u8 pub const SHIELDED_CREDIT_POOL_KEY_U8: u8 = b's'; -/// The subtree key for the shielded anchors under AddressBalances -pub const SHIELDED_ANCHORS_KEY: &[u8; 1] = b"a"; - -/// The subtree key for the shielded anchors as a u8 -pub const SHIELDED_ANCHORS_KEY_U8: u8 = b'a'; - -/// Key for the commitments tree inside a shielded pool -pub const SHIELDED_COMMITMENTS_KEY: u8 = 1; +/// Key for the notes tree (CommitmentTree) inside a shielded pool +pub const SHIELDED_NOTES_KEY: u8 = 1; /// Key for the nullifiers tree inside a shielded pool pub const SHIELDED_NULLIFIERS_KEY: u8 = 2; -/// Key for the encrypted notes tree inside a shielded pool -pub const SHIELDED_ENCRYPTED_NOTES_KEY: u8 = 3; - -/// Key for the params item inside a shielded pool -pub const SHIELDED_PARAMS_KEY: u8 = 4; - /// Key for the total balance sum item inside a shielded pool pub const SHIELDED_TOTAL_BALANCE_KEY: u8 = 5; +/// Key for the anchors tree inside a shielded pool +pub const SHIELDED_ANCHORS_IN_POOL_KEY: u8 = 6; + /// Path to the shielded credit pool: [AddressBalances, "s"] pub fn shielded_credit_pool_path() -> [&'static [u8]; 2] { [ @@ -43,55 +34,30 @@ pub fn shielded_credit_pool_path_vec() -> Vec> { ] } -/// Path to the commitments tree: [AddressBalances, "s", [1]] -pub fn shielded_credit_pool_commitments_path() -> [&'static [u8]; 3] { +/// Path to the notes tree: [AddressBalances, "s", [1]] +pub fn shielded_credit_pool_notes_path() -> [&'static [u8]; 3] { [ Into::<&[u8; 1]>::into(RootTree::AddressBalances), SHIELDED_CREDIT_POOL_KEY, - &[SHIELDED_COMMITMENTS_KEY], + &[SHIELDED_NOTES_KEY], ] } -/// Path to the nullifiers tree: [AddressBalances, "s", [2]] -pub fn shielded_credit_pool_nullifiers_path() -> [&'static [u8]; 3] { - [ - Into::<&[u8; 1]>::into(RootTree::AddressBalances), - SHIELDED_CREDIT_POOL_KEY, - &[SHIELDED_NULLIFIERS_KEY], +/// Path to the notes tree as a vec: [AddressBalances, "s", [1]] +pub fn shielded_credit_pool_notes_path_vec() -> Vec> { + vec![ + vec![RootTree::AddressBalances as u8], + SHIELDED_CREDIT_POOL_KEY.to_vec(), + vec![SHIELDED_NOTES_KEY], ] } -/// Path to the encrypted notes tree: [AddressBalances, "s", [3]] -pub fn shielded_credit_pool_encrypted_notes_path() -> [&'static [u8]; 3] { +/// Path to the nullifiers tree: [AddressBalances, "s", [2]] +pub fn shielded_credit_pool_nullifiers_path() -> [&'static [u8]; 3] { [ Into::<&[u8; 1]>::into(RootTree::AddressBalances), SHIELDED_CREDIT_POOL_KEY, - &[SHIELDED_ENCRYPTED_NOTES_KEY], - ] -} - -/// Path to the anchors tree: [AddressBalances, "a"] -pub fn shielded_anchors_path() -> [&'static [u8]; 2] { - [ - Into::<&[u8; 1]>::into(RootTree::AddressBalances), - SHIELDED_ANCHORS_KEY, - ] -} - -/// Path to the anchors tree as a vec -pub fn shielded_anchors_path_vec() -> Vec> { - vec![ - vec![RootTree::AddressBalances as u8], - SHIELDED_ANCHORS_KEY.to_vec(), - ] -} - -/// Path to the commitments tree as a vec: [AddressBalances, "s", [1]] -pub fn shielded_credit_pool_commitments_path_vec() -> Vec> { - vec![ - vec![RootTree::AddressBalances as u8], - SHIELDED_CREDIT_POOL_KEY.to_vec(), - vec![SHIELDED_COMMITMENTS_KEY], + &[SHIELDED_NULLIFIERS_KEY], ] } @@ -104,29 +70,20 @@ pub fn shielded_credit_pool_nullifiers_path_vec() -> Vec> { ] } -/// Path to the encrypted notes tree as a vec: [AddressBalances, "s", [3]] -pub fn shielded_credit_pool_encrypted_notes_path_vec() -> Vec> { - vec![ - vec![RootTree::AddressBalances as u8], - SHIELDED_CREDIT_POOL_KEY.to_vec(), - vec![SHIELDED_ENCRYPTED_NOTES_KEY], +/// Path to the anchors tree: [AddressBalances, "s", [6]] +pub fn shielded_credit_pool_anchors_path() -> [&'static [u8]; 3] { + [ + Into::<&[u8; 1]>::into(RootTree::AddressBalances), + SHIELDED_CREDIT_POOL_KEY, + &[SHIELDED_ANCHORS_IN_POOL_KEY], ] } -/// Path to the anchors credit pool as a vec: [AddressBalances, "a", "s"] -pub fn shielded_anchors_credit_pool_path_vec() -> Vec> { +/// Path to the anchors tree as a vec: [AddressBalances, "s", [6]] +pub fn shielded_credit_pool_anchors_path_vec() -> Vec> { vec![ vec![RootTree::AddressBalances as u8], - SHIELDED_ANCHORS_KEY.to_vec(), SHIELDED_CREDIT_POOL_KEY.to_vec(), - ] -} - -/// Path to the credit pool anchors: [AddressBalances, "a", "s"] -pub fn shielded_anchors_credit_pool_path() -> [&'static [u8]; 3] { - [ - Into::<&[u8; 1]>::into(RootTree::AddressBalances), - SHIELDED_ANCHORS_KEY, - SHIELDED_CREDIT_POOL_KEY, + vec![SHIELDED_ANCHORS_IN_POOL_KEY], ] } diff --git a/packages/rs-drive/src/fees/op.rs b/packages/rs-drive/src/fees/op.rs index b2429a6c035..a5c016eacb2 100644 --- a/packages/rs-drive/src/fees/op.rs +++ b/packages/rs-drive/src/fees/op.rs @@ -580,6 +580,13 @@ impl LowLevelDriveOperationTreeTypeConverter for TreeType { Element::empty_provable_count_sum_tree_with_flags(element_flags) } TreeType::CommitmentTree => Element::empty_commitment_tree_with_flags(element_flags), + TreeType::MmrTree => Element::empty_mmr_tree_with_flags(element_flags), + TreeType::BulkAppendTree => { + Element::empty_bulk_append_tree_with_flags(4, element_flags) + } + TreeType::DenseAppendOnlyFixedSizeTree => { + Element::empty_dense_tree_with_flags(8, element_flags) + } }; LowLevelDriveOperation::insert_for_known_path_key_element(path, key, element) @@ -600,6 +607,7 @@ impl DriveCost for OperationCost { storage_cost, storage_loaded_bytes, hash_node_calls, + sinsemilla_hash_calls, } = self; let epoch_cost_for_processing_credit_per_byte = fee_version.storage.storage_processing_credit_per_byte; @@ -625,12 +633,14 @@ impl DriveCost for OperationCost { let blake3_total = fee_version.hashing.blake3_base + fee_version.hashing.blake3_per_block; // this can't overflow let hash_node_cost = blake3_total * (*hash_node_calls as u64); + let sinsemilla_cost = fee_version.hashing.sinsemilla_base * (*sinsemilla_hash_calls as u64); seek_cost .checked_add(storage_added_bytes_ephemeral_cost) .and_then(|c| c.checked_add(storage_replaced_bytes_ephemeral_cost)) .and_then(|c| c.checked_add(storage_loaded_bytes_cost)) .and_then(|c| c.checked_add(storage_removed_bytes_ephemeral_cost)) .and_then(|c| c.checked_add(hash_node_cost)) + .and_then(|c| c.checked_add(sinsemilla_cost)) .ok_or_else(|| get_overflow_error("ephemeral cost addition overflow")) } } diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs index ee4b02f91be..06ddcb76633 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs @@ -4,38 +4,8 @@ mod shielded_transfer_transition; mod shielded_withdrawal_transition; mod unshield_transition; -use crate::util::batch::drive_op_batch::finalize_task::DriveOperationFinalizeTask; use crate::util::batch::drive_op_batch::ShieldedPoolOperationType; use crate::util::batch::DriveOperation; -use grovedb::Element; - -/// Build the encrypted note items (cmx || encrypted_note) for auto-incremented insertion. -fn build_encrypted_note_items( - note_commitments: &[[u8; 32]], - encrypted_notes: &[Vec], -) -> Vec { - note_commitments - .iter() - .zip(encrypted_notes.iter()) - .map(|(cmx, encrypted_note)| { - let mut value = cmx.to_vec(); - value.extend_from_slice(encrypted_note); - Element::new_item(value) - }) - .collect() -} - -/// Append each note commitment to the commitment tree. -pub(super) fn append_note_commitments<'a>( - ops: &mut Vec>, - note_commitments: &[[u8; 32]], -) { - for cmx in note_commitments.iter() { - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::AppendNoteCommitment { cmx: *cmx }, - )); - } -} /// Insert each nullifier (InsertOnly to prevent double-spend). pub(super) fn insert_nullifiers<'a>(ops: &mut Vec>, nullifiers: &[[u8; 32]]) { @@ -48,28 +18,25 @@ pub(super) fn insert_nullifiers<'a>(ops: &mut Vec>, nullifier } } -/// Insert encrypted notes with auto-incremented keys in count tree. -pub(super) fn insert_encrypted_notes<'a>( +/// Insert notes into the CommitmentTree (appends cmx to frontier + stores cmx||encrypted_note). +pub(super) fn insert_notes<'a>( ops: &mut Vec>, note_commitments: &[[u8; 32]], encrypted_notes: &[Vec], ) { - ops.push(DriveOperation::ShieldedPoolOperation( - ShieldedPoolOperationType::InsertEncryptedNotes { - items: build_encrypted_note_items(note_commitments, encrypted_notes), - }, - )); + for (cmx, encrypted_note) in note_commitments.iter().zip(encrypted_notes.iter()) { + ops.push(DriveOperation::ShieldedPoolOperation( + ShieldedPoolOperationType::InsertNote { + cmx: *cmx, + encrypted_note: encrypted_note.clone(), + }, + )); + } } -/// Update pool total balance and record shielded anchor. -pub(super) fn update_balance_and_record_anchor<'a>( - ops: &mut Vec>, - new_total_balance: u64, -) { +/// Update pool total balance. +pub(super) fn update_balance<'a>(ops: &mut Vec>, new_total_balance: u64) { ops.push(DriveOperation::ShieldedPoolOperation( ShieldedPoolOperationType::UpdateTotalBalance { new_total_balance }, )); - ops.push(DriveOperation::FinalizeOperation( - DriveOperationFinalizeTask::RecordShieldedAnchor, - )); } diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_from_asset_lock_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_from_asset_lock_transition.rs index 26a9aedd634..6859b0c1431 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_from_asset_lock_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_from_asset_lock_transition.rs @@ -1,4 +1,4 @@ -use super::{append_note_commitments, insert_encrypted_notes, update_balance_and_record_anchor}; +use super::{insert_notes, update_balance}; use crate::error::drive::DriveError; use crate::error::Error; use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; @@ -49,13 +49,10 @@ impl DriveHighLevelOperationConverter for ShieldFromAssetLockTransitionAction { }, )); - // 3. Append note commitments to commitment tree - append_note_commitments(&mut ops, &v0.note_commitments); + // 3. Insert notes into CommitmentTree + insert_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); - // 4. Insert encrypted notes with auto-incremented keys in count tree - insert_encrypted_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); - - // 5. Update total balance and record anchor + // 4. Update total balance let new_total_balance = v0.current_total_balance .checked_add(v0.shield_amount) @@ -65,7 +62,7 @@ impl DriveHighLevelOperationConverter for ShieldFromAssetLockTransitionAction { .to_string(), )) })?; - update_balance_and_record_anchor(&mut ops, new_total_balance); + update_balance(&mut ops, new_total_balance); Ok(ops) } diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_transition.rs index b6b5a06fdc6..38ca067b8eb 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_transition.rs @@ -1,4 +1,4 @@ -use super::{append_note_commitments, insert_encrypted_notes, update_balance_and_record_anchor}; +use super::{insert_notes, update_balance}; use crate::error::drive::DriveError; use crate::error::Error; use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; @@ -36,13 +36,10 @@ impl DriveHighLevelOperationConverter for ShieldTransitionAction { )); } - // 2. Append each note commitment to the commitment tree - append_note_commitments(&mut ops, &v0.note_commitments); + // 2. Insert notes into CommitmentTree + insert_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); - // 3. Insert encrypted notes with auto-incremented keys in count tree - insert_encrypted_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); - - // 4. Update total balance and record anchor + // 3. Update total balance let new_total_balance = v0 .current_total_balance .checked_add(v0.shield_amount) @@ -52,7 +49,7 @@ impl DriveHighLevelOperationConverter for ShieldTransitionAction { .to_string(), )) })?; - update_balance_and_record_anchor(&mut ops, new_total_balance); + update_balance(&mut ops, new_total_balance); Ok(ops) } diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs index 5b5043390ba..497af111301 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs @@ -1,7 +1,4 @@ -use super::{ - append_note_commitments, insert_encrypted_notes, insert_nullifiers, - update_balance_and_record_anchor, -}; +use super::{insert_notes, insert_nullifiers, update_balance}; use crate::error::drive::DriveError; use crate::error::Error; use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; @@ -30,13 +27,10 @@ impl DriveHighLevelOperationConverter for ShieldedTransferTransitionAction { // 1. Insert each nullifier (InsertOnly to prevent double-spend) insert_nullifiers(&mut ops, &v0.nullifiers); - // 2. Append each note commitment to the commitment tree - append_note_commitments(&mut ops, &v0.note_commitments); + // 2. Insert notes into CommitmentTree + insert_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); - // 3. Insert encrypted notes with auto-incremented keys in count tree - insert_encrypted_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); - - // 4. Update total balance and record anchor + // 3. Update total balance (pool decreases by fee_amount) let new_total_balance = v0 .current_total_balance .checked_sub(v0.fee_amount) @@ -46,7 +40,7 @@ impl DriveHighLevelOperationConverter for ShieldedTransferTransitionAction { .to_string(), )) })?; - update_balance_and_record_anchor(&mut ops, new_total_balance); + update_balance(&mut ops, new_total_balance); Ok(ops) } diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs index b617411cd01..564c1c04936 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs @@ -1,7 +1,4 @@ -use super::{ - append_note_commitments, insert_encrypted_notes, insert_nullifiers, - update_balance_and_record_anchor, -}; +use super::{insert_notes, insert_nullifiers, update_balance}; use crate::error::drive::DriveError; use crate::error::Error; use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; @@ -32,25 +29,29 @@ impl DriveHighLevelOperationConverter for ShieldedWithdrawalTransitionAction { // 1. Insert nullifiers (prevent double-spend) insert_nullifiers(&mut ops, &v0.nullifiers); - // 2. Append change note commitments to commitment tree - append_note_commitments(&mut ops, &v0.note_commitments); + // 2. Insert change notes into CommitmentTree + insert_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); - // 3. Insert encrypted change notes with auto-incremented keys in count tree - insert_encrypted_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); - - // 4. Update total balance: subtract withdrawal amount + // 3. Update total balance: subtract withdrawal amount + fee (both leave the pool) + let total_deduction = + v0.amount.checked_add(v0.fee_amount).ok_or_else(|| { + Error::Drive(DriveError::CorruptedDriveState( + "overflow when adding shielded_withdrawal amount and fee" + .to_string(), + )) + })?; let new_total_balance = v0.current_total_balance - .checked_sub(v0.amount) + .checked_sub(total_deduction) .ok_or_else(|| { Error::Drive(DriveError::CorruptedDriveState( - "shielded pool total balance underflow when subtracting shielded_withdrawal amount" + "shielded pool total balance underflow when subtracting shielded_withdrawal amount and fee" .to_string(), )) })?; - update_balance_and_record_anchor(&mut ops, new_total_balance); + update_balance(&mut ops, new_total_balance); - // 5. Add withdrawal document + // 4. Add withdrawal document ops.push(DriveOperation::DocumentOperation( DocumentOperationType::AddWithdrawalDocument { owned_document_info: OwnedDocumentInfo { @@ -63,7 +64,7 @@ impl DriveHighLevelOperationConverter for ShieldedWithdrawalTransitionAction { }, )); - // 6. Remove credits from system (they leave the system to Core) + // 5. Remove credits from system (they leave the system to Core) ops.push(DriveOperation::SystemOperation( SystemOperationType::RemoveFromSystemCredits { amount: v0.amount }, )); diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs index a63a820baa5..17a12dd35da 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs @@ -1,7 +1,4 @@ -use super::{ - append_note_commitments, insert_encrypted_notes, insert_nullifiers, - update_balance_and_record_anchor, -}; +use super::{insert_notes, insert_nullifiers, update_balance}; use crate::error::drive::DriveError; use crate::error::Error; use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; @@ -39,23 +36,27 @@ impl DriveHighLevelOperationConverter for UnshieldTransitionAction { }, )); - // 3. Append each note commitment (change outputs) to the commitment tree - append_note_commitments(&mut ops, &v0.note_commitments); + // 3. Insert notes into CommitmentTree (change outputs) + insert_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); - // 4. Insert encrypted notes with auto-incremented keys in count tree - insert_encrypted_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); - - // 5. Update total balance and record anchor + // 4. Update total balance + // Pool decreases by amount (to output address) + fee_amount (to proposers) + let total_deduction = + v0.amount.checked_add(v0.fee_amount).ok_or_else(|| { + Error::Drive(DriveError::CorruptedDriveState( + "overflow when adding unshield amount and fee".to_string(), + )) + })?; let new_total_balance = v0.current_total_balance - .checked_sub(v0.amount) + .checked_sub(total_deduction) .ok_or_else(|| { Error::Drive(DriveError::CorruptedDriveState( - "shielded pool total balance underflow when subtracting unshield amount" + "shielded pool total balance underflow when subtracting unshield amount and fee" .to_string(), )) })?; - update_balance_and_record_anchor(&mut ops, new_total_balance); + update_balance(&mut ops, new_total_balance); Ok(ops) } diff --git a/packages/rs-drive/src/state_transition_action/mod.rs b/packages/rs-drive/src/state_transition_action/mod.rs index 0e658f3ed72..59b51b03512 100644 --- a/packages/rs-drive/src/state_transition_action/mod.rs +++ b/packages/rs-drive/src/state_transition_action/mod.rs @@ -156,10 +156,16 @@ impl StateTransitionAction { action.user_fee_increase() } StateTransitionAction::ShieldAction(action) => action.user_fee_increase(), - StateTransitionAction::ShieldedTransferAction(action) => action.user_fee_increase(), - StateTransitionAction::UnshieldAction(action) => action.user_fee_increase(), + StateTransitionAction::ShieldedTransferAction(_) => { + UserFeeIncrease::default() // 0 (fee is locked by Orchard binding signature) + } + StateTransitionAction::UnshieldAction(_) => { + UserFeeIncrease::default() // 0 (fee is locked by Orchard binding signature) + } StateTransitionAction::ShieldFromAssetLockAction(action) => action.user_fee_increase(), - StateTransitionAction::ShieldedWithdrawalAction(action) => action.user_fee_increase(), + StateTransitionAction::ShieldedWithdrawalAction(_) => { + UserFeeIncrease::default() // 0 (fee is locked by Orchard binding signature) + } StateTransitionAction::PenalizeShieldedPoolAction(_) => { UserFeeIncrease::default() // 0 (no user fee increase for penalty actions) } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/mod.rs index ee59e530ad7..8972d0e2366 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/mod.rs @@ -6,7 +6,6 @@ pub mod v0; use crate::state_transition_action::shielded::shielded_transfer::v0::ShieldedTransferTransitionActionV0; use derive_more::From; use dpp::fee::Credits; -use dpp::prelude::UserFeeIncrease; /// Shielded transfer transition action #[derive(Debug, Clone, From)] @@ -46,10 +45,4 @@ impl ShieldedTransferTransitionAction { ShieldedTransferTransitionAction::V0(transition) => transition.fee_amount, } } - /// fee multiplier - pub fn user_fee_increase(&self) -> UserFeeIncrease { - match self { - ShieldedTransferTransitionAction::V0(transition) => transition.user_fee_increase, - } - } } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs index 0ff42384677..d3ef8cd05f9 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs @@ -1,7 +1,6 @@ mod transformer; use dpp::fee::Credits; -use dpp::prelude::UserFeeIncrease; /// Shielded transfer transition action v0 #[derive(Debug, Clone)] @@ -16,8 +15,6 @@ pub struct ShieldedTransferTransitionActionV0 { pub anchor: [u8; 32], /// Fee amount extracted from the value balance pub fee_amount: Credits, - /// fee multiplier - pub user_fee_increase: UserFeeIncrease, /// Current total balance of the shielded pool pub current_total_balance: Credits, } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs index 32010f40835..482c9de6de2 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs @@ -6,7 +6,7 @@ use dpp::state_transition::state_transitions::shielded::shielded_transfer_transi impl ShieldedTransferTransitionActionV0 { /// Transforms the shielded transfer transition into an action pub fn try_from_transition( - value: &ShieldedTransferTransitionV0, + _value: &ShieldedTransferTransitionV0, nullifiers: Vec<[u8; 32]>, note_commitments: Vec<[u8; 32]>, encrypted_notes: Vec>, @@ -20,7 +20,6 @@ impl ShieldedTransferTransitionActionV0 { encrypted_notes, anchor, fee_amount, - user_fee_increase: value.user_fee_increase, current_total_balance, }) } diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/mod.rs index 6838f0dbef8..61fdeaf61b0 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/mod.rs @@ -8,7 +8,6 @@ use derive_more::From; use dpp::document::Document; use dpp::fee::Credits; use dpp::identity::core_script::CoreScript; -use dpp::prelude::UserFeeIncrease; use dpp::withdrawal::Pooling; /// Shielded withdrawal transition action @@ -67,10 +66,10 @@ impl ShieldedWithdrawalTransitionAction { ShieldedWithdrawalTransitionAction::V0(transition) => &transition.output_script, } } - /// fee multiplier - pub fn user_fee_increase(&self) -> UserFeeIncrease { + /// Fee amount (value_balance - amount), paid to proposers + pub fn fee_amount(&self) -> Credits { match self { - ShieldedWithdrawalTransitionAction::V0(transition) => transition.user_fee_increase, + ShieldedWithdrawalTransitionAction::V0(transition) => transition.fee_amount, } } /// Get prepared withdrawal document diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/mod.rs index 9f2e4f465cf..f865b15d31c 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/mod.rs @@ -3,7 +3,6 @@ mod transformer; use dpp::document::Document; use dpp::fee::Credits; use dpp::identity::core_script::CoreScript; -use dpp::prelude::UserFeeIncrease; use dpp::withdrawal::Pooling; /// Shielded withdrawal transition action v0 @@ -25,8 +24,8 @@ pub struct ShieldedWithdrawalTransitionActionV0 { pub pooling: Pooling, /// Core address receiving funds pub output_script: CoreScript, - /// fee multiplier - pub user_fee_increase: UserFeeIncrease, + /// Fee amount (value_balance - amount), paid to proposers + pub fee_amount: Credits, /// Current total balance of the shielded pool pub current_total_balance: Credits, /// Pre-built withdrawal document (status: QUEUED) diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/transformer.rs index 94d9199e2d7..15e0d18e1c2 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/transformer.rs @@ -63,6 +63,9 @@ impl ShieldedWithdrawalTransitionActionV0 { } .into(); + // fee_amount = value_balance - amount (validated to be >= 0 in structure validation) + let fee_amount = (value.value_balance as u64).saturating_sub(value.amount); + ConsensusValidationResult::new_with_data(ShieldedWithdrawalTransitionActionV0 { amount: value.amount, nullifiers, @@ -72,7 +75,7 @@ impl ShieldedWithdrawalTransitionActionV0 { core_fee_per_byte: value.core_fee_per_byte, pooling: value.pooling, output_script: value.output_script.clone(), - user_fee_increase: value.user_fee_increase, + fee_amount, current_total_balance, prepared_withdrawal_document: withdrawal_document, }) diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/mod.rs index 3c5b3d1f150..84ad9d9d6d9 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/unshield/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/mod.rs @@ -7,7 +7,6 @@ use crate::state_transition_action::shielded::unshield::v0::UnshieldTransitionAc use derive_more::From; use dpp::address_funds::PlatformAddress; use dpp::fee::Credits; -use dpp::prelude::UserFeeIncrease; /// Unshield transition action #[derive(Debug, Clone, From)] @@ -53,10 +52,10 @@ impl UnshieldTransitionAction { UnshieldTransitionAction::V0(transition) => &transition.anchor, } } - /// fee multiplier - pub fn user_fee_increase(&self) -> UserFeeIncrease { + /// Fee amount (value_balance - amount), paid to proposers + pub fn fee_amount(&self) -> Credits { match self { - UnshieldTransitionAction::V0(transition) => transition.user_fee_increase, + UnshieldTransitionAction::V0(transition) => transition.fee_amount, } } } diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs index 7cd7d394e10..c1d4b3f6a1a 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs @@ -2,7 +2,6 @@ mod transformer; use dpp::address_funds::PlatformAddress; use dpp::fee::Credits; -use dpp::prelude::UserFeeIncrease; /// Unshield transition action v0 #[derive(Debug, Clone)] @@ -19,8 +18,8 @@ pub struct UnshieldTransitionActionV0 { pub encrypted_notes: Vec>, /// The anchor used for verification pub anchor: [u8; 32], - /// fee multiplier - pub user_fee_increase: UserFeeIncrease, + /// Fee amount (value_balance - amount), paid to proposers + pub fee_amount: Credits, /// Current total balance of the shielded pool pub current_total_balance: Credits, } diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs index 3611a4e9ab6..2465ae299b3 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs @@ -13,6 +13,9 @@ impl UnshieldTransitionActionV0 { anchor: [u8; 32], current_total_balance: Credits, ) -> ConsensusValidationResult { + // fee_amount = value_balance - amount (validated to be >= 0 in structure validation) + let fee_amount = (value.value_balance as u64).saturating_sub(value.amount); + ConsensusValidationResult::new_with_data(UnshieldTransitionActionV0 { output_address: value.output_address.clone(), amount: value.amount, @@ -20,7 +23,7 @@ impl UnshieldTransitionActionV0 { note_commitments, encrypted_notes, anchor, - user_fee_increase: value.user_fee_increase, + fee_amount, current_total_balance, }) } diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs b/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs index eaee1184145..270b34bfb46 100644 --- a/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs +++ b/packages/rs-drive/src/util/batch/drive_op_batch/finalize_task.rs @@ -1,21 +1,12 @@ -use crate::drive::shielded::paths::{ - shielded_anchors_credit_pool_path, shielded_credit_pool_path, SHIELDED_COMMITMENTS_KEY, - SHIELDED_PARAMS_KEY, -}; use crate::drive::Drive; use crate::error::Error; use dpp::prelude::Identifier; -use dpp::shielded::ShieldedPoolParams; use dpp::version::PlatformVersion; -use grovedb::{Element, TransactionArg}; +use grovedb::TransactionArg; #[derive(Clone, Debug)] pub enum DriveOperationFinalizeTask { - RemoveDataContractFromCache { - contract_id: Identifier, - }, - /// Record the current commitment tree root hash as a new anchor - RecordShieldedAnchor, + RemoveDataContractFromCache { contract_id: Identifier }, } /// Enable callbacks for drive operations that will be called after successful execution @@ -31,119 +22,14 @@ impl DriveOperationFinalizeTask { pub fn execute( self, drive: &Drive, - transaction: TransactionArg, - platform_version: &PlatformVersion, + _transaction: TransactionArg, + _platform_version: &PlatformVersion, ) -> Result<(), Error> { match self { DriveOperationFinalizeTask::RemoveDataContractFromCache { contract_id } => { drive.cache.data_contracts.remove(contract_id.to_buffer()); Ok(()) } - DriveOperationFinalizeTask::RecordShieldedAnchor => { - let grove_version = &platform_version.drive.grove_version; - let pool_path = shielded_credit_pool_path(); - - // Read current checkpoint_id_counter from ShieldedPoolParams - let params_element = drive - .grove - .get( - &pool_path, - &[SHIELDED_PARAMS_KEY], - transaction, - grove_version, - ) - .unwrap() - .map_err(Error::from)?; - - let params_bytes = match ¶ms_element { - Element::Item(data, _) => data.as_slice(), - _ => { - return Err(Error::Drive( - crate::error::drive::DriveError::CorruptedElementType( - "shielded pool params should be an Item", - ), - )) - } - }; - - let (params, _): (ShieldedPoolParams, _) = - bincode::decode_from_slice(params_bytes, bincode::config::standard()).map_err( - |e| { - Error::Drive(crate::error::drive::DriveError::CorruptedSerialization( - format!("could not decode shielded pool params: {e}"), - )) - }, - )?; - - let new_checkpoint_id = params.checkpoint_id_counter + 1; - - // Create a checkpoint in the commitment tree - drive - .grove - .commitment_tree_checkpoint( - &pool_path, - &[SHIELDED_COMMITMENTS_KEY], - new_checkpoint_id, - transaction, - grove_version, - ) - .unwrap() - .map_err(Error::from)?; - - // Get the current root hash (anchor) of the commitment tree - let root_hash = drive - .grove - .commitment_tree_root_hash( - &pool_path, - &[SHIELDED_COMMITMENTS_KEY], - transaction, - grove_version, - ) - .unwrap() - .map_err(Error::from)?; - - // Insert the root hash as an empty Item into the anchors tree - drive - .grove - .insert( - &shielded_anchors_credit_pool_path(), - &root_hash, - Element::Item(vec![], None), - None, - transaction, - grove_version, - ) - .unwrap() - .map_err(Error::from)?; - - // Update ShieldedPoolParams with new checkpoint_id_counter - let new_params = ShieldedPoolParams { - checkpoint_id_counter: new_checkpoint_id, - }; - let encoded_params = - bincode::encode_to_vec(&new_params, bincode::config::standard()).map_err( - |e| { - Error::Drive(crate::error::drive::DriveError::CorruptedSerialization( - format!("could not encode shielded pool params: {e}"), - )) - }, - )?; - - drive - .grove - .insert( - &pool_path, - &[SHIELDED_PARAMS_KEY], - Element::new_item(encoded_params), - None, - transaction, - grove_version, - ) - .unwrap() - .map_err(Error::from)?; - - Ok(()) - } } } } diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs b/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs index 79d817c2aae..d9e9ec1d1c6 100644 --- a/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs +++ b/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs @@ -1,6 +1,6 @@ use crate::drive::shielded::paths::{ - shielded_credit_pool_nullifiers_path_vec, shielded_credit_pool_path_vec, - SHIELDED_COMMITMENTS_KEY, SHIELDED_ENCRYPTED_NOTES_KEY, SHIELDED_TOTAL_BALANCE_KEY, + shielded_credit_pool_nullifiers_path_vec, shielded_credit_pool_path_vec, SHIELDED_NOTES_KEY, + SHIELDED_TOTAL_BALANCE_KEY, }; use crate::drive::Drive; use crate::error::drive::DriveError; @@ -17,10 +17,12 @@ use std::collections::HashMap; /// Operations on the Shielded Pool #[derive(Clone, Debug)] pub enum ShieldedPoolOperationType { - /// Append a note commitment (cmx) to the commitment tree - AppendNoteCommitment { - /// The 32-byte note commitment + /// Insert a note into the CommitmentTree (appends cmx to frontier + stores cmx||payload as item) + InsertNote { + /// The 32-byte note commitment (cmx) cmx: [u8; 32], + /// The encrypted note payload + encrypted_note: Vec, }, /// Insert a nullifier to prevent double-spend InsertNullifier { @@ -32,36 +34,35 @@ pub enum ShieldedPoolOperationType { /// The new total balance value new_total_balance: u64, }, - /// Insert encrypted notes with auto-incremented keys in the count tree - InsertEncryptedNotes { - /// Items to insert: each is cmx (32 bytes) || encrypted_note, packed as Element - items: Vec, - }, } impl DriveLowLevelOperationConverter for ShieldedPoolOperationType { fn into_low_level_drive_operations( self, - drive: &Drive, + _drive: &Drive, estimated_costs_only_with_layer_info: &mut Option< HashMap, >, _block_info: &BlockInfo, - transaction: TransactionArg, - platform_version: &PlatformVersion, + _transaction: TransactionArg, + _platform_version: &PlatformVersion, ) -> Result, Error> { if let Some(ref mut estimated_costs) = estimated_costs_only_with_layer_info { Drive::add_estimation_costs_for_shielded_pool_operations(estimated_costs); } match self { - ShieldedPoolOperationType::AppendNoteCommitment { cmx } => { + ShieldedPoolOperationType::InsertNote { + cmx, + encrypted_note, + } => { let pool_path = shielded_credit_pool_path_vec(); Ok(vec![GroveOperation( - QualifiedGroveDbOp::commitment_tree_append_op( + QualifiedGroveDbOp::commitment_tree_insert_op( pool_path, - vec![SHIELDED_COMMITMENTS_KEY], + vec![SHIELDED_NOTES_KEY], cmx, + encrypted_note, ), )]) } @@ -88,18 +89,6 @@ impl DriveLowLevelOperationConverter for ShieldedPoolOperationType { ), )]) } - ShieldedPoolOperationType::InsertEncryptedNotes { items } => { - let mut ops = vec![]; - drive.batch_insert_auto_incremented_items_in_count_tree( - shielded_credit_pool_path_vec(), - &[SHIELDED_ENCRYPTED_NOTES_KEY], - items, - transaction, - &mut ops, - &platform_version.drive, - )?; - Ok(ops) - } } } } diff --git a/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs index 15e0fbf9f39..887b11161f6 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs @@ -29,6 +29,9 @@ impl Drive { TreeType::ProvableCountTree => Element::empty_provable_count_tree(), TreeType::ProvableCountSumTree => Element::empty_provable_count_sum_tree(), TreeType::CommitmentTree => Element::empty_commitment_tree(), + TreeType::MmrTree => Element::empty_mmr_tree(), + TreeType::BulkAppendTree => Element::empty_bulk_append_tree(4), + TreeType::DenseAppendOnlyFixedSizeTree => Element::empty_dense_tree(8), }; let cost_context = self.grove.insert( path, diff --git a/packages/rs-drive/src/util/operations/apply_partial_batch_grovedb_operations/v0/mod.rs b/packages/rs-drive/src/util/operations/apply_partial_batch_grovedb_operations/v0/mod.rs index ff260a535bb..87d7382bd7a 100644 --- a/packages/rs-drive/src/util/operations/apply_partial_batch_grovedb_operations/v0/mod.rs +++ b/packages/rs-drive/src/util/operations/apply_partial_batch_grovedb_operations/v0/mod.rs @@ -52,6 +52,7 @@ impl Drive { }, storage_loaded_bytes: 1, hash_node_calls: 1, + sinsemilla_hash_calls: 0, }, &None, )?; diff --git a/packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/v0/mod.rs b/packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/v0/mod.rs index 57a3222a97d..e01870da58c 100644 --- a/packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/v0/mod.rs +++ b/packages/rs-drive/src/verify/address_funds/verify_compacted_address_balance_changes/v0/mod.rs @@ -8,7 +8,7 @@ use dpp::address_funds::PlatformAddress; /// The subtree key for compacted address balances storage as u8 const COMPACTED_ADDRESS_BALANCES_KEY_U8: u8 = b'c'; use dpp::balances::credits::BlockAwareCreditOperation; -use grovedb::operations::proof::GroveDBProof; +use grovedb::operations::proof::{GroveDBProof, ProofBytes}; use grovedb::{ GroveDb, MerkProofDecoder, MerkProofNode, MerkProofOp, PathQuery, Query, SizedQuery, }; @@ -75,24 +75,40 @@ impl Drive { // Navigate to the compacted address balances layer // Path: SavedBlockTransactions ('$' = 0x24) -> CompactedAddressBalances ('c' = 0x63) - let root_layer = match &grovedb_proof { - GroveDBProof::V0(v0) => &v0.root_layer, - }; - let saved_block_key = vec![RootTree::SavedBlockTransactions as u8]; let compacted_key = vec![COMPACTED_ADDRESS_BALANCES_KEY_U8]; - let compacted_layer = root_layer - .lower_layers - .get(&saved_block_key) - .and_then(|layer| layer.lower_layers.get(&compacted_key)); - // Extract KV entries from the compacted layer's merk proof to find - // if there's a containing range for start_block_height - let kv_entries = compacted_layer - .map(|layer| extract_kv_entries_from_merk_proof(&layer.merk_proof)) - .transpose()? - .unwrap_or_default(); + // if there's a containing range for start_block_height. + // V0 and V1 proofs have different layer types (MerkOnlyLayerProof vs LayerProof), + // so we handle them separately. + let kv_entries = match &grovedb_proof { + GroveDBProof::V0(v0) => { + let compacted_layer = v0 + .root_layer + .lower_layers + .get(&saved_block_key) + .and_then(|layer| layer.lower_layers.get(&compacted_key)); + compacted_layer + .map(|layer| extract_kv_entries_from_merk_proof(&layer.merk_proof)) + .transpose()? + .unwrap_or_default() + } + GroveDBProof::V1(v1) => { + let compacted_layer = v1 + .root_layer + .lower_layers + .get(&saved_block_key) + .and_then(|layer| layer.lower_layers.get(&compacted_key)); + compacted_layer + .map(|layer| match &layer.merk_proof { + ProofBytes::Merk(bytes) => extract_kv_entries_from_merk_proof(bytes), + _ => Ok(vec![]), + }) + .transpose()? + .unwrap_or_default() + } + }; // Look for a KV entry where the range contains start_block_height // Keys are 16 bytes: (start_block, end_block), both big-endian diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs index 1d0687ce7a9..a2f08d7c83e 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_anchors/v0/mod.rs @@ -1,9 +1,9 @@ -use crate::drive::shielded::paths::shielded_anchors_credit_pool_path_vec; +use crate::drive::shielded::paths::shielded_credit_pool_anchors_path_vec; use crate::drive::Drive; use crate::error::drive::DriveError; use crate::error::Error; use crate::verify::RootHash; -use grovedb::{GroveDb, PathQuery, Query, SizedQuery}; +use grovedb::{Element, GroveDb, PathQuery, Query, SizedQuery}; use platform_version::version::PlatformVersion; impl Drive { @@ -13,7 +13,7 @@ impl Drive { platform_version: &PlatformVersion, ) -> Result<(RootHash, Vec<[u8; 32]>), Error> { let path_query = PathQuery { - path: shielded_anchors_credit_pool_path_vec(), + path: shielded_credit_pool_anchors_path_vec(), query: SizedQuery { query: Query::new_range_full(), limit: None, @@ -28,13 +28,23 @@ impl Drive { }; let mut anchors = Vec::with_capacity(proved_key_values.len()); - for (_, key, _) in proved_key_values { - let anchor: [u8; 32] = key.try_into().map_err(|_: Vec| { - Error::Drive(DriveError::CorruptedElementType( - "anchor key is not 32 bytes", - )) - })?; - anchors.push(anchor); + for (_, _key, maybe_element) in proved_key_values { + match maybe_element { + Some(Element::Item(value, _)) => { + let anchor: [u8; 32] = value.try_into().map_err(|_v: Vec| { + Error::Drive(DriveError::CorruptedElementType( + "anchor value is not 32 bytes", + )) + })?; + anchors.push(anchor); + } + Some(_) => { + return Err(Error::Drive(DriveError::CorruptedElementType( + "expected Item element for anchor, got different element type", + ))); + } + None => {} + } } Ok((root_hash, anchors)) diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs index e41efc22ab7..611fb430590 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs @@ -1,4 +1,4 @@ -use crate::drive::shielded::paths::shielded_credit_pool_encrypted_notes_path_vec; +use crate::drive::shielded::paths::shielded_credit_pool_notes_path_vec; use crate::drive::Drive; use crate::error::drive::DriveError; use crate::error::Error; @@ -31,7 +31,7 @@ impl Drive { }; let path_query = PathQuery { - path: shielded_credit_pool_encrypted_notes_path_vec(), + path: shielded_credit_pool_notes_path_vec(), query: SizedQuery { query, limit: Some(limit), 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 022b69f0bb3..f4a5999a8f5 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 @@ -14,6 +14,7 @@ pub struct DriveAbciValidationVersions { pub has_nonce_validation: FeatureVersion, pub has_address_witness_validation: FeatureVersion, pub validate_address_witnesses: FeatureVersion, + pub validate_shielded_proof: FeatureVersion, pub process_state_transition: FeatureVersion, pub state_transition_to_execution_event_for_check_tx: FeatureVersion, pub penalties: PenaltyAmounts, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs index 6226ad4c6bb..8d5058db63f 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs @@ -244,6 +244,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V1: DriveAbciValidationVersions = has_nonce_validation: 0, has_address_witness_validation: 0, validate_address_witnesses: 0, + validate_shielded_proof: 0, 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/v2.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs index 1882d4a8ca2..0b6a9bc1c2a 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs @@ -244,6 +244,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V2: DriveAbciValidationVersions = has_nonce_validation: 0, has_address_witness_validation: 0, validate_address_witnesses: 0, + validate_shielded_proof: 0, 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/v3.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs index aecb62ff893..4c17a065eb9 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs @@ -244,6 +244,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V3: DriveAbciValidationVersions = has_nonce_validation: 0, has_address_witness_validation: 0, validate_address_witnesses: 0, + validate_shielded_proof: 0, 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/v4.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v4.rs index 9755ffa344d..f1affbaf9cd 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 @@ -247,6 +247,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V4: DriveAbciValidationVersions = has_nonce_validation: 1, // <---- changed this has_address_witness_validation: 0, validate_address_witnesses: 0, + validate_shielded_proof: 0, 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 index 425d4726e26..7afcbacfdc6 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs @@ -248,6 +248,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V5: DriveAbciValidationVersions = has_nonce_validation: 1, has_address_witness_validation: 0, validate_address_witnesses: 0, + validate_shielded_proof: 0, 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/v6.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs index 0f5396a58e3..474cf69b7ae 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs @@ -251,6 +251,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V6: DriveAbciValidationVersions = has_nonce_validation: 1, has_address_witness_validation: 0, validate_address_witnesses: 0, + validate_shielded_proof: 0, 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/v7.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs index 8653370db94..83a1ade1119 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs @@ -245,6 +245,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V7: DriveAbciValidationVersions = has_nonce_validation: 1, has_address_witness_validation: 0, validate_address_witnesses: 0, + validate_shielded_proof: 0, process_state_transition: 0, state_transition_to_execution_event_for_check_tx: 0, penalties: PenaltyAmounts { diff --git a/packages/rs-platform-version/src/version/fee/hashing/mod.rs b/packages/rs-platform-version/src/version/fee/hashing/mod.rs index 8e42863d3bb..0a1c42e535f 100644 --- a/packages/rs-platform-version/src/version/fee/hashing/mod.rs +++ b/packages/rs-platform-version/src/version/fee/hashing/mod.rs @@ -10,6 +10,8 @@ pub struct FeeHashingVersion { pub sha256_ripe_md160_base: u64, pub single_sha256_base: u64, pub ripemd160_per_block: u64, + /// Cost per Sinsemilla hash operation (elliptic curve, ~100x more expensive than Blake3) + pub sinsemilla_base: u64, } #[derive(Clone, Debug, Encode, Decode, Default, PartialEq, Eq)] diff --git a/packages/rs-platform-version/src/version/fee/hashing/v1.rs b/packages/rs-platform-version/src/version/fee/hashing/v1.rs index 7bdd3052142..15ff6967eaf 100644 --- a/packages/rs-platform-version/src/version/fee/hashing/v1.rs +++ b/packages/rs-platform-version/src/version/fee/hashing/v1.rs @@ -7,4 +7,5 @@ pub const FEE_HASHING_VERSION1: FeeHashingVersion = FeeHashingVersion { sha256_per_block: 5000, blake3_per_block: 300, ripemd160_per_block: 5000, // RIPEMD160 has 64-byte blocks, similar cost to SHA256 + sinsemilla_base: 40_000, // Sinsemilla is an elliptic curve hash (~100x Blake3) }; diff --git a/packages/rs-sdk-ffi/src/system/queries/path_elements.rs b/packages/rs-sdk-ffi/src/system/queries/path_elements.rs index bb17b06c9c1..cb9f8f87ce9 100644 --- a/packages/rs-sdk-ffi/src/system/queries/path_elements.rs +++ b/packages/rs-sdk-ffi/src/system/queries/path_elements.rs @@ -156,7 +156,16 @@ fn get_path_elements( Element::ProvableCountSumTree(_, count, sum, _) => { format!("provable_count_sum_tree:{}:{}", count, sum) } - Element::CommitmentTree(_, _) => "commitment_tree".to_string(), + Element::CommitmentTree(_, _, _, _) => { + "commitment_tree".to_string() + } + Element::MmrTree(_, _, _, _) => "mmr_tree".to_string(), + Element::BulkAppendTree(_, _, _, _, _) => { + "bulk_append_tree".to_string() + } + Element::DenseAppendOnlyFixedSizeTree(_, _, _, _, _) => { + "dense_tree".to_string() + } }; format!( @@ -177,7 +186,11 @@ fn get_path_elements( Element::ProvableCountSumTree(_, _, _, _) => { "provable_count_sum_tree" } - Element::CommitmentTree(_, _) => "commitment_tree", + Element::CommitmentTree(_, _, _, _) => "commitment_tree", + Element::MmrTree(_, _, _, _) => "mmr_tree", + Element::BulkAppendTree(_, _, _, _, _) => "bulk_append_tree", + Element::DenseAppendOnlyFixedSizeTree(_, _, _, _, _) => + "dense_tree", } ) }) diff --git a/packages/rs-sdk/src/platform/transition/shielded_transfer.rs b/packages/rs-sdk/src/platform/transition/shielded_transfer.rs index e5b48029fe3..b96fe729b4f 100644 --- a/packages/rs-sdk/src/platform/transition/shielded_transfer.rs +++ b/packages/rs-sdk/src/platform/transition/shielded_transfer.rs @@ -27,11 +27,6 @@ impl TransferShielded for Sdk { value_balance: u64, settings: Option, ) -> Result<(), Error> { - let user_fee_increase = settings - .as_ref() - .and_then(|s| s.user_fee_increase) - .unwrap_or_default(); - let OrchardBundleParams { actions, flags, @@ -47,7 +42,6 @@ impl TransferShielded for Sdk { anchor, proof, binding_signature, - user_fee_increase, self.version(), )?; ensure_valid_state_transition_structure(&state_transition, self.version())?; diff --git a/packages/rs-sdk/src/platform/transition/shielded_withdrawal.rs b/packages/rs-sdk/src/platform/transition/shielded_withdrawal.rs index af105038fc1..4db09eb1b20 100644 --- a/packages/rs-sdk/src/platform/transition/shielded_withdrawal.rs +++ b/packages/rs-sdk/src/platform/transition/shielded_withdrawal.rs @@ -39,11 +39,6 @@ impl WithdrawShielded for Sdk { output_script: CoreScript, settings: Option, ) -> Result<(), Error> { - let user_fee_increase = settings - .as_ref() - .and_then(|s| s.user_fee_increase) - .unwrap_or_default(); - let OrchardBundleParams { actions, flags, @@ -63,7 +58,6 @@ impl WithdrawShielded for Sdk { core_fee_per_byte, pooling, output_script, - user_fee_increase, self.version(), )?; ensure_valid_state_transition_structure(&state_transition, self.version())?; diff --git a/packages/rs-sdk/src/platform/transition/unshield.rs b/packages/rs-sdk/src/platform/transition/unshield.rs index 4a09f40dea4..a121e538a0d 100644 --- a/packages/rs-sdk/src/platform/transition/unshield.rs +++ b/packages/rs-sdk/src/platform/transition/unshield.rs @@ -32,11 +32,6 @@ impl UnshieldFunds for Sdk { value_balance: i64, settings: Option, ) -> Result<(), Error> { - let user_fee_increase = settings - .as_ref() - .and_then(|s| s.user_fee_increase) - .unwrap_or_default(); - let OrchardBundleParams { actions, flags, @@ -54,7 +49,6 @@ impl UnshieldFunds for Sdk { anchor, proof, binding_signature, - user_fee_increase, self.version(), )?; ensure_valid_state_transition_structure(&state_transition, self.version())?; diff --git a/packages/wasm-dpp/src/shielded/shielded_transfer_transition.rs b/packages/wasm-dpp/src/shielded/shielded_transfer_transition.rs index 87f5ea656f4..87b84834ccb 100644 --- a/packages/wasm-dpp/src/shielded/shielded_transfer_transition.rs +++ b/packages/wasm-dpp/src/shielded/shielded_transfer_transition.rs @@ -47,9 +47,9 @@ impl ShieldedTransferTransitionWasm { } } - /// Returns the net value balance. + /// Returns the value balance (fee amount leaving the pool). #[wasm_bindgen(js_name = getValueBalance)] - pub fn get_value_balance(&self) -> i64 { + pub fn get_value_balance(&self) -> u64 { match &self.0 { ShieldedTransferTransition::V0(v0) => v0.value_balance, } @@ -82,12 +82,10 @@ impl ShieldedTransferTransitionWasm { Buffer::from_bytes(sig) } - /// Returns the user fee increase multiplier. + /// Always returns 0 — the fee is cryptographically locked by the Orchard binding signature. #[wasm_bindgen(js_name = getUserFeeIncrease)] pub fn get_user_fee_increase(&self) -> u16 { - match &self.0 { - ShieldedTransferTransition::V0(v0) => v0.user_fee_increase, - } + 0 } #[wasm_bindgen(js_name = toObject)] diff --git a/packages/wasm-dpp/src/shielded/shielded_withdrawal_transition.rs b/packages/wasm-dpp/src/shielded/shielded_withdrawal_transition.rs index f2f45559b82..7cf68c858ba 100644 --- a/packages/wasm-dpp/src/shielded/shielded_withdrawal_transition.rs +++ b/packages/wasm-dpp/src/shielded/shielded_withdrawal_transition.rs @@ -115,12 +115,10 @@ impl ShieldedWithdrawalTransitionWasm { Buffer::from_bytes(script.as_bytes()) } - /// Returns the user fee increase multiplier. + /// Always returns 0 — the fee is cryptographically locked by the Orchard binding signature. #[wasm_bindgen(js_name = getUserFeeIncrease)] pub fn get_user_fee_increase(&self) -> u16 { - match &self.0 { - ShieldedWithdrawalTransition::V0(v0) => v0.user_fee_increase, - } + 0 } #[wasm_bindgen(js_name = toObject)] diff --git a/packages/wasm-dpp/src/shielded/unshield_transition.rs b/packages/wasm-dpp/src/shielded/unshield_transition.rs index 887508e640b..b56342bc9e5 100644 --- a/packages/wasm-dpp/src/shielded/unshield_transition.rs +++ b/packages/wasm-dpp/src/shielded/unshield_transition.rs @@ -100,11 +100,10 @@ impl UnshieldTransitionWasm { } /// Returns the user fee increase multiplier. + /// Always returns 0 — the fee is cryptographically locked by the Orchard binding signature. #[wasm_bindgen(js_name = getUserFeeIncrease)] pub fn get_user_fee_increase(&self) -> u16 { - match &self.0 { - UnshieldTransition::V0(v0) => v0.user_fee_increase, - } + 0 } #[wasm_bindgen(js_name = toObject)] From b92b6fe95cdd6816ffb29d4c832cd068759a99d8 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 17 Feb 2026 11:21:54 +0700 Subject: [PATCH 17/40] more work --- Cargo.lock | 7 +- docs/SHIELDED_CLIENT_INTEGRATION.md | 706 ++++++++++++++++++ packages/rs-dpp/Cargo.toml | 5 + .../src/address_funds/platform_address.rs | 345 ++++++++- packages/rs-dpp/src/shielded/builder.rs | 537 +++++++++++++ packages/rs-dpp/src/shielded/mod.rs | 11 +- packages/rs-drive-abci/Cargo.toml | 1 - .../state_transitions/shield/tests.rs | 18 +- .../shield_from_asset_lock/tests.rs | 20 +- .../state_transitions/shielded_common/mod.rs | 22 +- .../shielded_transfer/tests.rs | 34 +- .../shielded_withdrawal/tests.rs | 30 +- .../state_transitions/unshield/tests.rs | 34 +- .../tests/strategy_tests/strategy.rs | 34 +- 14 files changed, 1693 insertions(+), 111 deletions(-) create mode 100644 docs/SHIELDED_CLIENT_INTEGRATION.md create mode 100644 packages/rs-dpp/src/shielded/builder.rs diff --git a/Cargo.lock b/Cargo.lock index 9f9e869f4ed..acffb585a2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1866,6 +1866,7 @@ dependencies = [ "dpp", "env_logger 0.11.8", "getrandom 0.2.16", + "grovedb-commitment-tree", "hex", "indexmap 2.12.1", "integer-encoding", @@ -1975,7 +1976,6 @@ dependencies = [ "metrics-exporter-prometheus", "mockall", "nonempty", - "orchard", "platform-version", "prost 0.14.1", "rand 0.8.5", @@ -2649,6 +2649,7 @@ dependencies = [ "orchard", "shardtree", "thiserror 2.0.17", + "zcash_note_encryption", ] [[package]] @@ -4370,8 +4371,6 @@ dependencies = [ [[package]] name = "orchard" version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c01cd4ea711aab5f263f2b7aa6966687a2d6c7df4f78eb1b97a66a7a4e78e3b" dependencies = [ "aes", "bitvec", @@ -8293,8 +8292,6 @@ dependencies = [ [[package]] name = "zcash_note_encryption" version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77efec759c3798b6e4d829fcc762070d9b229b0f13338c40bf993b7b609c2272" dependencies = [ "chacha20", "chacha20poly1305", diff --git a/docs/SHIELDED_CLIENT_INTEGRATION.md b/docs/SHIELDED_CLIENT_INTEGRATION.md new file mode 100644 index 00000000000..6752c32c706 --- /dev/null +++ b/docs/SHIELDED_CLIENT_INTEGRATION.md @@ -0,0 +1,706 @@ +# Shielded Pool Client Integration Guide + +This guide explains how to build client applications that interact with Dash Platform's shielded credit pool. It covers key management, bundle construction, state transition creation, note tracking, and light client synchronization. + +For the protocol specification, see [DIP-0040](../dip/dip-0040.md) (shielded credit pool), [DIP-0041](../dip/dip-0041.md) (L1 bridge), and [DIP-0042](../dip/dip-0042.md) (light client syncing). + +## Table of Contents + +1. [Overview](#1-overview) +2. [Dependencies](#2-dependencies) +3. [Key Management](#3-key-management) +4. [Commitment Tree and Note Tracking](#4-commitment-tree-and-note-tracking) +5. [Platform Sighash](#5-platform-sighash) +6. [Building Shielded State Transitions](#6-building-shielded-state-transitions) + 1. [Shield (Type 15)](#61-shield-type-15) + 2. [ShieldFromAssetLock (Type 18)](#62-shieldfromassetlock-type-18) + 3. [ShieldedTransfer (Type 16)](#63-shieldedtransfer-type-16) + 4. [Unshield (Type 17)](#64-unshield-type-17) + 5. [ShieldedWithdrawal (Type 19)](#65-shieldedwithdrawal-type-19) +7. [Bundle Serialization](#7-bundle-serialization) +8. [Light Client Syncing](#8-light-client-syncing) +9. [Trial Decryption](#9-trial-decryption) +10. [Fee Model](#10-fee-model) +11. [Security Considerations](#11-security-considerations) + +--- + +## 1. Overview + +The shielded credit pool enables private value transfers on Dash Platform using the Zcash Orchard protocol. Five state transition types move credits between transparent and shielded domains: + +| Type ID | Name | Direction | When to Use | +|---------|------|-----------|-------------| +| 15 | Shield | Transparent -> Pool | Deposit platform credits into the shielded pool | +| 16 | ShieldedTransfer | Pool -> Pool | Transfer value privately within the pool | +| 17 | Unshield | Pool -> Transparent | Withdraw credits to a platform address | +| 18 | ShieldFromAssetLock | Core L1 -> Pool | Deposit directly from a Dash Core asset lock | +| 19 | ShieldedWithdrawal | Pool -> Core L1 | Withdraw credits to a Dash Core address | + +All five types carry Orchard bundle data: serialized actions, a Halo 2 zero-knowledge proof, and RedPallas signatures. The client constructs these bundles using the Orchard builder API, then wraps them in the appropriate state transition struct. + +### Cryptographic Primitives + +| Primitive | Purpose | +|-----------|---------| +| Halo 2 | Zero-knowledge proof system (no trusted setup) | +| RedPallas | Re-randomizable Schnorr signatures on the Pallas curve | +| Sinsemilla | Hash-based commitment scheme for the Merkle tree | +| BLAKE2b-256 | Bundle commitment computation (per ZIP-244) | +| SHA-256 | Platform sighash computation | + +--- + +## 2. Dependencies + +Client applications use the `grovedb-commitment-tree` crate, which re-exports all necessary Orchard types: + +```toml +[dependencies] +grovedb-commitment-tree = { version = "4", features = ["client"] } +``` + +The `client` feature enables `ClientCommitmentTree` for wallet-side note tracking and Merkle witness generation. All Orchard types are re-exported from this crate: + +```rust +use grovedb_commitment_tree::{ + // Builder + Builder, BundleType, + // Key management + SpendingKey, FullViewingKey, IncomingViewingKey, OutgoingViewingKey, + SpendAuthorizingKey, Scope, + // Bundle types + Bundle, Authorized, Flags, Action, + // Memo types (Dash uses 36-byte memos, not Zcash 512-byte) + DashMemo, NoteBytesData, + // Proof creation/verification + ProvingKey, VerifyingKey, + // Note types + Note, NoteValue, PaymentAddress, + ExtractedNoteCommitment, Nullifier, Rho, TransmittedNoteCiphertext, + // Tree types + Anchor, MerklePath, MerkleHashOrchard, + // Client tree + ClientCommitmentTree, Position, Retention, +}; +``` + +For the platform sighash, also depend on `dpp`: + +```rust +use dpp::shielded::compute_platform_sighash; +``` + +--- + +## 3. Key Management + +### Key Hierarchy + +The Orchard key hierarchy derives all keys from a single 32-byte spending key: + +``` +SpendingKey (sk) + | + +-- SpendAuthorizingKey (ask) -- signs spend actions + | + +-- FullViewingKey (fvk) -- derives all viewing keys + addresses + | + +-- IncomingViewingKey (ivk) -- detects incoming notes (trial decryption) + | + +-- OutgoingViewingKey (ovk) -- recovers sent notes (wallet recovery) + | + +-- PaymentAddress -- derived per-contact diversified address +``` + +### Creating Keys + +```rust +use grovedb_commitment_tree::{ + SpendingKey, FullViewingKey, SpendAuthorizingKey, + IncomingViewingKey, OutgoingViewingKey, Scope, +}; + +// Generate or load a 32-byte spending key seed +let sk = SpendingKey::from_bytes(seed_bytes) + .expect("invalid spending key bytes"); + +// Derive all other keys +let fvk = FullViewingKey::from(&sk); +let ask = SpendAuthorizingKey::from(&sk); + +// Derive payment addresses (use different indices for different contacts) +let default_address = fvk.address_at(0u32, Scope::External); +let contact_address = fvk.address_at(1u32, Scope::External); + +// Viewing keys for note detection +let ivk: IncomingViewingKey = fvk.to_ivk(Scope::External); +let ovk: OutgoingViewingKey = fvk.to_ovk(Scope::External); +``` + +### Key Storage + +- **SpendingKey**: Must be stored encrypted. This is the master secret -- anyone who obtains it can spend all shielded funds. +- **FullViewingKey**: Allows detecting all incoming and outgoing notes. Store securely but does not enable spending. +- **IncomingViewingKey**: Allows detecting only incoming notes. Safe to share with a watch-only server for filtered sync (DIP-0043). +- **PaymentAddress**: Safe to share publicly. Give a unique diversified address to each contact for privacy. + +--- + +## 4. Commitment Tree and Note Tracking + +### ClientCommitmentTree + +The `ClientCommitmentTree` maintains a local copy of the on-chain Sinsemilla Merkle tree (depth 32). It supports: + +- Appending note commitments as they appear on-chain +- Checkpointing after each block +- Generating Merkle witnesses (authentication paths) for spending notes + +```rust +use grovedb_commitment_tree::{ClientCommitmentTree, Retention, Position, Anchor, MerklePath}; + +// Create a new client tree (retain up to 1000 checkpoints) +let mut tree = ClientCommitmentTree::new(1000); + +// Append notes as they appear on-chain +// Use Retention::Marked for notes belonging to this wallet (need witnesses later) +// Use Retention::Ephemeral for notes belonging to other wallets +tree.append(cmx_bytes, Retention::Marked)?; // Our note +tree.append(other_cmx, Retention::Ephemeral)?; // Someone else's note + +// Checkpoint after each block +tree.checkpoint(block_height)?; + +// Get the current anchor (Merkle root) +let anchor: Anchor = tree.anchor()?; + +// Generate a witness for spending a note at a known position +let merkle_path: MerklePath = tree.witness(position, 0)? + .expect("witness should exist for marked leaf"); +``` + +### Wallet Note State + +A wallet tracks each note through its lifecycle: + +``` +Created (cmx appended to tree) + | + +-- Unspent (nullifier not seen on-chain) + | | + | +-- Spendable (witness available at current anchor) + | + +-- Spent (nullifier published on-chain) +``` + +For each detected note, store: + +| Field | Source | Purpose | +|-------|--------|---------| +| `Note` | Trial decryption | The note object (value, address, rho, rseed) | +| `Position` | Tree append order | Location in commitment tree (for witness generation) | +| `cmx` | `ExtractedNoteCommitment::from(note.commitment())` | For tree tracking | +| `nullifier` | Known from note + spending key | To detect when the note is spent | +| `block_height` | Block where cmx appeared | For sync tracking | + +--- + +## 5. Platform Sighash + +The **platform sighash** cryptographically binds Orchard bundle data to platform-specific transparent fields. It is the hash that all Orchard signatures commit to. + +``` +sighash = SHA-256("DashPlatformSighash" || bundle_commitment || extra_data) +``` + +Where: +- `"DashPlatformSighash"` is a fixed 19-byte ASCII domain separator +- `bundle_commitment` is the 32-byte BLAKE2b-256 Orchard bundle commitment (per ZIP-244), covering: flags, value_balance, anchor, and all action fields (nullifier, rk, cmx, cv_net, encrypted_note) -- but NOT signatures or proof +- `extra_data` varies by transition type: + +| Transition | extra_data | Rationale | +|------------|------------|-----------| +| Shield | empty (`&[]`) | Witness signatures already authenticate inputs | +| ShieldFromAssetLock | empty (`&[]`) | Asset lock proof authenticates the source | +| ShieldedTransfer | empty (`&[]`) | No transparent fields exist | +| Unshield | `output_address.to_bytes() \|\| amount.to_le_bytes()` | Binds destination and amount to the proof | +| ShieldedWithdrawal | `output_script \|\| amount.to_le_bytes()` | Binds Core script and amount to the proof | + +### Computing the Sighash + +```rust +use dpp::shielded::compute_platform_sighash; + +// After building the bundle but before signing: +let bundle_commitment: [u8; 32] = unauthorized_bundle.commitment().into(); + +// For Shield, ShieldFromAssetLock, or ShieldedTransfer (no extra data): +let sighash = compute_platform_sighash(&bundle_commitment, &[]); + +// For Unshield (bind output_address and amount): +let mut extra_data = output_address.to_bytes(); +extra_data.extend_from_slice(&amount.to_le_bytes()); +let sighash = compute_platform_sighash(&bundle_commitment, &extra_data); + +// For ShieldedWithdrawal (bind output_script and amount): +let mut extra_data = output_script.to_bytes(); +extra_data.extend_from_slice(&amount.to_le_bytes()); +let sighash = compute_platform_sighash(&bundle_commitment, &extra_data); +``` + +The same sighash must be computed identically on both the signing (client) and verification (platform) sides. If any transparent field is modified after signing, verification will fail. + +--- + +## 6. Building Shielded State Transitions + +### Common Pattern + +All shielded transitions follow the same five-step pattern: + +1. **Create an Orchard builder** with the appropriate flags and anchor +2. **Add spends and/or outputs** to the builder +3. **Build, prove, and sign** the bundle using the platform sighash +4. **Serialize the bundle** into platform format (`SerializedAction` structs) +5. **Wrap in a state transition** and broadcast + +### ProvingKey Caching + +The `ProvingKey` takes approximately 30 seconds to build. Cache it for the lifetime of the application: + +```rust +use std::sync::OnceLock; +use grovedb_commitment_tree::ProvingKey; + +static PROVING_KEY: OnceLock = OnceLock::new(); + +fn get_proving_key() -> &'static ProvingKey { + PROVING_KEY.get_or_init(ProvingKey::build) +} +``` + +### 6.1 Shield (Type 15) + +Deposits credits from transparent platform addresses into the shielded pool. This is an **output-only** bundle (no spends). + +```rust +use grovedb_commitment_tree::{ + Builder, BundleType, Flags as OrchardFlags, Anchor, + SpendingKey, FullViewingKey, NoteValue, Scope, +}; +use dpp::shielded::compute_platform_sighash; +use dpp::state_transition::state_transitions::shielded::shield_transition::ShieldTransition; + +// 1. Setup keys and recipient +let sk = SpendingKey::from_bytes(seed)?; +let fvk = FullViewingKey::from(&sk); +let recipient = fvk.address_at(0u32, Scope::External); + +// 2. Build output-only bundle (spends disabled for shielding) +let anchor = Anchor::empty_tree(); // No spends, so anchor is unused +let mut builder = Builder::::new( + BundleType::Transactional { + flags: OrchardFlags::SPENDS_DISABLED, + bundle_required: false, + }, + anchor, +); + +let shield_amount: u64 = 100_000; // Credits to shield +builder.add_output( + None, // No outgoing viewing key needed + recipient, + NoteValue::from_raw(shield_amount), + [0u8; 36], // 36-byte structured memo +)?; + +// 3. Build -> prove -> sign +let pk = get_proving_key(); +let mut rng = rand::rngs::OsRng; +let (unauthorized, _) = builder + .build::(&mut rng)? + .expect("bundle should be present"); + +let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); +let sighash = compute_platform_sighash(&bundle_commitment, &[]); +let proven = unauthorized.create_proof(pk, &mut rng)?; +let bundle = proven.apply_signatures(rng, sighash, &[])?; // No spend auth keys + +// 4. Serialize bundle (see Section 7) +let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + +// 5. Create state transition +// `inputs` = map of platform addresses contributing credits +// `signer` = signs the address witnesses +let transition = ShieldTransition::try_from_bundle_with_signer( + inputs, // BTreeMap + actions, + flags, + value_balance, // Negative (credits flow INTO pool) + anchor_bytes, + proof_bytes, + binding_sig, + fee_strategy, // Which inputs pay fees + signer, // Signs address witnesses + user_fee_increase, + platform_version, +)?; +``` + +**Key points:** +- `value_balance` will be **negative** (credits flow into the pool) +- The shield amount equals `|value_balance|` +- Fees are paid from the transparent platform address inputs +- No `SpendAuthorizingKey` needed (empty `&[]` for signatures) + +### 6.2 ShieldFromAssetLock (Type 18) + +Deposits credits directly from a Dash Core asset lock proof. Identical bundle construction to Shield, but the funding source is a core asset lock instead of platform address balances. + +```rust +use dpp::state_transition::state_transitions::shielded::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; + +// Bundle construction is identical to Shield (output-only, empty sighash) +// ... (same builder/prove/sign steps as Shield) ... + +// Create state transition with asset lock proof +let transition = ShieldFromAssetLockTransition::try_from_asset_lock_with_bundle( + asset_lock_proof, // From Dash Core + asset_lock_private_key_bytes, // Signs the asset lock + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + user_fee_increase, + platform_version, +)?; +``` + +### 6.3 ShieldedTransfer (Type 16) + +Transfers value privately within the shielded pool. **Spends** an existing note and creates a new output note. The ZK proof is the sole authorization. + +```rust +use dpp::state_transition::state_transitions::shielded::shielded_transfer_transition::ShieldedTransferTransition; + +// 1. Get a spendable note with its Merkle witness +let (note, merkle_path, anchor) = wallet.take_spendable_note()?; +let note_value = note.value().inner(); + +// 2. Build spend + output bundle +let mut builder = Builder::::new(BundleType::DEFAULT, anchor); +builder.add_spend(fvk.clone(), note, merkle_path)?; +builder.add_output( + None, + recipient_address, // The recipient's payment address + NoteValue::from_raw(note_value), // Transfer full value (no fee from pool) + memo_bytes, // [u8; 36] structured memo +)?; + +// 3. Build -> prove -> sign (needs SpendAuthorizingKey for the spend) +let pk = get_proving_key(); +let mut rng = rand::rngs::OsRng; +let (unauthorized, _) = builder.build::(&mut rng)?.expect("bundle present"); + +let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); +let sighash = compute_platform_sighash(&bundle_commitment, &[]); // No extra_data +let proven = unauthorized.create_proof(pk, &mut rng)?; +let bundle = proven.apply_signatures(rng, sighash, &[ask])?; // Spend auth key required + +// 4. Serialize and create transition +let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + +let transition = ShieldedTransferTransition::try_from_bundle( + actions, + flags, + value_balance as u64, // 0 for pure transfer, >0 if paying fees from pool + anchor_bytes, + proof_bytes, + binding_sig, + platform_version, +)?; +``` + +**Key points:** +- The `anchor` must match a historical anchor stored on-chain (not `Anchor::empty_tree()`) +- `value_balance` is 0 for a pure private transfer (all value stays in the pool) +- `value_balance` > 0 means that amount is extracted from the pool as a fee +- The `SpendAuthorizingKey` (`ask`) must be provided to `apply_signatures` + +### 6.4 Unshield (Type 17) + +Withdraws credits from the shielded pool to a transparent platform address. Spends a note and delivers part of the value to a transparent address. + +```rust +use dpp::state_transition::state_transitions::shielded::unshield_transition::UnshieldTransition; + +// 1. Get a spendable note +let (note, merkle_path, anchor) = wallet.take_spendable_note()?; +let note_value = note.value().inner(); + +// 2. Decide amounts +let unshield_amount = note_value / 2; // Amount going to transparent address +let change_amount = note_value - unshield_amount; // Change staying in pool + +// 3. Build bundle: spend note, output change back to self +let mut builder = Builder::::new(BundleType::DEFAULT, anchor); +builder.add_spend(fvk.clone(), note, merkle_path)?; +builder.add_output( + None, + self_address, // Change goes back to our shielded address + NoteValue::from_raw(change_amount), + [0u8; 36], // 36-byte structured memo +)?; + +// 4. Build -> prove -> sign WITH extra_data binding +let pk = get_proving_key(); +let mut rng = rand::rngs::OsRng; +let (unauthorized, _) = builder.build::(&mut rng)?.expect("bundle present"); + +let output_address = PlatformAddress::P2pkh(recipient_hash); +let mut extra_data = output_address.to_bytes(); +extra_data.extend_from_slice(&unshield_amount.to_le_bytes()); + +let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); +let sighash = compute_platform_sighash(&bundle_commitment, &extra_data); +let proven = unauthorized.create_proof(pk, &mut rng)?; +let bundle = proven.apply_signatures(rng, sighash, &[ask])?; + +// 5. Serialize and create transition +let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + +let transition = UnshieldTransition::try_from_bundle( + output_address, + unshield_amount, + actions, + flags, + value_balance, // Positive (credits flow OUT of pool) + anchor_bytes, + proof_bytes, + binding_sig, + platform_version, +)?; +``` + +**Key points:** +- `value_balance` must be **positive** (credits flow out of the pool) +- `value_balance >= amount` (the difference is the fee paid from the pool) +- `output_address` and `amount` are bound to the sighash -- they cannot be modified after signing +- The `output_address` is a `PlatformAddress` (P2pkh or P2sh, not a Core address) + +### 6.5 ShieldedWithdrawal (Type 19) + +Withdraws credits from the shielded pool to a Dash Core L1 address. Similar to Unshield but targets a Core script instead of a platform address. + +```rust +use dpp::state_transition::state_transitions::shielded::shielded_withdrawal_transition::ShieldedWithdrawalTransition; + +// Bundle construction similar to Unshield, but with output_script in extra_data +let mut extra_data = output_script.to_bytes(); +extra_data.extend_from_slice(&withdrawal_amount.to_le_bytes()); + +let sighash = compute_platform_sighash(&bundle_commitment, &extra_data); +// ... prove and sign as usual ... + +let transition = ShieldedWithdrawalTransition::try_from_bundle( + withdrawal_amount, + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + core_fee_per_byte, // Core transaction fee rate + pooling, // Pooling strategy (Never, Standard, etc.) + output_script, // Dash Core output script (e.g., P2PKH) + platform_version, +)?; +``` + +--- + +## 7. Bundle Serialization + +After building and signing an Orchard bundle, decompose it into the platform serialization format: + +```rust +use dpp::shielded::SerializedAction; +use grovedb_commitment_tree::{Bundle, Authorized, DashMemo}; + +fn serialize_authorized_bundle( + bundle: &Bundle, +) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { + let actions: Vec = bundle.actions().iter().map(|action| { + let enc = action.encrypted_note(); + let mut encrypted_note = Vec::with_capacity(216); // 32 + 104 + 80 + encrypted_note.extend_from_slice(&enc.epk_bytes); + encrypted_note.extend_from_slice(enc.enc_ciphertext.as_ref()); + encrypted_note.extend_from_slice(&enc.out_ciphertext); + + SerializedAction { + nullifier: action.nullifier().to_bytes(), + rk: <[u8; 32]>::from(action.rk()), + cmx: action.cmx().to_bytes(), + encrypted_note, + cv_net: action.cv_net().to_bytes(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()), + } + }).collect(); + + let flags = bundle.flags().to_byte(); + let value_balance = *bundle.value_balance(); + let anchor = bundle.anchor().to_bytes(); + let proof = bundle.authorization().proof().as_ref().to_vec(); + let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); + + (actions, flags, value_balance, anchor, proof, binding_sig) +} +``` + +### SerializedAction Fields + +| Field | Size | Description | +|-------|------|-------------| +| `nullifier` | 32 bytes | Unique tag preventing double-spends | +| `rk` | 32 bytes | Randomized spend validating key (RedPallas) | +| `cmx` | 32 bytes | Extracted note commitment for the new output | +| `encrypted_note` | 216 bytes | `epk` (32) + `enc_ciphertext` (104) + `out_ciphertext` (80) | +| `cv_net` | 32 bytes | Pedersen value commitment | +| `spend_auth_sig` | 64 bytes | RedPallas spend authorization signature | + +--- + +## 8. Light Client Syncing + +Light clients must synchronize with the on-chain shielded pool state. The protocol is specified in [DIP-0042](../dip/dip-0042.md). The key gRPC queries are: + +### Available Queries + +| Query | Returns | Purpose | +|-------|---------|---------| +| `GetShieldedPoolState` | Pool parameters, total balance, note count | Initial state check | +| `GetShieldedEncryptedNotes` | Encrypted notes in block range | Note discovery via trial decryption | +| `GetShieldedAnchors` | Historical anchors by block height | Verify spend witnesses | +| `GetShieldedNullifiers` | Published nullifiers | Detect spent notes | + +### Sync Flow + +``` +1. Query pool state to get current note count and latest block height +2. For each unseen block range: + a. Fetch encrypted notes + b. Trial-decrypt each note with IncomingViewingKey + c. For decrypted notes: record (Note, Position, cmx) in wallet + d. Append ALL cmx values to ClientCommitmentTree (Marked for ours, Ephemeral for others) + e. Checkpoint the tree at each block boundary +3. Query nullifiers to detect which of our notes have been spent +4. Remove spent notes from the spendable set +``` + +### Sync Strategies + +| Strategy | Description | Best For | +|----------|-------------|----------| +| Sequential | Process every block in order | Simple implementation, full history | +| Warp Sync | Scan notes first, compute witnesses later | Fast initial sync (10-100x faster) | +| Spend-Before-Sync | Use server-provided witness for immediate spending | Spending before full sync completes | +| Parallel Block Scanning | Scan multiple block ranges concurrently | Multi-core devices | + +--- + +## 9. Trial Decryption + +Light clients discover their notes by attempting to decrypt every encrypted note on-chain: + +```rust +use grovedb_commitment_tree::{ + IncomingViewingKey, Note, TransmittedNoteCiphertext, + ExtractedNoteCommitment, PaymentAddress, + DashMemo, NoteBytesData, +}; + +fn try_decrypt_note( + ivk: &IncomingViewingKey, + encrypted_note: &[u8], // 216 bytes + cmx: &[u8; 32], +) -> Option { + // Parse the encrypted note into its components + let epk_bytes: [u8; 32] = encrypted_note[0..32].try_into().ok()?; + let enc_ciphertext: [u8; 104] = encrypted_note[32..136].try_into().ok()?; + let out_ciphertext: [u8; 80] = encrypted_note[136..216].try_into().ok()?; + + // Use from_parts() — struct literal not available (private PhantomData field) + let transmitted = TransmittedNoteCiphertext::::from_parts( + epk_bytes, + NoteBytesData(enc_ciphertext), + out_ciphertext, + ); + + // Attempt decryption with our incoming viewing key + // Returns None if the note is not addressed to us + let (note, _address, _memo) = transmitted.decrypt(ivk, cmx)?; + Some(note) +} +``` + +Trial decryption is the core privacy guarantee: the server cannot determine which notes belong to which client. The client downloads all encrypted notes and tests each one locally. + +--- + +## 10. Fee Model + +Fees vary by transition type: + +| Transition | Fee Source | Calculation | +|------------|-----------|-------------| +| Shield | Platform address inputs | Standard fee model (deducted from input addresses) | +| ShieldFromAssetLock | Asset lock value | `asset_lock_value - shield_amount` | +| ShieldedTransfer | Shielded pool | `value_balance` (extracted from pool, can be 0) | +| Unshield | Shielded pool | `value_balance - amount` (extracted from pool) | +| ShieldedWithdrawal | Shielded pool | `value_balance - amount` (extracted from pool) | + +For Shield, fees are deducted from the transparent platform address inputs using the standard fee model with `user_fee_increase` as a multiplier (0 = 100% of base fee, 1 = 101%, etc.). For ShieldFromAssetLock, the fee is `asset_lock_value - shield_amount`, validated against the minimum fee with `user_fee_increase` applied. For ShieldedTransfer, Unshield, and ShieldedWithdrawal, fees are cryptographically locked by the Orchard binding signature -- the client chooses the fee at bundle construction time by setting the `value_balance` appropriately. + +--- + +## 11. Security Considerations + +### Sighash Binding + +The platform sighash cryptographically binds transparent fields to the Orchard proof. For Unshield and ShieldedWithdrawal, the `output_address`/`output_script` and `amount` are included in `extra_data`. If an attacker modifies these fields, the binding signature and spend authorization signatures will fail verification. + +**Always compute the sighash correctly.** Using wrong `extra_data` will produce a valid-looking bundle that the platform will reject. + +### Anchor Freshness + +Spend-based transitions (ShieldedTransfer, Unshield, ShieldedWithdrawal) must reference a **historical anchor** stored on-chain. The platform rejects: +- `Anchor::empty_tree()` (all zeros) for spend transitions +- Anchors that don't match any recorded on-chain anchor + +Build spend bundles using the anchor from your `ClientCommitmentTree`, which must be in sync with the on-chain state. + +### Nullifier Uniqueness + +Each nullifier can only be published once. If a client submits a transition containing a nullifier that already exists in the on-chain nullifier set, the transition will be rejected (double-spend prevention). + +### Key Security + +- Never transmit the `SpendingKey` or `SpendAuthorizingKey` over the network +- The `ProvingKey` and `VerifyingKey` are deterministic and public -- safe to share +- Diversified addresses (different `address_at` indices) are unlinkable to each other without the `FullViewingKey` + +### Value Conservation + +The Orchard binding signature mathematically guarantees that no credits are created or destroyed: + +``` +sum(input_values) = sum(output_values) + value_balance +``` + +The platform verifies this constraint via the binding signature without learning any individual values. diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index 09643a4a23b..e10a6610845 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -71,6 +71,7 @@ strum = { version = "0.26", features = ["derive"] } json-schema-compatibility-validator = { path = '../rs-json-schema-compatibility-validator', optional = true } once_cell = "1.19.0" tracing = { version = "0.1.41" } +grovedb-commitment-tree = { path = "../../../grovedb/grovedb-commitment-tree", optional = true } [dev-dependencies] tokio = { version = "1.40", features = ["full"] } @@ -327,5 +328,9 @@ extended-document = [ ] token-reward-explanations = ["dep:chrono-tz"] +shielded-bundle-building = [ + "state-transition-signing", + "dep:grovedb-commitment-tree", +] factories = [] client = ["factories", "state-transitions"] diff --git a/packages/rs-dpp/src/address_funds/platform_address.rs b/packages/rs-dpp/src/address_funds/platform_address.rs index 8d6f3e7a722..5121f016e05 100644 --- a/packages/rs-dpp/src/address_funds/platform_address.rs +++ b/packages/rs-dpp/src/address_funds/platform_address.rs @@ -555,6 +555,204 @@ impl PlatformAddress { } } +// --------------------------------------------------------------------------- +// Orchard shielded payment address (requires `shielded-bundle-building`) +// --------------------------------------------------------------------------- + +/// Size of the Orchard diversifier (11 bytes). +#[cfg(feature = "shielded-bundle-building")] +pub const ORCHARD_DIVERSIFIER_SIZE: usize = 11; +/// Size of the Orchard diversified transmission key pk_d (32 bytes, Pallas curve point). +#[cfg(feature = "shielded-bundle-building")] +pub const ORCHARD_PKD_SIZE: usize = 32; +/// Total size of a raw Orchard payment address (43 bytes = diversifier + pk_d). +#[cfg(feature = "shielded-bundle-building")] +pub const ORCHARD_ADDRESS_SIZE: usize = ORCHARD_DIVERSIFIER_SIZE + ORCHARD_PKD_SIZE; + +/// An Orchard shielded payment address. +/// +/// Composed of a diversifier (11 bytes) and a diversified transmission key (32 bytes). +/// The diversifier enables a single spending key to derive an unlimited number of +/// unlinkable payment addresses. Only the holder of the corresponding FullViewingKey +/// (or IncomingViewingKey) can link diversified addresses to the same wallet. +/// +/// Bech32m encoding uses type byte `0x10`, producing addresses that start with `z`: +/// - Mainnet: `dash1z...` +/// - Testnet: `tdash1z...` +/// +/// The raw Orchard address format matches Zcash Orchard (43 bytes), but the +/// string encoding is Dash-specific (no F4Jumble, no Unified Address wrapper). +/// +/// Use [`From`] to convert from the `orchard` crate's native type, +/// or [`to_payment_address()`](OrchardAddress::to_payment_address) to convert back +/// (with pk_d validation). +/// +/// Requires the `shielded-bundle-building` feature. +#[cfg(feature = "shielded-bundle-building")] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct OrchardAddress { + /// 11-byte diversifier derived from the FullViewingKey with an index. + diversifier: [u8; ORCHARD_DIVERSIFIER_SIZE], + /// 32-byte diversified transmission key (point on the Pallas curve). + pk_d: [u8; ORCHARD_PKD_SIZE], +} + +#[cfg(feature = "shielded-bundle-building")] +impl OrchardAddress { + /// Type byte for Orchard addresses in bech32m encoding (user-facing). + /// Produces 'z' as the first bech32 character. + pub const ORCHARD_TYPE: u8 = 0x10; + + /// Creates an OrchardAddress from its raw components. + pub fn from_parts( + diversifier: [u8; ORCHARD_DIVERSIFIER_SIZE], + pk_d: [u8; ORCHARD_PKD_SIZE], + ) -> Self { + Self { diversifier, pk_d } + } + + /// Creates an OrchardAddress from a 43-byte raw address. + /// + /// The first 11 bytes are the diversifier, the next 32 are pk_d. + /// No validation is performed on pk_d; use [`From`] + /// for a pre-validated address. + pub fn from_raw_bytes(bytes: &[u8; ORCHARD_ADDRESS_SIZE]) -> Self { + let mut diversifier = [0u8; ORCHARD_DIVERSIFIER_SIZE]; + let mut pk_d = [0u8; ORCHARD_PKD_SIZE]; + diversifier.copy_from_slice(&bytes[..ORCHARD_DIVERSIFIER_SIZE]); + pk_d.copy_from_slice(&bytes[ORCHARD_DIVERSIFIER_SIZE..]); + Self { diversifier, pk_d } + } + + /// Returns the raw 43-byte address (diversifier || pk_d). + pub fn to_raw_bytes(&self) -> [u8; ORCHARD_ADDRESS_SIZE] { + let mut bytes = [0u8; ORCHARD_ADDRESS_SIZE]; + bytes[..ORCHARD_DIVERSIFIER_SIZE].copy_from_slice(&self.diversifier); + bytes[ORCHARD_DIVERSIFIER_SIZE..].copy_from_slice(&self.pk_d); + bytes + } + + /// Returns the 11-byte diversifier. + pub fn diversifier(&self) -> &[u8; ORCHARD_DIVERSIFIER_SIZE] { + &self.diversifier + } + + /// Returns the 32-byte diversified transmission key. + pub fn pk_d(&self) -> &[u8; ORCHARD_PKD_SIZE] { + &self.pk_d + } + + /// Encodes the OrchardAddress as a bech32m string for the specified network. + /// + /// Format: `1` + /// - Data: type_byte (0x10) || diversifier (11 bytes) || pk_d (32 bytes) + /// - Total payload: 44 bytes + /// - Checksum: bech32m (BIP-350) + /// + /// # Example + /// ```ignore + /// let address = OrchardAddress::from_raw_bytes(&raw_bytes); + /// let encoded = address.to_bech32m_string(Network::Dash); + /// // Returns something like "dash1z..." + /// ``` + pub fn to_bech32m_string(&self, network: Network) -> String { + let hrp_str = PlatformAddress::hrp_for_network(network); + let hrp = Hrp::parse(hrp_str).expect("HRP is valid"); + + let mut payload = Vec::with_capacity(1 + ORCHARD_ADDRESS_SIZE); + payload.push(Self::ORCHARD_TYPE); + payload.extend_from_slice(&self.diversifier); + payload.extend_from_slice(&self.pk_d); + + bech32::encode::(hrp, &payload).expect("encoding should succeed") + } + + /// Converts this address to an Orchard [`PaymentAddress`](grovedb_commitment_tree::PaymentAddress). + /// + /// Returns an error if `pk_d` is not a valid Pallas curve point. + pub fn to_payment_address( + &self, + ) -> Result { + crate::shielded::builder::orchard_address_to_payment_address(self) + } + + /// Decodes a bech32m-encoded Orchard address string. + /// + /// # Returns + /// - `Ok((OrchardAddress, Network))` - The decoded address and its network + /// - `Err(ProtocolError)` - If the address is invalid + pub fn from_bech32m_string(s: &str) -> Result<(Self, Network), ProtocolError> { + let (hrp, data) = + bech32::decode(s).map_err(|e| ProtocolError::DecodingError(format!("{}", e)))?; + + let hrp_lower = hrp.as_str().to_ascii_lowercase(); + let network = match hrp_lower.as_str() { + s if s == PLATFORM_HRP_MAINNET => Network::Dash, + s if s == PLATFORM_HRP_TESTNET => Network::Testnet, + _ => { + return Err(ProtocolError::DecodingError(format!( + "invalid HRP '{}': expected '{}' or '{}'", + hrp, PLATFORM_HRP_MAINNET, PLATFORM_HRP_TESTNET + ))) + } + }; + + // Validate payload: 1 type byte + 11 diversifier + 32 pk_d = 44 bytes + if data.len() != 1 + ORCHARD_ADDRESS_SIZE { + return Err(ProtocolError::DecodingError(format!( + "invalid Orchard address length: expected {} bytes, got {}", + 1 + ORCHARD_ADDRESS_SIZE, + data.len() + ))); + } + + if data[0] != Self::ORCHARD_TYPE { + return Err(ProtocolError::DecodingError(format!( + "invalid Orchard address type byte: expected 0x{:02x}, got 0x{:02x}", + Self::ORCHARD_TYPE, + data[0] + ))); + } + + let mut diversifier = [0u8; ORCHARD_DIVERSIFIER_SIZE]; + let mut pk_d = [0u8; ORCHARD_PKD_SIZE]; + diversifier.copy_from_slice(&data[1..1 + ORCHARD_DIVERSIFIER_SIZE]); + pk_d.copy_from_slice(&data[1 + ORCHARD_DIVERSIFIER_SIZE..]); + + Ok((Self { diversifier, pk_d }, network)) + } +} + +/// Infallible conversion from the orchard crate's `PaymentAddress` to `OrchardAddress`. +/// +/// Extracts the raw 43 bytes (diversifier || pk_d) from the validated address. +#[cfg(feature = "shielded-bundle-building")] +impl From for OrchardAddress { + fn from(addr: grovedb_commitment_tree::PaymentAddress) -> Self { + Self::from_raw_bytes(&addr.to_raw_address_bytes()) + } +} + +/// Infallible conversion from a reference to `PaymentAddress`. +#[cfg(feature = "shielded-bundle-building")] +impl From<&grovedb_commitment_tree::PaymentAddress> for OrchardAddress { + fn from(addr: &grovedb_commitment_tree::PaymentAddress) -> Self { + Self::from_raw_bytes(&addr.to_raw_address_bytes()) + } +} + +#[cfg(feature = "shielded-bundle-building")] +impl std::fmt::Display for OrchardAddress { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "Orchard(d={}, pk_d={})", + hex::encode(self.diversifier), + hex::encode(self.pk_d) + ) + } +} + impl std::fmt::Display for PlatformAddress { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -1303,7 +1501,7 @@ mod tests { assert_eq!(p2pkh.to_bytes()[0], 0x00); assert_eq!(p2sh.to_bytes()[0], 0x01); - // Bech32m encoding uses 0xb0/0x80 (verified by successful roundtrip) + // Bech32m encoding uses 0xb0/0xb8 (verified by successful roundtrip) let p2pkh_encoded = p2pkh.to_bech32m_string(Network::Dash); let p2sh_encoded = p2sh.to_bech32m_string(Network::Dash); @@ -1313,4 +1511,149 @@ mod tests { assert_eq!(p2pkh_decoded, p2pkh); assert_eq!(p2sh_decoded, p2sh); } + + // ======================== + // Orchard address tests (require shielded-bundle-building feature) + // ======================== + + #[cfg(feature = "shielded-bundle-building")] + #[test] + fn test_orchard_address_from_parts_roundtrip() { + let diversifier = [ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + ]; + let pk_d = [0xAB; 32]; + let address = OrchardAddress::from_parts(diversifier, pk_d); + + assert_eq!(address.diversifier(), &diversifier); + assert_eq!(address.pk_d(), &pk_d); + + let raw = address.to_raw_bytes(); + assert_eq!(raw.len(), 43); + assert_eq!(&raw[..11], &diversifier); + assert_eq!(&raw[11..], &pk_d[..]); + + let recovered = OrchardAddress::from_raw_bytes(&raw); + assert_eq!(recovered, address); + } + + #[cfg(feature = "shielded-bundle-building")] + #[test] + fn test_orchard_bech32m_mainnet_roundtrip() { + let diversifier = [ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + ]; + let pk_d = [0xAB; 32]; + let address = OrchardAddress::from_parts(diversifier, pk_d); + + let encoded = address.to_bech32m_string(Network::Dash); + assert!( + encoded.starts_with("dash1z"), + "Orchard mainnet address should start with 'dash1z', got: {}", + encoded + ); + + let (decoded, network) = + OrchardAddress::from_bech32m_string(&encoded).expect("decoding should succeed"); + assert_eq!(decoded, address); + assert_eq!(network, Network::Dash); + } + + #[cfg(feature = "shielded-bundle-building")] + #[test] + fn test_orchard_bech32m_testnet_roundtrip() { + let diversifier = [0xFF; 11]; + let pk_d = [0x42; 32]; + let address = OrchardAddress::from_parts(diversifier, pk_d); + + let encoded = address.to_bech32m_string(Network::Testnet); + assert!( + encoded.starts_with("tdash1z"), + "Orchard testnet address should start with 'tdash1z', got: {}", + encoded + ); + + let (decoded, network) = + OrchardAddress::from_bech32m_string(&encoded).expect("decoding should succeed"); + assert_eq!(decoded, address); + assert_eq!(network, Network::Testnet); + } + + #[cfg(feature = "shielded-bundle-building")] + #[test] + fn test_orchard_bech32m_wrong_type_byte_fails() { + // Manually construct an address with P2PKH type byte (0xb0) but 44-byte payload + let hrp = Hrp::parse("dash").unwrap(); + let mut payload = vec![PlatformAddress::P2PKH_TYPE]; // Wrong type byte + payload.extend_from_slice(&[0u8; 43]); + let encoded = bech32::encode::(hrp, &payload).unwrap(); + + let result = OrchardAddress::from_bech32m_string(&encoded); + assert!(result.is_err()); + assert!(result + .unwrap_err() + .to_string() + .contains("invalid Orchard address type byte")); + } + + #[cfg(feature = "shielded-bundle-building")] + #[test] + fn test_orchard_bech32m_wrong_length_fails() { + // Too short (only 20 bytes instead of 43) + let hrp = Hrp::parse("dash").unwrap(); + let mut payload = vec![OrchardAddress::ORCHARD_TYPE]; + payload.extend_from_slice(&[0u8; 20]); + let encoded = bech32::encode::(hrp, &payload).unwrap(); + + let result = OrchardAddress::from_bech32m_string(&encoded); + assert!(result.is_err()); + assert!(result + .unwrap_err() + .to_string() + .contains("invalid Orchard address length")); + } + + #[cfg(feature = "shielded-bundle-building")] + #[test] + fn test_orchard_and_platform_addresses_are_distinguishable() { + // Verify that the type bytes produce distinct prefixes + let p2pkh = PlatformAddress::P2pkh([0xAB; 20]); + let p2sh = PlatformAddress::P2sh([0xAB; 20]); + let orchard = OrchardAddress::from_parts([0xAB; 11], [0xAB; 32]); + + let p2pkh_enc = p2pkh.to_bech32m_string(Network::Dash); + let p2sh_enc = p2sh.to_bech32m_string(Network::Dash); + let orchard_enc = orchard.to_bech32m_string(Network::Dash); + + // All three start with "dash1" but have different type-byte characters + assert!(p2pkh_enc.starts_with("dash1k"), "P2PKH: {}", p2pkh_enc); + assert!(p2sh_enc.starts_with("dash1s"), "P2SH: {}", p2sh_enc); + assert!( + orchard_enc.starts_with("dash1z"), + "Orchard: {}", + orchard_enc + ); + + // Cross-decoding should fail + assert!(PlatformAddress::from_bech32m_string(&orchard_enc).is_err()); + assert!(OrchardAddress::from_bech32m_string(&p2pkh_enc).is_err()); + } + + #[cfg(feature = "shielded-bundle-building")] + #[test] + fn test_orchard_address_all_zeros() { + let address = OrchardAddress::from_parts([0u8; 11], [0u8; 32]); + let encoded = address.to_bech32m_string(Network::Dash); + let (decoded, _) = OrchardAddress::from_bech32m_string(&encoded).unwrap(); + assert_eq!(decoded, address); + } + + #[cfg(feature = "shielded-bundle-building")] + #[test] + fn test_orchard_address_display() { + let address = OrchardAddress::from_parts([0x01; 11], [0x02; 32]); + let display = format!("{}", address); + assert!(display.starts_with("Orchard(d=")); + assert!(display.contains("pk_d=")); + } } diff --git a/packages/rs-dpp/src/shielded/builder.rs b/packages/rs-dpp/src/shielded/builder.rs new file mode 100644 index 00000000000..57c5821c8d6 --- /dev/null +++ b/packages/rs-dpp/src/shielded/builder.rs @@ -0,0 +1,537 @@ +//! Convenience builders for constructing shielded state transitions. +//! +//! These functions encapsulate the full Orchard bundle construction pipeline: +//! builder configuration, proof generation, signature application, +//! and serialization into platform state transitions. +//! +//! Requires the `shielded-bundle-building` feature, which pulls in +//! `grovedb-commitment-tree` (and transitively the `orchard` crate). +//! +//! # Example +//! +//! ```ignore +//! use dpp::shielded::builder::*; +//! use grovedb_commitment_tree::{SpendingKey, FullViewingKey, Scope, ProvingKey}; +//! +//! // Derive recipient address +//! let sk = SpendingKey::from_bytes(seed)?; +//! let fvk = FullViewingKey::from(&sk); +//! let recipient = OrchardAddress::from_raw_bytes( +//! &fvk.address_at(0, Scope::External).to_raw_address_bytes(), +//! ); +//! +//! // Build a shield transition +//! let pk = ProvingKey::build(); +//! let st = build_shield_transition( +//! &recipient, shield_amount, inputs, fee_strategy, +//! &signer, 0, &pk, [0u8; 36], platform_version, +//! )?; +//! ``` + +use std::collections::BTreeMap; + +use grovedb_commitment_tree::{ + Anchor, Authorized, Builder, Bundle, BundleType, DashMemo, Flags as OrchardFlags, + FullViewingKey, MerklePath, Note, NoteValue, PaymentAddress, ProvingKey, SpendAuthorizingKey, +}; +use rand::rngs::OsRng; + +use crate::address_funds::AddressFundsFeeStrategy; +use crate::address_funds::{OrchardAddress, PlatformAddress}; +use crate::fee::Credits; +use crate::identity::core_script::CoreScript; +use crate::identity::signer::Signer; +use crate::prelude::{AddressNonce, UserFeeIncrease}; +use crate::shielded::{compute_platform_sighash, SerializedAction}; +use crate::state_transition::shield_from_asset_lock_transition::methods::ShieldFromAssetLockTransitionMethodsV0; +use crate::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; +use crate::state_transition::shield_transition::methods::ShieldTransitionMethodsV0; +use crate::state_transition::shield_transition::ShieldTransition; +use crate::state_transition::shielded_transfer_transition::methods::ShieldedTransferTransitionMethodsV0; +use crate::state_transition::shielded_transfer_transition::ShieldedTransferTransition; +use crate::state_transition::shielded_withdrawal_transition::methods::ShieldedWithdrawalTransitionMethodsV0; +use crate::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; +use crate::state_transition::unshield_transition::methods::UnshieldTransitionMethodsV0; +use crate::state_transition::unshield_transition::UnshieldTransition; +use crate::state_transition::StateTransition; +use crate::withdrawal::Pooling; +use crate::ProtocolError; +use platform_version::version::PlatformVersion; + +/// A note that can be spent in a shielded transaction, paired with its +/// Merkle inclusion path in the commitment tree. +pub struct SpendableNote { + /// The Orchard note to spend. + pub note: Note, + /// Merkle path proving the note's commitment exists in the tree. + pub merkle_path: MerklePath, +} + +/// Converts an [`OrchardAddress`] to an Orchard [`PaymentAddress`]. +/// +/// Returns an error if `pk_d` is not a valid Pallas curve point. +pub fn orchard_address_to_payment_address( + address: &OrchardAddress, +) -> Result { + let raw = address.to_raw_bytes(); + Option::from(PaymentAddress::from_raw_address_bytes(&raw)).ok_or_else(|| { + ProtocolError::DecodingError( + "OrchardAddress pk_d is not a valid Pallas curve point".to_string(), + ) + }) +} + +/// Serializes an authorized Orchard bundle into the raw fields used by +/// state transition constructors. +/// +/// Returns `(actions, flags, value_balance, anchor, proof, binding_signature)`. +pub fn serialize_authorized_bundle( + bundle: &Bundle, +) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { + let actions: Vec = bundle + .actions() + .iter() + .map(|action| { + let enc = action.encrypted_note(); + let mut encrypted_note = Vec::with_capacity(216); + encrypted_note.extend_from_slice(&enc.epk_bytes); + encrypted_note.extend_from_slice(enc.enc_ciphertext.as_ref()); + encrypted_note.extend_from_slice(&enc.out_ciphertext); + SerializedAction { + nullifier: action.nullifier().to_bytes(), + rk: <[u8; 32]>::from(action.rk()), + cmx: action.cmx().to_bytes(), + encrypted_note, + cv_net: action.cv_net().to_bytes(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()), + } + }) + .collect(); + let flags = bundle.flags().to_byte(); + let value_balance = *bundle.value_balance(); + let anchor = bundle.anchor().to_bytes(); + let proof = bundle.authorization().proof().as_ref().to_vec(); + let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); + (actions, flags, value_balance, anchor, proof, binding_sig) +} + +// --------------------------------------------------------------------------- +// Internal helpers +// --------------------------------------------------------------------------- + +/// Builds an output-only Orchard bundle (no spends). +/// +/// Used by Shield and ShieldFromAssetLock transitions where funds enter +/// the shielded pool from transparent sources. +fn build_output_only_bundle( + recipient: &OrchardAddress, + amount: u64, + memo: [u8; 36], + proving_key: &ProvingKey, +) -> Result, ProtocolError> { + let payment_address = orchard_address_to_payment_address(recipient)?; + let anchor = Anchor::empty_tree(); + let mut builder = Builder::::new( + BundleType::Transactional { + flags: OrchardFlags::SPENDS_DISABLED, + bundle_required: false, + }, + anchor, + ); + + builder + .add_output(None, payment_address, NoteValue::from_raw(amount), memo) + .map_err(|e| ProtocolError::Generic(format!("failed to add output: {:?}", e)))?; + + prove_and_sign_bundle(builder, proving_key, &[], &[]) +} + +/// Builds a spend+output Orchard bundle. +/// +/// Used by ShieldedTransfer, Unshield, and ShieldedWithdrawal where funds +/// are spent from existing notes. +fn build_spend_bundle( + spends: Vec, + recipient: &OrchardAddress, + output_amount: u64, + memo: [u8; 36], + fvk: &FullViewingKey, + ask: &SpendAuthorizingKey, + anchor: Anchor, + proving_key: &ProvingKey, + extra_sighash_data: &[u8], +) -> Result, ProtocolError> { + let payment_address = orchard_address_to_payment_address(recipient)?; + + let mut builder = Builder::::new(BundleType::DEFAULT, anchor); + + for spend in spends { + builder + .add_spend(fvk.clone(), spend.note, spend.merkle_path) + .map_err(|e| ProtocolError::Generic(format!("failed to add spend: {:?}", e)))?; + } + + builder + .add_output( + None, + payment_address, + NoteValue::from_raw(output_amount), + memo, + ) + .map_err(|e| ProtocolError::Generic(format!("failed to add output: {:?}", e)))?; + + prove_and_sign_bundle(builder, proving_key, &[ask.clone()], extra_sighash_data) +} + +/// Takes a configured Builder, generates the proof, computes the platform +/// sighash, and applies signatures. +fn prove_and_sign_bundle( + builder: Builder, + proving_key: &ProvingKey, + signing_keys: &[SpendAuthorizingKey], + extra_sighash_data: &[u8], +) -> Result, ProtocolError> { + let mut rng = OsRng; + + let (unauthorized, _) = builder + .build::(&mut rng) + .map_err(|e| ProtocolError::Generic(format!("failed to build bundle: {:?}", e)))? + .ok_or_else(|| ProtocolError::Generic("bundle was empty after build".to_string()))?; + + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, extra_sighash_data); + + let proven = unauthorized + .create_proof(proving_key, &mut rng) + .map_err(|e| ProtocolError::Generic(format!("failed to create proof: {:?}", e)))?; + + proven + .apply_signatures(rng, sighash, signing_keys) + .map_err(|e| ProtocolError::Generic(format!("failed to apply signatures: {:?}", e))) +} + +// --------------------------------------------------------------------------- +// Public builder functions +// --------------------------------------------------------------------------- + +/// Builds a Shield state transition (transparent platform addresses -> shielded pool). +/// +/// Constructs an output-only Orchard bundle (no spends), proves it, signs the +/// transparent input witnesses, and returns a ready-to-broadcast `StateTransition`. +/// +/// # Parameters +/// - `recipient` - Orchard address to receive the shielded note +/// - `shield_amount` - Amount of credits to shield +/// - `inputs` - Platform address inputs with their nonces and balances +/// - `fee_strategy` - How to deduct fees from the transparent inputs +/// - `signer` - Signs each input address witness (ECDSA) +/// - `user_fee_increase` - Fee multiplier (0 = 100% base fee) +/// - `proving_key` - Halo 2 proving key (cache with `OnceLock` — ~30s to build) +/// - `memo` - 36-byte structured memo for the recipient (4-byte type tag + 32-byte payload) +/// - `platform_version` - Protocol version +pub fn build_shield_transition>( + recipient: &OrchardAddress, + shield_amount: u64, + inputs: BTreeMap, + fee_strategy: AddressFundsFeeStrategy, + signer: &S, + user_fee_increase: UserFeeIncrease, + proving_key: &ProvingKey, + memo: [u8; 36], + platform_version: &PlatformVersion, +) -> Result { + let bundle = build_output_only_bundle(recipient, shield_amount, memo, proving_key)?; + let (actions, flags, value_balance, anchor, proof, binding_sig) = + serialize_authorized_bundle(&bundle); + + ShieldTransition::try_from_bundle_with_signer( + inputs, + actions, + flags, + value_balance, + anchor, + proof, + binding_sig, + fee_strategy, + signer, + user_fee_increase, + platform_version, + ) +} + +/// Builds a ShieldFromAssetLock state transition (core asset lock -> shielded pool). +/// +/// Like Shield, constructs an output-only Orchard bundle. The funds come from +/// a core asset lock proof rather than platform address inputs. +/// +/// # Parameters +/// - `recipient` - Orchard address to receive the shielded note +/// - `shield_amount` - Amount of credits to shield (from the asset lock) +/// - `asset_lock_proof` - Proof that funds are locked on core chain +/// - `asset_lock_private_key` - Private key for the asset lock (signs the transition) +/// - `user_fee_increase` - Fee multiplier (0 = 100% base fee) +/// - `proving_key` - Halo 2 proving key +/// - `memo` - 36-byte structured memo for the recipient (4-byte type tag + 32-byte payload) +/// - `platform_version` - Protocol version +pub fn build_shield_from_asset_lock_transition( + recipient: &OrchardAddress, + shield_amount: u64, + asset_lock_proof: crate::prelude::AssetLockProof, + asset_lock_private_key: &[u8], + user_fee_increase: UserFeeIncrease, + proving_key: &ProvingKey, + memo: [u8; 36], + platform_version: &PlatformVersion, +) -> Result { + let bundle = build_output_only_bundle(recipient, shield_amount, memo, proving_key)?; + let (actions, flags, value_balance, anchor, proof, binding_sig) = + serialize_authorized_bundle(&bundle); + + ShieldFromAssetLockTransition::try_from_asset_lock_with_bundle( + asset_lock_proof, + asset_lock_private_key, + actions, + flags, + value_balance, + anchor, + proof, + binding_sig, + user_fee_increase, + platform_version, + ) +} + +/// Builds a ShieldedTransfer state transition (shielded pool -> shielded pool). +/// +/// Spends existing notes and creates a new note for the recipient. Any change +/// (total spent - transfer amount) is returned to the `change_address`. +/// +/// # Parameters +/// - `spends` - Notes to spend with their Merkle paths +/// - `recipient` - Orchard address to receive the transferred note +/// - `transfer_amount` - Amount to transfer to the recipient +/// - `change_address` - Orchard address for change output (if any) +/// - `fvk` - Full viewing key for spend authorization +/// - `ask` - Spend authorizing key for RedPallas signatures +/// - `anchor` - Merkle root of the commitment tree +/// - `proving_key` - Halo 2 proving key +/// - `memo` - 36-byte structured memo for the recipient (4-byte type tag + 32-byte payload) +/// - `platform_version` - Protocol version +pub fn build_shielded_transfer_transition( + spends: Vec, + recipient: &OrchardAddress, + transfer_amount: u64, + change_address: &OrchardAddress, + fvk: &FullViewingKey, + ask: &SpendAuthorizingKey, + anchor: Anchor, + proving_key: &ProvingKey, + memo: [u8; 36], + platform_version: &PlatformVersion, +) -> Result { + let total_spent: u64 = spends.iter().map(|s| s.note.value().inner()).sum(); + if transfer_amount > total_spent { + return Err(ProtocolError::Generic(format!( + "transfer amount {} exceeds total spendable value {}", + transfer_amount, total_spent + ))); + } + + let change_amount = total_spent - transfer_amount; + + let recipient_payment = orchard_address_to_payment_address(recipient)?; + + let mut builder = Builder::::new(BundleType::DEFAULT, anchor); + + for spend in spends { + builder + .add_spend(fvk.clone(), spend.note, spend.merkle_path) + .map_err(|e| ProtocolError::Generic(format!("failed to add spend: {:?}", e)))?; + } + + // Primary output to recipient + builder + .add_output( + None, + recipient_payment, + NoteValue::from_raw(transfer_amount), + memo, + ) + .map_err(|e| ProtocolError::Generic(format!("failed to add output: {:?}", e)))?; + + // Change output (if any) + if change_amount > 0 { + let change_payment = orchard_address_to_payment_address(change_address)?; + builder + .add_output( + None, + change_payment, + NoteValue::from_raw(change_amount), + [0u8; 36], + ) + .map_err(|e| ProtocolError::Generic(format!("failed to add change output: {:?}", e)))?; + } + + // ShieldedTransfer has no extra_data in sighash + let bundle = prove_and_sign_bundle(builder, proving_key, &[ask.clone()], &[])?; + let (actions, flags, value_balance, anchor_bytes, proof, binding_sig) = + serialize_authorized_bundle(&bundle); + + // value_balance for shielded transfer is u64; cast from i64 + // (should be 0 when transfer_amount == total_spent, positive if fees leave pool) + ShieldedTransferTransition::try_from_bundle( + actions, + flags, + value_balance as u64, + anchor_bytes, + proof, + binding_sig, + platform_version, + ) +} + +/// Builds an Unshield state transition (shielded pool -> platform address). +/// +/// Spends existing notes and sends part of the value to a transparent platform +/// address. Any remaining value is returned to the shielded `change_address`. +/// +/// # Parameters +/// - `spends` - Notes to spend with their Merkle paths +/// - `output_address` - Platform address to receive the unshielded funds +/// - `unshield_amount` - Amount to unshield to the platform address +/// - `change_address` - Orchard address for change output +/// - `fvk` - Full viewing key for spend authorization +/// - `ask` - Spend authorizing key for RedPallas signatures +/// - `anchor` - Merkle root of the commitment tree +/// - `proving_key` - Halo 2 proving key +/// - `memo` - 36-byte structured memo for the change output (4-byte type tag + 32-byte payload) +/// - `platform_version` - Protocol version +pub fn build_unshield_transition( + spends: Vec, + output_address: PlatformAddress, + unshield_amount: u64, + change_address: &OrchardAddress, + fvk: &FullViewingKey, + ask: &SpendAuthorizingKey, + anchor: Anchor, + proving_key: &ProvingKey, + memo: [u8; 36], + platform_version: &PlatformVersion, +) -> Result { + let total_spent: u64 = spends.iter().map(|s| s.note.value().inner()).sum(); + if unshield_amount > total_spent { + return Err(ProtocolError::Generic(format!( + "unshield amount {} exceeds total spendable value {}", + unshield_amount, total_spent + ))); + } + + let change_amount = total_spent - unshield_amount; + + // Unshield extra_data = output_address.to_bytes() || amount.to_le_bytes() + let mut extra_sighash_data = output_address.to_bytes(); + extra_sighash_data.extend_from_slice(&unshield_amount.to_le_bytes()); + + let bundle = build_spend_bundle( + spends, + change_address, + change_amount, + memo, + fvk, + ask, + anchor, + proving_key, + &extra_sighash_data, + )?; + + let (actions, flags, value_balance, anchor_bytes, proof, binding_sig) = + serialize_authorized_bundle(&bundle); + + UnshieldTransition::try_from_bundle( + output_address, + unshield_amount, + actions, + flags, + value_balance, + anchor_bytes, + proof, + binding_sig, + platform_version, + ) +} + +/// Builds a ShieldedWithdrawal state transition (shielded pool -> core L1 address). +/// +/// Spends existing notes and withdraws value to a core chain script output. +/// Any remaining value is returned to the shielded `change_address`. +/// +/// # Parameters +/// - `spends` - Notes to spend with their Merkle paths +/// - `withdrawal_amount` - Amount to withdraw to the core chain +/// - `output_script` - Core chain script to receive the funds +/// - `core_fee_per_byte` - Core chain fee rate +/// - `pooling` - Withdrawal pooling strategy +/// - `change_address` - Orchard address for change output +/// - `fvk` - Full viewing key for spend authorization +/// - `ask` - Spend authorizing key for RedPallas signatures +/// - `anchor` - Merkle root of the commitment tree +/// - `proving_key` - Halo 2 proving key +/// - `memo` - 36-byte structured memo for the change output (4-byte type tag + 32-byte payload) +/// - `platform_version` - Protocol version +pub fn build_shielded_withdrawal_transition( + spends: Vec, + withdrawal_amount: u64, + output_script: CoreScript, + core_fee_per_byte: u32, + pooling: Pooling, + change_address: &OrchardAddress, + fvk: &FullViewingKey, + ask: &SpendAuthorizingKey, + anchor: Anchor, + proving_key: &ProvingKey, + memo: [u8; 36], + platform_version: &PlatformVersion, +) -> Result { + let total_spent: u64 = spends.iter().map(|s| s.note.value().inner()).sum(); + if withdrawal_amount > total_spent { + return Err(ProtocolError::Generic(format!( + "withdrawal amount {} exceeds total spendable value {}", + withdrawal_amount, total_spent + ))); + } + + let change_amount = total_spent - withdrawal_amount; + + // ShieldedWithdrawal extra_data = output_script.as_bytes() || amount.to_le_bytes() + let mut extra_sighash_data = output_script.as_bytes().to_vec(); + extra_sighash_data.extend_from_slice(&withdrawal_amount.to_le_bytes()); + + let bundle = build_spend_bundle( + spends, + change_address, + change_amount, + memo, + fvk, + ask, + anchor, + proving_key, + &extra_sighash_data, + )?; + + let (actions, flags, value_balance, anchor_bytes, proof, binding_sig) = + serialize_authorized_bundle(&bundle); + + ShieldedWithdrawalTransition::try_from_bundle( + withdrawal_amount, + actions, + flags, + value_balance, + anchor_bytes, + proof, + binding_sig, + core_fee_per_byte, + pooling, + output_script, + platform_version, + ) +} diff --git a/packages/rs-dpp/src/shielded/mod.rs b/packages/rs-dpp/src/shielded/mod.rs index 78d244e79d1..0690ffcab8b 100644 --- a/packages/rs-dpp/src/shielded/mod.rs +++ b/packages/rs-dpp/src/shielded/mod.rs @@ -1,3 +1,6 @@ +#[cfg(feature = "shielded-bundle-building")] +pub mod builder; + use bincode::{Decode, Encode}; #[cfg(feature = "state-transition-serde-conversion")] use serde::{Deserialize, Serialize}; @@ -105,11 +108,11 @@ pub struct SerializedAction { /// decryption key) can identify and spend this note. pub cmx: [u8; 32], - /// Encrypted note ciphertext (692 bytes = epk 32 + enc_ciphertext 580 + out_ciphertext 80). + /// Encrypted note ciphertext (216 bytes = epk 32 + enc_ciphertext 104 + out_ciphertext 80). /// Contains the `TransmittedNoteCiphertext` fields packed contiguously: - /// - `epk`: ephemeral public key for Diffie-Hellman key agreement - /// - `enc_ciphertext`: note plaintext encrypted to the recipient (value, address, memo) - /// - `out_ciphertext`: encrypted to the sender for wallet recovery + /// - `epk`: ephemeral public key for Diffie-Hellman key agreement (32 bytes) + /// - `enc_ciphertext`: note plaintext encrypted to the recipient (104 bytes = 52 compact + 36 memo + 16 AEAD tag) + /// - `out_ciphertext`: encrypted to the sender for wallet recovery (80 bytes) /// Stored on-chain so recipients can scan and decrypt notes addressed to them. /// Only the intended recipient (or sender) can decrypt; all others see random bytes. pub encrypted_note: Vec, diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index 5b5fe4dcd11..125894cbc8a 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -83,7 +83,6 @@ async-trait = "0.1.77" console-subscriber = { version = "0.4", optional = true } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f", optional = true } grovedb-commitment-tree = { path = "../../../grovedb/grovedb-commitment-tree" } -orchard = "0.12" sha2 = "0.10" nonempty = "0.11" diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs index ab650c6ca4a..fee944e2aa2 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs @@ -24,7 +24,7 @@ mod tests { use dpp::state_transition::shield_transition::ShieldTransition; use dpp::state_transition::StateTransition; use grovedb_commitment_tree::{ - Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, DashMemo, Flags as OrchardFlags, FullViewingKey, NoteValue, ProvingKey, Scope, SpendingKey, }; use platform_version::version::PlatformVersion; @@ -146,16 +146,16 @@ mod tests { /// Extract serialized fields from an authorized Orchard bundle into the /// platform-compatible format: (actions, flags, value_balance, anchor, proof, binding_sig). fn serialize_authorized_bundle( - bundle: &Bundle, + bundle: &Bundle, ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { let actions: Vec = bundle .actions() .iter() .map(|action| { let enc = action.encrypted_note(); - let mut encrypted_note = Vec::with_capacity(692); + let mut encrypted_note = Vec::with_capacity(216); encrypted_note.extend_from_slice(&enc.epk_bytes); - encrypted_note.extend_from_slice(&enc.enc_ciphertext); + encrypted_note.extend_from_slice(enc.enc_ciphertext.as_ref()); encrypted_note.extend_from_slice(&enc.out_ciphertext); SerializedAction { @@ -790,7 +790,7 @@ mod tests { let recipient = fvk.address_at(0u32, Scope::External); let anchor = Anchor::empty_tree(); - let mut builder = Builder::new( + let mut builder = Builder::::new( BundleType::Transactional { flags: OrchardFlags::SPENDS_DISABLED, bundle_required: false, @@ -804,7 +804,7 @@ mod tests { None, recipient, NoteValue::from_raw(shield_value), - [0u8; 512], + [0u8; 36], ) .unwrap(); @@ -877,7 +877,7 @@ mod tests { // Create action with wrong encrypted_note size let mut bad_action = create_dummy_serialized_action(); - bad_action.encrypted_note = vec![0u8; 100]; // 100 bytes instead of 692 + bad_action.encrypted_note = vec![0u8; 100]; // 100 bytes instead of 216 let mut inputs = BTreeMap::new(); inputs.insert(input_address, (1 as AddressNonce, dash_to_credits!(0.5))); @@ -978,7 +978,7 @@ mod tests { let recipient = fvk.address_at(0u32, Scope::External); let anchor = Anchor::empty_tree(); - let mut builder = Builder::new( + let mut builder = Builder::::new( BundleType::Transactional { flags: OrchardFlags::SPENDS_DISABLED, bundle_required: false, @@ -987,7 +987,7 @@ mod tests { ); builder - .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 512]) + .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 36]) .unwrap(); let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs index b5e3c34f1bd..4b8d522fe00 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs @@ -21,7 +21,7 @@ mod tests { use dpp::state_transition::StateTransition; use dpp::tests::fixtures::instant_asset_lock_proof_fixture; use grovedb_commitment_tree::{ - Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, DashMemo, Flags as OrchardFlags, FullViewingKey, NoteValue, ProvingKey, Scope, SpendingKey, }; use platform_version::version::PlatformVersion; @@ -142,16 +142,16 @@ mod tests { /// Extract serialized fields from an authorized Orchard bundle into the /// platform-compatible format: (actions, flags, value_balance, anchor, proof, binding_sig). fn serialize_authorized_bundle( - bundle: &Bundle, + bundle: &Bundle, ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { let actions: Vec = bundle .actions() .iter() .map(|action| { let enc = action.encrypted_note(); - let mut encrypted_note = Vec::with_capacity(692); + let mut encrypted_note = Vec::with_capacity(216); encrypted_note.extend_from_slice(&enc.epk_bytes); - encrypted_note.extend_from_slice(&enc.enc_ciphertext); + encrypted_note.extend_from_slice(enc.enc_ciphertext.as_ref()); encrypted_note.extend_from_slice(&enc.out_ciphertext); SerializedAction { @@ -452,7 +452,7 @@ mod tests { let recipient = fvk.address_at(0u32, Scope::External); let anchor = Anchor::empty_tree(); - let mut builder = Builder::new( + let mut builder = Builder::::new( BundleType::Transactional { flags: OrchardFlags::SPENDS_DISABLED, bundle_required: false, @@ -466,7 +466,7 @@ mod tests { None, recipient, NoteValue::from_raw(shield_value), - [0u8; 512], + [0u8; 36], ) .unwrap(); @@ -612,7 +612,7 @@ mod tests { let recipient = fvk.address_at(0u32, Scope::External); let anchor = Anchor::empty_tree(); - let mut builder = Builder::new( + let mut builder = Builder::::new( BundleType::Transactional { flags: OrchardFlags::SPENDS_DISABLED, bundle_required: false, @@ -621,7 +621,7 @@ mod tests { ); builder - .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 512]) + .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 36]) .unwrap(); let (unauthorized, _) = builder.build::(&mut orchard_rng).unwrap().unwrap(); @@ -683,7 +683,7 @@ mod tests { let recipient = fvk.address_at(0u32, Scope::External); let anchor = Anchor::empty_tree(); - let mut builder = Builder::new( + let mut builder = Builder::::new( BundleType::Transactional { flags: OrchardFlags::SPENDS_DISABLED, bundle_required: false, @@ -692,7 +692,7 @@ mod tests { ); builder - .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 512]) + .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 36]) .unwrap(); let (unauthorized, _) = builder.build::(&mut orchard_rng).unwrap().unwrap(); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs index f999208ec22..1007b15ae6a 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs @@ -19,12 +19,10 @@ use drive::grovedb::TransactionArg; use drive::state_transition_action::StateTransitionAction; use drive::util::grove_operations::DirectQueryType; use grovedb_commitment_tree::{ - Action, Anchor, Authorized, BatchValidator, Bundle, ExtractedNoteCommitment, Flags, Nullifier, - Proof, VerifyingKey, + redpallas, Action, Anchor, Authorized, BatchValidator, Bundle, DashMemo, + ExtractedNoteCommitment, Flags, NoteBytesData, Nullifier, Proof, TransmittedNoteCiphertext, + ValueCommitment, VerifyingKey, }; -use orchard::note::TransmittedNoteCiphertext; -use orchard::primitives::redpallas; -use orchard::value::ValueCommitment; use std::sync::OnceLock; /// Cached verifying key for shielded proof verification. @@ -38,11 +36,11 @@ fn get_verifying_key() -> &'static VerifyingKey { } const EPK_SIZE: usize = 32; -const ENC_CIPHERTEXT_SIZE: usize = 580; +const ENC_CIPHERTEXT_SIZE: usize = 104; const OUT_CIPHERTEXT_SIZE: usize = 80; -const ENCRYPTED_NOTE_SIZE: usize = EPK_SIZE + ENC_CIPHERTEXT_SIZE + OUT_CIPHERTEXT_SIZE; // 692 +const ENCRYPTED_NOTE_SIZE: usize = EPK_SIZE + ENC_CIPHERTEXT_SIZE + OUT_CIPHERTEXT_SIZE; // 216 -/// Reconstructs an orchard `Bundle` from the serialized fields +/// Reconstructs an orchard `Bundle` from the serialized fields /// of a shielded state transition and verifies the Halo 2 ZK proof along with /// all RedPallas signatures (spend auth + binding). /// @@ -76,7 +74,7 @@ pub fn reconstruct_and_verify_bundle( // Reconstruct each Action let mut orchard_actions = Vec::with_capacity(actions.len()); for a in actions { - // Parse encrypted_note (692 bytes = epk 32 + enc 580 + out 80) + // Parse encrypted_note (216 bytes = epk 32 + enc 104 + out 80) if a.encrypted_note.len() != ENCRYPTED_NOTE_SIZE { return Err(InvalidShieldedProofError::new(format!( "encrypted note size mismatch: expected {ENCRYPTED_NOTE_SIZE}, got {}", @@ -116,11 +114,11 @@ pub fn reconstruct_and_verify_bundle( nullifier, rk, cmx, - TransmittedNoteCiphertext { + TransmittedNoteCiphertext::::from_parts( epk_bytes, - enc_ciphertext, + NoteBytesData(enc_ciphertext), out_ciphertext, - }, + ), cv_net, redpallas::Signature::from(a.spend_auth_sig), ); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs index e41c06a00a7..94912509794 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs @@ -231,11 +231,10 @@ mod tests { use super::*; use grovedb_commitment_tree::{ Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - ClientCommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, - NoteValue, Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, - SpendingKey, + ClientCommitmentTree, DashMemo, ExtractedNoteCommitment, FullViewingKey, MerklePath, + Note, NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, + SpendAuthorizingKey, SpendingKey, }; - use orchard::note::RandomSeed; use rand::rngs::OsRng; use std::sync::OnceLock; @@ -245,16 +244,16 @@ mod tests { } fn serialize_authorized_bundle( - bundle: &Bundle, + bundle: &Bundle, ) -> (Vec, u8, u64, [u8; 32], Vec, [u8; 64]) { let actions: Vec = bundle .actions() .iter() .map(|action| { let enc = action.encrypted_note(); - let mut encrypted_note = Vec::with_capacity(692); + let mut encrypted_note = Vec::with_capacity(216); encrypted_note.extend_from_slice(&enc.epk_bytes); - encrypted_note.extend_from_slice(&enc.enc_ciphertext); + encrypted_note.extend_from_slice(enc.enc_ciphertext.as_ref()); encrypted_note.extend_from_slice(&enc.out_ciphertext); SerializedAction { nullifier: action.nullifier().to_bytes(), @@ -332,10 +331,10 @@ mod tests { let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); // --- Build bundle: spend 10_000 → output 10_000 (value_balance = 0) --- - let mut builder = Builder::new(BundleType::DEFAULT, anchor); + let mut builder = Builder::::new(BundleType::DEFAULT, anchor); builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); builder - .add_output(None, recipient, NoteValue::from_raw(10_000), [0u8; 512]) + .add_output(None, recipient, NoteValue::from_raw(10_000), [0u8; 36]) .unwrap(); let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); @@ -419,11 +418,10 @@ mod tests { use super::*; use grovedb_commitment_tree::{ Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - ClientCommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, - NoteValue, Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, - SpendingKey, + ClientCommitmentTree, DashMemo, ExtractedNoteCommitment, FullViewingKey, MerklePath, + Note, NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, + SpendAuthorizingKey, SpendingKey, }; - use orchard::note::RandomSeed; use rand::rngs::OsRng; use std::sync::OnceLock; @@ -433,16 +431,16 @@ mod tests { } fn serialize_authorized_bundle( - bundle: &Bundle, + bundle: &Bundle, ) -> (Vec, u8, u64, [u8; 32], Vec, [u8; 64]) { let actions: Vec = bundle .actions() .iter() .map(|action| { let enc = action.encrypted_note(); - let mut encrypted_note = Vec::with_capacity(692); + let mut encrypted_note = Vec::with_capacity(216); encrypted_note.extend_from_slice(&enc.epk_bytes); - encrypted_note.extend_from_slice(&enc.enc_ciphertext); + encrypted_note.extend_from_slice(enc.enc_ciphertext.as_ref()); encrypted_note.extend_from_slice(&enc.out_ciphertext); SerializedAction { nullifier: action.nullifier().to_bytes(), @@ -491,10 +489,10 @@ mod tests { let anchor = tree.anchor().unwrap(); let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); - let mut builder = Builder::new(BundleType::DEFAULT, anchor); + let mut builder = Builder::::new(BundleType::DEFAULT, anchor); builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); builder - .add_output(None, recipient, NoteValue::from_raw(10_000), [0u8; 512]) + .add_output(None, recipient, NoteValue::from_raw(10_000), [0u8; 36]) .unwrap(); let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs index a33cc839399..1ae966236f4 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs @@ -386,10 +386,9 @@ mod tests { use super::*; use grovedb_commitment_tree::{ Authorized as OrchardAuthorized, Builder, Bundle, BundleType, ClientCommitmentTree, - ExtractedNoteCommitment, FullViewingKey, Note, NoteValue, Position, ProvingKey, - Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, + DashMemo, ExtractedNoteCommitment, FullViewingKey, Note, NoteValue, Position, + ProvingKey, RandomSeed, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, }; - use orchard::note::RandomSeed; use rand::rngs::OsRng; use std::sync::OnceLock; @@ -399,16 +398,16 @@ mod tests { } fn serialize_authorized_bundle( - bundle: &Bundle, + bundle: &Bundle, ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { let actions: Vec = bundle .actions() .iter() .map(|action| { let enc = action.encrypted_note(); - let mut encrypted_note = Vec::with_capacity(692); + let mut encrypted_note = Vec::with_capacity(216); encrypted_note.extend_from_slice(&enc.epk_bytes); - encrypted_note.extend_from_slice(&enc.enc_ciphertext); + encrypted_note.extend_from_slice(enc.enc_ciphertext.as_ref()); encrypted_note.extend_from_slice(&enc.out_ciphertext); SerializedAction { nullifier: action.nullifier().to_bytes(), @@ -491,10 +490,10 @@ mod tests { let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); // --- Build bundle: spend 10,000 -> output 5,000 (value_balance = 5,000) --- - let mut builder = Builder::new(BundleType::DEFAULT, anchor); + let mut builder = Builder::::new(BundleType::DEFAULT, anchor); builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); builder - .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 512]) + .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 36]) .unwrap(); let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); @@ -601,10 +600,9 @@ mod tests { use super::*; use grovedb_commitment_tree::{ Authorized as OrchardAuthorized, Builder, Bundle, BundleType, ClientCommitmentTree, - ExtractedNoteCommitment, FullViewingKey, Note, NoteValue, Position, ProvingKey, - Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, + DashMemo, ExtractedNoteCommitment, FullViewingKey, Note, NoteValue, Position, + ProvingKey, RandomSeed, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, }; - use orchard::note::RandomSeed; use rand::rngs::OsRng; use std::sync::OnceLock; @@ -614,16 +612,16 @@ mod tests { } fn serialize_authorized_bundle( - bundle: &Bundle, + bundle: &Bundle, ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { let actions: Vec = bundle .actions() .iter() .map(|action| { let enc = action.encrypted_note(); - let mut encrypted_note = Vec::with_capacity(692); + let mut encrypted_note = Vec::with_capacity(216); encrypted_note.extend_from_slice(&enc.epk_bytes); - encrypted_note.extend_from_slice(&enc.enc_ciphertext); + encrypted_note.extend_from_slice(enc.enc_ciphertext.as_ref()); encrypted_note.extend_from_slice(&enc.out_ciphertext); SerializedAction { nullifier: action.nullifier().to_bytes(), @@ -677,10 +675,10 @@ mod tests { let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); // Spend 10,000 -> output 5,000 -> value_balance = 5,000 - let mut builder = Builder::new(BundleType::DEFAULT, anchor); + let mut builder = Builder::::new(BundleType::DEFAULT, anchor); builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); builder - .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 512]) + .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 36]) .unwrap(); let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs index 635d8c9393b..265576a66a0 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs @@ -355,11 +355,10 @@ mod tests { use super::*; use grovedb_commitment_tree::{ Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - ClientCommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, - NoteValue, Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, - SpendingKey, + ClientCommitmentTree, DashMemo, ExtractedNoteCommitment, FullViewingKey, MerklePath, + Note, NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, + SpendAuthorizingKey, SpendingKey, }; - use orchard::note::RandomSeed; use rand::rngs::OsRng; use std::sync::OnceLock; @@ -369,16 +368,16 @@ mod tests { } fn serialize_authorized_bundle( - bundle: &Bundle, + bundle: &Bundle, ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { let actions: Vec = bundle .actions() .iter() .map(|action| { let enc = action.encrypted_note(); - let mut encrypted_note = Vec::with_capacity(692); + let mut encrypted_note = Vec::with_capacity(216); encrypted_note.extend_from_slice(&enc.epk_bytes); - encrypted_note.extend_from_slice(&enc.enc_ciphertext); + encrypted_note.extend_from_slice(enc.enc_ciphertext.as_ref()); encrypted_note.extend_from_slice(&enc.out_ciphertext); SerializedAction { nullifier: action.nullifier().to_bytes(), @@ -458,10 +457,10 @@ mod tests { let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); // --- Build bundle: spend 10,000 → output 5,000 (value_balance = 5,000) --- - let mut builder = Builder::new(BundleType::DEFAULT, anchor); + let mut builder = Builder::::new(BundleType::DEFAULT, anchor); builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); builder - .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 512]) + .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 36]) .unwrap(); let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); @@ -557,11 +556,10 @@ mod tests { use super::*; use grovedb_commitment_tree::{ Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - ClientCommitmentTree, ExtractedNoteCommitment, FullViewingKey, MerklePath, Note, - NoteValue, Position, ProvingKey, Retention, Rho, Scope, SpendAuthorizingKey, - SpendingKey, + ClientCommitmentTree, DashMemo, ExtractedNoteCommitment, FullViewingKey, MerklePath, + Note, NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, + SpendAuthorizingKey, SpendingKey, }; - use orchard::note::RandomSeed; use rand::rngs::OsRng; use std::sync::OnceLock; @@ -571,16 +569,16 @@ mod tests { } fn serialize_authorized_bundle( - bundle: &Bundle, + bundle: &Bundle, ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { let actions: Vec = bundle .actions() .iter() .map(|action| { let enc = action.encrypted_note(); - let mut encrypted_note = Vec::with_capacity(692); + let mut encrypted_note = Vec::with_capacity(216); encrypted_note.extend_from_slice(&enc.epk_bytes); - encrypted_note.extend_from_slice(&enc.enc_ciphertext); + encrypted_note.extend_from_slice(enc.enc_ciphertext.as_ref()); encrypted_note.extend_from_slice(&enc.out_ciphertext); SerializedAction { nullifier: action.nullifier().to_bytes(), @@ -634,10 +632,10 @@ mod tests { let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); // Spend 10,000 → output 5,000 → value_balance = 5,000 - let mut builder = Builder::new(BundleType::DEFAULT, anchor); + let mut builder = Builder::::new(BundleType::DEFAULT, anchor); builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); builder - .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 512]) + .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 36]) .unwrap(); let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); diff --git a/packages/rs-drive-abci/tests/strategy_tests/strategy.rs b/packages/rs-drive-abci/tests/strategy_tests/strategy.rs index 0c91649e13e..fbae6c67d5f 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/strategy.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/strategy.rs @@ -18,10 +18,10 @@ use dpp::state_transition::unshield_transition::UnshieldTransition; use dpp::ProtocolError; use grovedb_commitment_tree::{ Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, ClientCommitmentTree, - ExtractedNoteCommitment, Flags as OrchardFlags, FullViewingKey, MerklePath, Note, NoteValue, - Position, ProvingKey, Retention, Scope, SpendAuthorizingKey, SpendingKey, + DashMemo, ExtractedNoteCommitment, Flags as OrchardFlags, FullViewingKey, MerklePath, Note, + NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, SpendAuthorizingKey, + SpendingKey, }; -use orchard::note::RandomSeed; use dpp::dashcore::secp256k1::SecretKey; use dpp::data_contract::document_type::random_document::CreateRandomDocument; @@ -201,7 +201,7 @@ impl ShieldedState { rho_bytes[..8].copy_from_slice(&self.rho_counter.to_le_bytes()); self.rho_counter += 1; - let rho = orchard::note::Rho::from_bytes(&rho_bytes).unwrap(); + let rho = Rho::from_bytes(&rho_bytes).unwrap(); let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); let note = Note::from_parts(recipient, NoteValue::from_raw(value), rho, rseed).unwrap(); @@ -246,16 +246,16 @@ impl ShieldedState { /// Decompose an authorized Orchard bundle into platform serialization fields. fn serialize_authorized_bundle( - bundle: &Bundle, + bundle: &Bundle, ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { let actions: Vec = bundle .actions() .iter() .map(|action| { let enc = action.encrypted_note(); - let mut encrypted_note = Vec::with_capacity(692); + let mut encrypted_note = Vec::with_capacity(216); encrypted_note.extend_from_slice(&enc.epk_bytes); - encrypted_note.extend_from_slice(&enc.enc_ciphertext); + encrypted_note.extend_from_slice(enc.enc_ciphertext.as_ref()); encrypted_note.extend_from_slice(&enc.out_ciphertext); SerializedAction { nullifier: action.nullifier().to_bytes(), @@ -2735,7 +2735,7 @@ impl NetworkStrategy { // 3. Build output-only Orchard bundle (shield = outputs only, no spends) let anchor = Anchor::empty_tree(); - let mut builder = Builder::new( + let mut builder = Builder::::new( BundleType::Transactional { flags: OrchardFlags::SPENDS_DISABLED, bundle_required: false, @@ -2751,7 +2751,7 @@ impl NetworkStrategy { None, recipient, NoteValue::from_raw(shield_value), - [0u8; 512], + [0u8; 36], ) .expect("expected to add output"); @@ -2831,7 +2831,7 @@ impl NetworkStrategy { // 3. Build output-only Orchard bundle (same as Shield) let anchor = Anchor::empty_tree(); - let mut builder = Builder::new( + let mut builder = Builder::::new( BundleType::Transactional { flags: OrchardFlags::SPENDS_DISABLED, bundle_required: false, @@ -2844,7 +2844,7 @@ impl NetworkStrategy { None, recipient, NoteValue::from_raw(funded_amount), - [0u8; 512], + [0u8; 36], ) .expect("expected to add output"); @@ -2916,12 +2916,12 @@ impl NetworkStrategy { let recipient = fvk.address_at(0u32, Scope::External); // Build bundle: spend note -> output same value (value_balance = 0) - let mut builder = Builder::new(BundleType::DEFAULT, anchor); + let mut builder = Builder::::new(BundleType::DEFAULT, anchor); builder .add_spend(fvk, note, merkle_path) .expect("expected to add spend"); builder - .add_output(None, recipient, NoteValue::from_raw(note_value), [0u8; 512]) + .add_output(None, recipient, NoteValue::from_raw(note_value), [0u8; 36]) .expect("expected to add output"); let pk = get_proving_key(); @@ -2994,7 +2994,7 @@ impl NetworkStrategy { let change_amount = note_value - unshield_amount; // Build bundle: spend note -> output change (value_balance = unshield_amount) - let mut builder = Builder::new(BundleType::DEFAULT, anchor); + let mut builder = Builder::::new(BundleType::DEFAULT, anchor); builder .add_spend(fvk, note, merkle_path) .expect("expected to add spend"); @@ -3003,7 +3003,7 @@ impl NetworkStrategy { None, recipient, NoteValue::from_raw(change_amount), - [0u8; 512], + [0u8; 36], ) .expect("expected to add output"); @@ -3081,7 +3081,7 @@ impl NetworkStrategy { let change_amount = note_value - withdrawal_amount; // Build bundle: spend note -> output change (value_balance = withdrawal_amount) - let mut builder = Builder::new(BundleType::DEFAULT, anchor); + let mut builder = Builder::::new(BundleType::DEFAULT, anchor); builder .add_spend(fvk, note, merkle_path) .expect("expected to add spend"); @@ -3090,7 +3090,7 @@ impl NetworkStrategy { None, recipient, NoteValue::from_raw(change_amount), - [0u8; 512], + [0u8; 36], ) .expect("expected to add output"); From c83730b7c3745310bd2a96fdfdf915e6a9108919 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 17 Feb 2026 17:42:31 +0700 Subject: [PATCH 18/40] more work --- Cargo.lock | 1 + docs/SHIELDED_CLIENT_INTEGRATION.md | 111 ++++++++++++++--- .../v0/mod.rs | 2 +- .../state_transitions/shielded_common/mod.rs | 18 ++- .../query/shielded/encrypted_notes/v0/mod.rs | 117 ++++++++++-------- .../src/drive/initialization/v3/mod.rs | 2 +- packages/rs-drive/src/fees/op.rs | 2 +- .../grove_commitment_tree_count/mod.rs | 54 ++++++++ .../grove_commitment_tree_count/v0/mod.rs | 30 +++++ .../grove_get_proved_path_query_v1/mod.rs | 48 +++++++ .../grove_get_proved_path_query_v1/v0/mod.rs | 27 ++++ .../grove_insert_empty_tree/v0/mod.rs | 2 +- .../rs-drive/src/util/grove_operations/mod.rs | 6 + .../drive_grove_method_versions/mod.rs | 2 + .../drive_grove_method_versions/v1.rs | 2 + packages/rs-sdk/Cargo.toml | 2 + packages/rs-sdk/src/lib.rs | 2 + 17 files changed, 346 insertions(+), 82 deletions(-) create mode 100644 packages/rs-drive/src/util/grove_operations/grove_commitment_tree_count/mod.rs create mode 100644 packages/rs-drive/src/util/grove_operations/grove_commitment_tree_count/v0/mod.rs create mode 100644 packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_v1/mod.rs create mode 100644 packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_v1/v0/mod.rs diff --git a/Cargo.lock b/Cargo.lock index acffb585a2d..b8c07174dec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1526,6 +1526,7 @@ dependencies = [ "drive-proof-verifier", "envy", "futures", + "grovedb-commitment-tree", "hex", "http", "js-sys", diff --git a/docs/SHIELDED_CLIENT_INTEGRATION.md b/docs/SHIELDED_CLIENT_INTEGRATION.md index 6752c32c706..619f3141c8b 100644 --- a/docs/SHIELDED_CLIENT_INTEGRATION.md +++ b/docs/SHIELDED_CLIENT_INTEGRATION.md @@ -53,17 +53,17 @@ All five types carry Orchard bundle data: serialized actions, a Halo 2 zero-know ## 2. Dependencies -Client applications use the `grovedb-commitment-tree` crate, which re-exports all necessary Orchard types: +The Dash Platform SDK (`dash-sdk`) re-exports all necessary Orchard and commitment tree types behind the `shielded` feature: ```toml [dependencies] -grovedb-commitment-tree = { version = "4", features = ["client"] } +dash-sdk = { version = "3", features = ["shielded"] } ``` -The `client` feature enables `ClientCommitmentTree` for wallet-side note tracking and Merkle witness generation. All Orchard types are re-exported from this crate: +The `shielded` feature enables `ClientCommitmentTree` for wallet-side note tracking and Merkle witness generation, as well as the Orchard builder for constructing shielded bundles. All Orchard types are re-exported from `dash_sdk::grovedb_commitment_tree`: ```rust -use grovedb_commitment_tree::{ +use dash_sdk::grovedb_commitment_tree::{ // Builder Builder, BundleType, // Key management @@ -85,10 +85,17 @@ use grovedb_commitment_tree::{ }; ``` -For the platform sighash, also depend on `dpp`: +For the platform sighash, use the re-exported `dpp`: ```rust -use dpp::shielded::compute_platform_sighash; +use dash_sdk::dpp::shielded::compute_platform_sighash; +``` + +Alternatively, for projects that don't use the full SDK, the crate can be used directly: + +```toml +[dependencies] +grovedb-commitment-tree = { version = "4", features = ["client"] } ``` --- @@ -149,7 +156,32 @@ let ovk: OutgoingViewingKey = fvk.to_ovk(Scope::External); ## 4. Commitment Tree and Note Tracking -### ClientCommitmentTree +### Server-Side Storage: BulkAppendTree + +On the platform, encrypted notes are stored in a **CommitmentTree** element backed by a **BulkAppendTree** — a two-level append-only authenticated data structure: + +``` +CommitmentTree (epoch_size = 2048) + | + +-- Buffer (dense Merkle tree, up to 2048 entries) + | Entries 0..2047 of the current epoch + | + +-- MMR (Merkle Mountain Range of completed epochs) + Epoch 0: entries 0..2047 (immutable blob, CDN-cacheable) + Epoch 1: entries 2048..4095 (immutable blob, CDN-cacheable) + ... +``` + +When the buffer fills (2048 notes), all entries are compacted into an immutable epoch blob and appended to the MMR. This gives: +- **O(1) append** for new notes +- **O(log n) authenticated reads** by global position +- **CDN-cacheable epoch blobs** for bulk syncing (completed epochs never change) + +Each note is stored as `cmx (32 bytes) || encrypted_note (216 bytes)` = 248 bytes, accessed by its global position (0-indexed `u64`). + +Separately, the CommitmentTree maintains a **Sinsemilla frontier** in auxiliary storage, used to compute the Orchard anchor (Merkle root) at the end of each block. + +### Client-Side: ClientCommitmentTree The `ClientCommitmentTree` maintains a local copy of the on-chain Sinsemilla Merkle tree (depth 32). It supports: @@ -163,7 +195,7 @@ use grovedb_commitment_tree::{ClientCommitmentTree, Retention, Position, Anchor, // Create a new client tree (retain up to 1000 checkpoints) let mut tree = ClientCommitmentTree::new(1000); -// Append notes as they appear on-chain +// Append notes as they appear on-chain (in global position order) // Use Retention::Marked for notes belonging to this wallet (need witnesses later) // Use Retention::Ephemeral for notes belonging to other wallets tree.append(cmx_bytes, Retention::Marked)?; // Our note @@ -180,6 +212,8 @@ let merkle_path: MerklePath = tree.witness(position, 0)? .expect("witness should exist for marked leaf"); ``` +The `ClientCommitmentTree` tracks the Sinsemilla tree only — it does not replicate the BulkAppendTree structure. The server stores notes in the BulkAppendTree for efficient retrieval; the client appends cmx values to its Sinsemilla tree for witness generation. + ### Wallet Note State A wallet tracks each note through its lifecycle: @@ -199,7 +233,7 @@ For each detected note, store: | Field | Source | Purpose | |-------|--------|---------| | `Note` | Trial decryption | The note object (value, address, rho, rseed) | -| `Position` | Tree append order | Location in commitment tree (for witness generation) | +| `Position` | Tree append order (= global position) | Location in commitment tree (for witness generation) | | `cmx` | `ExtractedNoteCommitment::from(note.commitment())` | For tree tracking | | `nullifier` | Known from note + spending key | To detect when the note is spent | | `block_height` | Block where cmx appeared | For sync tracking | @@ -585,32 +619,75 @@ Light clients must synchronize with the on-chain shielded pool state. The protoc | Query | Returns | Purpose | |-------|---------|---------| | `GetShieldedPoolState` | Pool parameters, total balance, note count | Initial state check | -| `GetShieldedEncryptedNotes` | Encrypted notes in block range | Note discovery via trial decryption | +| `GetShieldedEncryptedNotes` | Encrypted notes by global position range | Note discovery via trial decryption | | `GetShieldedAnchors` | Historical anchors by block height | Verify spend witnesses | | `GetShieldedNullifiers` | Published nullifiers | Detect spent notes | +### GetShieldedEncryptedNotes + +Notes are indexed by **global position** (a monotonically increasing `u64`). The request takes: + +| Field | Type | Description | +|-------|------|-------------| +| `start_index` | `u64` | First global position to fetch (0-based) | +| `count` | `u32` | Maximum number of notes to return | +| `prove` | `bool` | Whether to return a GroveDB proof (V1) instead of raw data | + +**Non-proved response** (`prove = false`): Returns a list of `EncryptedNote { cmx, encrypted_note }` for each position in the requested range. The response stops early if the position is past the end of the tree. + +**Proved response** (`prove = true`): Returns a GroveDB **V1 proof** (supports BulkAppendTree subqueries). The client verifies using: + +```rust +use grovedb::GroveDb; +use grovedb::VerifyOptions; + +let (root_hash, result_set) = GroveDb::verify_query_with_options( + &proof_bytes, + &path_query, // Same PathQuery structure as the server used + VerifyOptions { + absence_proofs_for_non_existing_searched_keys: false, + verify_proof_succinctness: false, + include_empty_trees_in_result: false, + }, + grove_version, +)?; +``` + +V1 proofs authenticate BulkAppendTree entries by global position range. A single proof covers all requested positions efficiently (epoch blobs + buffer entries). + ### Sync Flow ``` 1. Query pool state to get current note count and latest block height -2. For each unseen block range: - a. Fetch encrypted notes +2. Determine the last synced position (wallet state) +3. Fetch notes in batches by position range: + a. GetShieldedEncryptedNotes(start_index = last_synced + 1, count = batch_size) b. Trial-decrypt each note with IncomingViewingKey c. For decrypted notes: record (Note, Position, cmx) in wallet d. Append ALL cmx values to ClientCommitmentTree (Marked for ours, Ephemeral for others) - e. Checkpoint the tree at each block boundary -3. Query nullifiers to detect which of our notes have been spent -4. Remove spent notes from the spendable set + e. Repeat until fewer than batch_size notes returned (caught up) +4. Checkpoint the ClientCommitmentTree at the current sync point +5. Query nullifiers to detect which of our notes have been spent +6. Remove spent notes from the spendable set ``` +### Epoch-Based Bulk Syncing + +The BulkAppendTree's epoch structure (epoch_size = 2048) enables efficient bulk syncing: + +- **Completed epochs** (positions 0..2047, 2048..4095, ...) are immutable blobs that never change +- These can be served from CDN/cache without re-querying the state tree +- A client syncing from scratch can download completed epoch blobs in parallel +- Only the current (partial) buffer needs fresh queries from platform nodes + ### Sync Strategies | Strategy | Description | Best For | |----------|-------------|----------| -| Sequential | Process every block in order | Simple implementation, full history | +| Sequential | Process every position in order | Simple implementation, full history | | Warp Sync | Scan notes first, compute witnesses later | Fast initial sync (10-100x faster) | | Spend-Before-Sync | Use server-provided witness for immediate spending | Spending before full sync completes | -| Parallel Block Scanning | Scan multiple block ranges concurrently | Multi-core devices | +| Epoch-Parallel | Download completed epoch blobs concurrently | Initial sync on fast connections | --- 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 1f839c4843b..28337d5fdf1 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 @@ -631,7 +631,7 @@ impl Platform { self.drive.grove_insert_if_not_exists( (&shielded_pool_path).into(), &[SHIELDED_NOTES_KEY], - Element::empty_commitment_tree(), + Element::empty_commitment_tree(2048), Some(transaction), None, &platform_version.drive, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs index 1007b15ae6a..222649b1dc4 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs @@ -307,17 +307,13 @@ pub fn validate_minimum_pool_notes( .minimum_pool_notes_for_outgoing; if min_notes > 0 { let pool_path = shielded_credit_pool_path(); - let encrypted_notes_count = drive - .grove_get_raw_optional( - (&pool_path).into(), - &[SHIELDED_NOTES_KEY], - DirectQueryType::StatefulDirectQuery, - transaction, - drive_operations, - &platform_version.drive, - )? - .map(|element| element.count_value_or_default()) - .unwrap_or(0); + let encrypted_notes_count = drive.grove_commitment_tree_count( + (&pool_path).into(), + &[SHIELDED_NOTES_KEY], + transaction, + drive_operations, + &platform_version.drive, + )?; if encrypted_notes_count < min_notes { return Ok(Some(ConsensusValidationResult::new_with_error( StateError::InsufficientPoolNotesError(InsufficientPoolNotesError::new( diff --git a/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs index 1c048fa9960..193292b3ac8 100644 --- a/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs @@ -13,9 +13,11 @@ use dapi_grpc::platform::v0::get_shielded_encrypted_notes_response::{ use dpp::check_validation_result_with_data; use dpp::validation::ValidationResult; use dpp::version::PlatformVersion; -use drive::drive::shielded::paths::shielded_credit_pool_notes_path_vec; -use drive::grovedb::query_result_type::QueryResultType; -use drive::grovedb::{PathQuery, Query, SizedQuery}; +use drive::drive::shielded::paths::{ + shielded_credit_pool_path, shielded_credit_pool_path_vec, SHIELDED_NOTES_KEY, +}; +use drive::grovedb::{PathQuery, Query, QueryItem, SizedQuery, SubqueryBranch}; +use drive::grovedb_path::SubtreePath; use drive::util::grove_operations::GroveDBToUse; impl Platform { @@ -37,30 +39,38 @@ impl Platform { }; let limit = effective.min(u16::MAX as u32) as u16; - let query = if start_index == 0 { - Query::new_range_full() - } else { - let mut q = Query::new(); - q.insert_range_from(start_index.to_be_bytes().to_vec()..); - q - }; + let response = if prove { + // V1 proof: PathQuery with subquery targeting positions in the CommitmentTree + let end_index = start_index + limit as u64 - 1; + let mut inner_query = Query::new(); + inner_query.insert_range_inclusive( + start_index.to_be_bytes().to_vec()..=end_index.to_be_bytes().to_vec(), + ); - let path_query = PathQuery { - path: shielded_credit_pool_notes_path_vec(), - query: SizedQuery { - query, - limit: Some(limit), - offset: None, - }, - }; + let path_query = PathQuery { + path: shielded_credit_pool_path_vec(), + query: SizedQuery { + query: Query { + items: vec![QueryItem::Key(vec![SHIELDED_NOTES_KEY])], + default_subquery_branch: SubqueryBranch { + subquery_path: None, + subquery: Some(inner_query.into()), + }, + left_to_right: true, + conditional_subquery_branches: None, + add_parent_tree_on_subquery: false, + }, + limit: None, + offset: None, + }, + }; - let response = if prove { - let proof = check_validation_result_with_data!(self.drive.grove_get_proved_path_query( - &path_query, - None, - &mut vec![], - &platform_version.drive, - )); + let proof = + check_validation_result_with_data!(self.drive.grove_get_proved_path_query_v1( + &path_query, + &mut vec![], + &platform_version.drive, + )); let (grovedb_used, proof) = self.response_proof_v0(platform_state, proof, GroveDBToUse::Current)?; @@ -72,31 +82,36 @@ impl Platform { metadata: Some(self.response_metadata_v0(platform_state, grovedb_used)), } } else { - let (results, _) = self.drive.grove_get_raw_path_query( - &path_query, - None, - QueryResultType::QueryKeyElementPairResultType, - &mut vec![], - &platform_version.drive, - )?; + // Non-proved: loop over commitment_tree_get_value for each position + let pool_path = shielded_credit_pool_path(); + let pool_subtree: SubtreePath<&[u8]> = (&pool_path).into(); + let notes_key: &[u8] = &[SHIELDED_NOTES_KEY]; + + let mut entries = Vec::with_capacity(limit as usize); + for pos in start_index..(start_index + limit as u64) { + let maybe_value = self + .drive + .grove + .commitment_tree_get_value( + pool_subtree.clone(), + notes_key, + pos, + None, + &platform_version.drive.grove_version, + ) + .unwrap() + .map_err(|e| Error::Drive(drive::error::Error::GroveDB(Box::new(e))))?; - let entries: Vec = results - .to_key_elements() - .into_iter() - .filter_map(|(_key, element)| { - element.into_item_bytes().ok().and_then(|value| { - // Value format: cmx (32 bytes) || encrypted_note (remaining bytes) - if value.len() > 32 { - Some(EncryptedNote { - cmx: value[..32].to_vec(), - encrypted_note: value[32..].to_vec(), - }) - } else { - None - } - }) - }) - .collect(); + match maybe_value { + Some(value) if value.len() > 32 => { + entries.push(EncryptedNote { + cmx: value[..32].to_vec(), + encrypted_note: value[32..].to_vec(), + }); + } + _ => break, // past end of tree + } + } GetShieldedEncryptedNotesResponseV0 { result: Some( @@ -104,7 +119,9 @@ impl Platform { EncryptedNotes { entries }, ), ), - metadata: Some(self.response_metadata_v0(platform_state, CheckpointUsed::Current)), + metadata: Some( + self.response_metadata_v0(platform_state, CheckpointUsed::Current), + ), } }; diff --git a/packages/rs-drive/src/drive/initialization/v3/mod.rs b/packages/rs-drive/src/drive/initialization/v3/mod.rs index 89fe1742269..b2b97b9c371 100644 --- a/packages/rs-drive/src/drive/initialization/v3/mod.rs +++ b/packages/rs-drive/src/drive/initialization/v3/mod.rs @@ -82,7 +82,7 @@ impl Drive { batch.add_insert( shielded_credit_pool_path_vec(), vec![SHIELDED_NOTES_KEY], - Element::empty_commitment_tree(), + Element::empty_commitment_tree(2048), ); // 3. Nullifiers tree (NormalTree) diff --git a/packages/rs-drive/src/fees/op.rs b/packages/rs-drive/src/fees/op.rs index a5c016eacb2..0f70a0397cf 100644 --- a/packages/rs-drive/src/fees/op.rs +++ b/packages/rs-drive/src/fees/op.rs @@ -579,7 +579,7 @@ impl LowLevelDriveOperationTreeTypeConverter for TreeType { TreeType::ProvableCountSumTree => { Element::empty_provable_count_sum_tree_with_flags(element_flags) } - TreeType::CommitmentTree => Element::empty_commitment_tree_with_flags(element_flags), + TreeType::CommitmentTree => Element::empty_commitment_tree_with_flags(2048, element_flags), TreeType::MmrTree => Element::empty_mmr_tree_with_flags(element_flags), TreeType::BulkAppendTree => { Element::empty_bulk_append_tree_with_flags(4, element_flags) diff --git a/packages/rs-drive/src/util/grove_operations/grove_commitment_tree_count/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_commitment_tree_count/mod.rs new file mode 100644 index 00000000000..ff402130db6 --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/grove_commitment_tree_count/mod.rs @@ -0,0 +1,54 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; + +use dpp::version::drive_versions::DriveVersion; + +use grovedb::TransactionArg; +use grovedb_path::SubtreePath; + +impl Drive { + /// Returns the total number of items in a CommitmentTree. + /// The operation's cost is then added to `drive_operations` for later processing. + /// + /// # Parameters + /// * `path`: The path to the CommitmentTree's parent. + /// * `key`: The key of the CommitmentTree element. + /// * `transaction`: The groveDB transaction associated with this operation. + /// * `drive_operations`: A vector to collect the costs of operations for later computation. + /// * `drive_version`: The drive version to select the correct function version to run. + /// + /// # Returns + /// * `Ok(u64)` — the total number of items in the CommitmentTree. + /// * `Err(DriveError::UnknownVersionMismatch)` if the drive version does not match known versions. + pub fn grove_commitment_tree_count>( + &self, + path: SubtreePath<'_, B>, + key: &[u8], + transaction: TransactionArg, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result { + match drive_version + .grove_methods + .basic + .grove_commitment_tree_count + { + 0 => self.grove_commitment_tree_count_v0( + path, + key, + transaction, + drive_operations, + drive_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "grove_commitment_tree_count".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/util/grove_operations/grove_commitment_tree_count/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_commitment_tree_count/v0/mod.rs new file mode 100644 index 00000000000..237cafa239e --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/grove_commitment_tree_count/v0/mod.rs @@ -0,0 +1,30 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::fees::op::LowLevelDriveOperation::CalculatedCostOperation; +use grovedb::TransactionArg; +use grovedb_costs::CostContext; +use grovedb_path::SubtreePath; +use platform_version::version::drive_versions::DriveVersion; + +impl Drive { + /// Returns the total number of items in a CommitmentTree. + /// Pushes the cost to `drive_operations` and returns the count. + pub(super) fn grove_commitment_tree_count_v0>( + &self, + path: SubtreePath<'_, B>, + key: &[u8], + transaction: TransactionArg, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result { + let CostContext { value, cost } = self.grove.commitment_tree_count( + path, + key, + transaction, + &drive_version.grove_version, + ); + drive_operations.push(CalculatedCostOperation(cost)); + value.map_err(Error::from) + } +} diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_v1/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_v1/mod.rs new file mode 100644 index 00000000000..b151f16af4b --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_v1/mod.rs @@ -0,0 +1,48 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; + +use dpp::version::drive_versions::DriveVersion; + +use grovedb::PathQuery; + +impl Drive { + /// Generates a V1 proof for the specified path query in groveDB. + /// V1 proofs support BulkAppendTree/CommitmentTree subqueries. + /// The operation's cost is then added to `drive_operations` for later processing. + /// + /// # Parameters + /// * `path_query`: The groveDB path query to generate a V1 proof for. + /// * `drive_operations`: A vector to collect the costs of operations for later computation. + /// * `drive_version`: The drive version to select the correct function version to run. + /// + /// # Returns + /// * `Ok(Vec)` if the operation was successful, returning the serialized proof bytes. + /// * `Err(DriveError::UnknownVersionMismatch)` if the drive version does not match known versions. + pub fn grove_get_proved_path_query_v1( + &self, + path_query: &PathQuery, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result, Error> { + match drive_version + .grove_methods + .basic + .grove_get_proved_path_query_v1 + { + 0 => self.grove_get_proved_path_query_v1_v0( + path_query, + drive_operations, + drive_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "grove_get_proved_path_query_v1".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_v1/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_v1/v0/mod.rs new file mode 100644 index 00000000000..eb8c8e3f2cf --- /dev/null +++ b/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_v1/v0/mod.rs @@ -0,0 +1,27 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::fees::op::LowLevelDriveOperation::CalculatedCostOperation; +use grovedb::PathQuery; +use grovedb_costs::CostContext; +use platform_version::version::drive_versions::DriveVersion; + +impl Drive { + /// Gets the return value and the cost of a groveDB V1 proved path query. + /// V1 proofs support BulkAppendTree and CommitmentTree subqueries. + /// Pushes the cost to `drive_operations` and returns the proof bytes. + pub(super) fn grove_get_proved_path_query_v1_v0( + &self, + path_query: &PathQuery, + drive_operations: &mut Vec, + drive_version: &DriveVersion, + ) -> Result, Error> { + let CostContext { value, cost } = self.grove.prove_query_v1( + path_query, + None, + &drive_version.grove_version, + ); + drive_operations.push(CalculatedCostOperation(cost)); + value.map_err(Error::from) + } +} diff --git a/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs index 887b11161f6..3c4ee655b0b 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs @@ -28,7 +28,7 @@ impl Drive { TreeType::CountSumTree => Element::empty_count_sum_tree(), TreeType::ProvableCountTree => Element::empty_provable_count_tree(), TreeType::ProvableCountSumTree => Element::empty_provable_count_sum_tree(), - TreeType::CommitmentTree => Element::empty_commitment_tree(), + TreeType::CommitmentTree => Element::empty_commitment_tree(2048), TreeType::MmrTree => Element::empty_mmr_tree(), TreeType::BulkAppendTree => Element::empty_bulk_append_tree(4), TreeType::DenseAppendOnlyFixedSizeTree => Element::empty_dense_tree(8), diff --git a/packages/rs-drive/src/util/grove_operations/mod.rs b/packages/rs-drive/src/util/grove_operations/mod.rs index e0cb4cff5dc..eced6fa04d6 100644 --- a/packages/rs-drive/src/util/grove_operations/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/mod.rs @@ -48,6 +48,12 @@ pub mod grove_get_raw_path_query; /// Proved path query in grove pub mod grove_get_proved_path_query; +/// V1 proved path query in grove (supports BulkAppendTree/CommitmentTree) +pub mod grove_get_proved_path_query_v1; + +/// Get total count from a CommitmentTree +pub mod grove_commitment_tree_count; + /// Proved branch chunk query in grove pub mod grove_get_proved_branch_chunk_query; diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/mod.rs index f10f99fc6d7..4c0712225c8 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/mod.rs @@ -38,6 +38,8 @@ pub struct DriveGroveBasicMethodVersions { pub grove_get_optional_sum_tree_total_value: FeatureVersion, pub grove_get_raw_optional_item: FeatureVersion, pub grove_get_big_sum_tree_total_value: FeatureVersion, + pub grove_get_proved_path_query_v1: FeatureVersion, + pub grove_commitment_tree_count: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/v1.rs index 162d8bcfa0b..2df9f00f055 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_grove_method_versions/v1.rs @@ -31,6 +31,8 @@ pub const DRIVE_GROVE_METHOD_VERSIONS_V1: DriveGroveMethodVersions = DriveGroveM grove_get_optional_sum_tree_total_value: 0, grove_get_raw_optional_item: 0, grove_get_big_sum_tree_total_value: 0, + grove_get_proved_path_query_v1: 0, + grove_commitment_tree_count: 0, }, batch: DriveGroveBatchMethodVersions { batch_insert_empty_tree: 0, diff --git a/packages/rs-sdk/Cargo.toml b/packages/rs-sdk/Cargo.toml index 41ffae82784..7a95a87dbf6 100644 --- a/packages/rs-sdk/Cargo.toml +++ b/packages/rs-sdk/Cargo.toml @@ -18,6 +18,7 @@ drive = { path = "../rs-drive", default-features = false, features = [ platform-wallet = { path = "../rs-platform-wallet", optional = true } drive-proof-verifier = { path = "../rs-drive-proof-verifier", default-features = false } +grovedb-commitment-tree = { path = "../../../grovedb/grovedb-commitment-tree", features = ["client"], optional = true } dash-context-provider = { path = "../rs-context-provider", default-features = false } dash-platform-macros = { path = "../rs-dash-platform-macros" } http = { version = "1.1" } @@ -150,6 +151,7 @@ core_key_wallet_bip38 = ["dpp/core_key_wallet_bip_38"] core_spv = ["dpp/core_spv"] core_rpc_client = ["dpp/core_rpc_client"] platform_wallet_manager = ["platform-wallet/manager"] +shielded = ["dep:grovedb-commitment-tree", "dpp/shielded-bundle-building"] [[example]] diff --git a/packages/rs-sdk/src/lib.rs b/packages/rs-sdk/src/lib.rs index 582d44c291d..ee5fe952180 100644 --- a/packages/rs-sdk/src/lib.rs +++ b/packages/rs-sdk/src/lib.rs @@ -79,6 +79,8 @@ pub use dpp::dash_spv; #[cfg(feature = "core_rpc_client")] pub use dpp::dashcore_rpc; pub use drive; +#[cfg(feature = "shielded")] +pub use grovedb_commitment_tree; pub use drive_proof_verifier::types as query_types; pub use drive_proof_verifier::Error as ProofVerifierError; #[cfg(feature = "platform-wallet")] From ecd5804f400c6359c9ed4719f2ea82fe7eb827ce Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 18 Feb 2026 01:10:37 +0700 Subject: [PATCH 19/40] more work --- ...-darwin-arm64-npm-1.11.1-c78d4bd2cb-10.zip | Bin 0 -> 837916 bytes ...linux-x64-gnu-npm-1.11.1-93a00570de-10.zip | Bin 965852 -> 0 bytes docs/SHIELDED_CLIENT_INTEGRATION.md | 115 ++++++++++++++---- .../clients/core/v0/nodejs/core_protoc.js | 76 ++++++------ .../dapi-grpc/clients/core/v0/web/core_pb.js | 76 ++++++------ .../clients/drive/v0/nodejs/drive_pbjs.js | 37 +++++- .../clients/drive/v0/nodejs/drive_protoc.js | 8 +- .../clients/drive/v0/web/drive_pb.js | 8 +- .../platform/v0/nodejs/platform_pbjs.js | 37 +++++- .../platform/v0/nodejs/platform_protoc.js | 80 ++++++++++-- .../platform/v0/objective-c/Platform.pbobjc.h | 10 +- .../platform/v0/objective-c/Platform.pbobjc.m | 15 ++- .../platform/v0/python/platform_pb2.py | 91 +++++++------- .../clients/platform/v0/web/platform_pb.d.ts | 6 + .../clients/platform/v0/web/platform_pb.js | 80 ++++++++++-- .../protos/platform/v0/platform.proto | 5 +- .../shield/transform_into_action/v0/mod.rs | 6 +- .../transform_into_action/v0/mod.rs | 8 +- .../query/shielded/encrypted_notes/v0/mod.rs | 10 +- packages/rs-drive/src/fees/op.rs | 4 +- .../shielded/mod.rs | 13 +- .../shield_from_asset_lock_transition.rs | 7 +- .../shielded/shield_transition.rs | 7 +- .../shielded/shielded_transfer_transition.rs | 7 +- .../shielded_withdrawal_transition.rs | 7 +- .../shielded/unshield_transition.rs | 7 +- .../shielded/shield/transformer.rs | 2 + .../shielded/shield/v0/mod.rs | 2 + .../shielded/shield/v0/transformer.rs | 2 + .../shield_from_asset_lock/transformer.rs | 2 + .../shielded/shield_from_asset_lock/v0/mod.rs | 2 + .../shield_from_asset_lock/v0/transformer.rs | 2 + .../src/util/batch/drive_op_batch/shielded.rs | 13 +- .../grove_commitment_tree_count/v0/mod.rs | 9 +- .../grove_get_proved_path_query_v1/mod.rs | 8 +- .../grove_get_proved_path_query_v1/v0/mod.rs | 8 +- packages/rs-sdk/src/lib.rs | 4 +- 37 files changed, 553 insertions(+), 221 deletions(-) create mode 100644 .yarn/cache/@unrs-resolver-binding-darwin-arm64-npm-1.11.1-c78d4bd2cb-10.zip delete mode 100644 .yarn/cache/@unrs-resolver-binding-linux-x64-gnu-npm-1.11.1-93a00570de-10.zip diff --git a/.yarn/cache/@unrs-resolver-binding-darwin-arm64-npm-1.11.1-c78d4bd2cb-10.zip b/.yarn/cache/@unrs-resolver-binding-darwin-arm64-npm-1.11.1-c78d4bd2cb-10.zip new file mode 100644 index 0000000000000000000000000000000000000000..c25b83d2ad63cf7b7ffd05372e4625cbe1c84a6a GIT binary patch literal 837916 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

KtO)k71ok!lVwS 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%0A^Yf}DYlwqB&fsGv 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

3yZ?Jy3K58T26u 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

(s(mmKPg4)v%*J>pPbaH!8a)aM-PVTXFip+0R$ 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 a5YfT+R+XoE=h~ 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 S{R1EB?@9F+dV3h*uk~M7>iiM_ literal 0 HcmV?d00001 diff --git a/.yarn/cache/@unrs-resolver-binding-linux-x64-gnu-npm-1.11.1-93a00570de-10.zip b/.yarn/cache/@unrs-resolver-binding-linux-x64-gnu-npm-1.11.1-93a00570de-10.zip deleted file mode 100644 index a5061a1a7ebd458f9e3e57f6a99e19cac9da85cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 965852 zcmbSzd0bLy`+ke&mYP{wqk?PHlv3G@ng}kLmL)n?wkgv%Wvgo?BtmZ4DyU6X8nifL zla(!&nJB3hkR_#+=7#1mQWNN?&|&>ORx|I+yz~D4`1bisgUC5N=UMLiy07cH3k#X7 zH)F#1AK&Y*4L`s5`j;vAe_Z^}TS>cu19A&iVz>-q#s^8aqN3^opUgdLIJyRDG zo!mHeyT_W*Z(D^w`xpwQ2MC6D`W;9x-QXJe@W8cS66cWyqAsms`pm_$ee;KINqn11 zUmLZ5v`K3BEFHc&S6N$nxZCN#sfQ;9@3{rqcF%HIc%po6M3e<@_I2v+zK02W(Hr-q zC+@iPDe+_e!r?Nj-N~iU6urgOiBl(CbtmzTEI+=oD{cLi@Hy4Oq2*!K$6; zVbj(p84&`b5FcISn;CD`u$Q*4-YnQ+;=1O8@6k`D(9b&4FT3N9#eq~$Y&U{MNdf

odXA`PZIbTj>5` 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μ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%0ABPGV2|=E<7@d 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 I>UEB1`(N9bMi4ft&j#`4 zZF+Mfxn}nHMZEa{Z-D3M=`&M2uihppx0KTc^iNg5TFtiaY>4qRp9#v^_%&H(wGH3H795#v@4dDKK$VB<}CbC2PRV*@)BoNH$ z6iWDX2UUv9X;kq3*J&oOxGh1VOgqDG+H46Dm zQbuwhikwaqnbR{wjsyAFe;-N6V|o(K=)8fd*)M1@rzidy)03%?)k|b&3(@K|BU39V zk?(ql#-tQW6krB#dL)*~K}@foMNRSh^;I;de^=Rxh2eS;pX_~_+*~q678CfGI)Pg_ zB_XZSXtFqUBam+)%H7H{2nLWsf-%h^O*9Y)VK|v^L^E@*tl*hDAftU?=DrKg+#T8o^GI1(ZGAV8eTe_zO)QK(uy;_=zKY>io4l4Z}YVPTjOReslZh!Kr&%yt(Uh zIdxscbJ6E=>fU@wYX=W_vm6p?X7oI@R$mHh+MHy9GIC^8Pw&PK^Q-BmT7MQz^tWDUp!onUmvnu9i)sP7h0Up(sjR9uJL)M$--B}m_EVt(RrDV7;SOHCC^ERg?7&6!l&es<;1(^%Z8M@n;OT z+f`E$_Y{kIUj&0wHX<=fBrH1Sx%B%f1aA3hteZ-fZOEAh{TATo8<>h&Q#nT>ABn;3dMwci4>13^Tgd3WTignE`vc zp&vmGBpvT5K2<#aU$!RY>jjM|DV{f&gZkZ>@5Hf0nk<#P_5((>M5BZ|N?31H!{&&B z3t(fJ>zS_S!soIVB$qpP!^@JPW^&oqcO>Ycgi1^Y&c{qM*}NG3-_A}b$5oItJA^Av&G&Q~*}suYr3sJQ7REOS56u}0th z81LI87n2Eb_fPn2L1x7lVDS%>Qfd&cD#Ymp_j+$L(HQ$F6|eC29oa=-1z;S@u}h0B z{U{Bsm4;981ri5+BHU;&(aC~}gr#+!G`-G5y~)DjnhrgwZwp#7(xHeX1E@~zkw$@E zuec&DLg4_ynuvO70waZxB5K?8q_|8%ZRh2sB+5UZrI@`wwPM>st^n*)2&RA%a@O^{4r zRysku=JOfSrAz?bSSUD-nWl{T=@3u;NrNT{~4P)J^mE6 z_n^OZQTkYlSSvWgLr-078lOGR(|Br~oW`hUFS3JhfQABf2NAqs5L>!SkVsY}X?KuA zoQ4oSFd|L}HhQ)|md676t?o*KJ!H}bBF+-MKNjqPy}H>$i;-3GAdaQJxN7TIgRV|OG^~Z*@hHIZ} zdbi0r$`tkLT1inKK6ME)35)Erda42m?LBv5b;n*Cq@+pQnf_KjedUrn12G1q%j(JE zxRgT#cSr{r4FqGE`IeD|5b}6eLxgIQOQH9Vqa4HuS& zSi|c72-biJ^%HAAU4CK>w7xTg{NdZz!ubPkGEx+p$^pO(J+Gg3uapHIX5}|a63H5~ z%xK9W(uL?i7OtI%Uy#xQQ(6~f6ED0KJY|Ynsu#v-+*FVHTZFg+2zt!pawZQpoXMGo zc_zQElr!mjvQfEVI?D}$#jA3IkS>FALr{esCO1@Sc)d9!UXt9PW=Ic7mWo@tAbnE6 z9G}&eG}xa=KO`YwhB5tnUR7lU`zr-d~Qnp$F?$#&nA>%Ipb6;sT)5Df}# z=xI-&=bq>ElZ5GazC#{y(ca3%al-Dh{B%SaI}j8Qd^`v9@IA-oZM;7ffD2Esy4(|z z0dfF0*A+vPdfLcV#-Tp}?b)d+eQCGyGoZi~+(n03;;s%f6E;1et`=gqoDBMyjDvU% z6oS8|?eO2oSw6kwER1OlWx&^uk_s{@iEp=P!Qw`wcM^=ZdBvB;lQ|OnQ@|e(HpZ|a zTc@{^hx|Bp3sPaY8tQ?$4UFJANVI|OyODMZ+AxK&4~q1djY%)llqQL=C%)|j%6myU z5uF8gWG@jQ7Yy3EB=N52dmQ=0!&mWz)owYrGk9(Xwsi%AS$?q zv#1fA`7}&p$vx^6W@@K!nq~?MQyC`$^PWl>CSPg>b=H?*;rpklW1XoT>*<=YzDLZ` zEkq-{+fcY2f5xTed-N$eK^)VD4X4>H9*1WRfy^NpSY0hhPNlXNmkMgLZHU$jr-Njg zCUI|0j+UT3)bdcOpuLqBF+zSLi~=Sw1q3{Fzti8yno_|{Y5K9ur&uukR-S%hZkYaQ za{4D|rvIKLn(0qqKPS!Hw++rc-ZwV!j17i~XZG2|#Haq*iBG-6i68e5?Zl`4!337Q z)A+>yQNHyb{I!Yi@nUG=NyLy2bXJDv9Y+SS7RK%6X@8^1X(uU;4N(LDBw{FeViDT3 zYKa8BbT>1tSS5BZuYPJvd_66{`hRi+wn|rnRuTkomd0OW{3}E{*Tc=u0RE99h8|-M zgIPw#4yD}uNYEFAFm~{h0>TPpTuU@>=!I%HJcm(U>#bx2L~%7gW~ zGjoX%-Kp0J&bZ+No z&jk?^G+p;34+>>yN2Wo^P+WY{+> zkt+l+B^f8-rII6%OUrRS@LM<}g*qJaONu)#gkbuo$~^jJQ)S-w++Qv8l_#4jGwx+g znf1-WKMw+&lD#LWv#TRQg!UFe(!>oz+K#|3AmG7@?5KWft6cXoh642O1t4`a+_r!g zPbTWZ6`SnSBQNUC+(gCw^p{d`@&CT!vrSjrk}GbJ>n`1$?*Hb0T5I=9>Mrxlzt&v} zTZpp^E*=CH&JGCFu@naq+rum)*FM z_y@uh{EYuQheGf_Sjfd@WX>}ZI1t(WH7rTo7d0qJI5Gd3k{;|y#U#jLEL_ag?o`H4 zmskc)orH?j3FqAt(htYs#^SzWhK9Uc$FPYS0p+|6l{mR86kM z@BfutAO59WU;kmQ`i>n0_a-<8%!!qs!NQ(K8LXRkW~`qoFqawjcozwxgbbI)m(?td z`f)^nqyuf;EOwR@@k87s{+6)JNk6J6laT4?*NjdcOr0VXy_E$p5Sj0X)=@MA`|~P ztU_)!lNOh4S$|?N=^+YBWMRA4O@C)RGu;0_!x8n&qq%Ic5#UgU=`000#3n?Xf`Ai? z^EQ+LZ3&E}1!r?YZ|{#MbW=CXv}lX`!P_F0qZx2X+XdWEk%9H>K)t-qq6?xkl#eru zgu}p;Rjek+{j*8qF#rw7;$V0gCrVmC%22w@1v-WQ7_HD~@jybri0gV3n2ojfKkKSPsjI`VLTi%|#d-eOQ(C5%q#~nYgY;vclBno6L8to7+`KJ)6 zP%2!q)o3}~XiKQk0(d4{Mp=?=X6;uajh62lY4wlKQ>(Q^w(pS!L`D>nxv+~~QV4_q z`4l2EHGa=YVaa5MtypJhjZ9g`fZH^aE;AWjLk2qfh16t0-+!!@x1Q!j7K-RYL4|7> zhi?XQQ;*vaoEM5PEA19S7Ig-;mLYigKy!GgBx^7VI|=M5$BI%%rtNUl9%oW) zce_$fIjWAp(RTFYOKY)z@+FoDf1Q|1EVFjPrI)$$!AmQ%yyUNpY|9rft@JM*3M+lM zCh!Lb#2~&EA2c(cU=RhmnCtB%V!b|{s!hm~X9U{hEAV+pb#`e-Q zhdaZm)H!SS7GGsD+rYJ}EF69Z8kaiKmqS$^O^c*_gT=pvzA`Ski53m~*Jp5B9oiUH zjgRg02QIDmHA^pjzCM2V(#q^SOjRml<-fCO zLKlz_`#C&hmdNv=uxjcGN3(GMT*0BmN-gRlcPYI$(j9Q%v$Eebt2~^|Ov99R6CFDE z$2{hxq7aV>$B;!~MFBX9db;{z*w5SB>3TZ%;K~;J`SpZ9N@8-a>nXfs2|^TXaGLDD zVT^2nT>@mVH&h<$oe+cl04ey@JK-)qHU$#DS;TcV35a--!@_j>$R7dI+pdd5?cn~( z`ph}!BT9P`kX&xBTgsZDGKd(cPw`fHX@rdZ7Is-xh&$_5`YNxv-$MJUNT~V=5Y@lt zVl_%)Ky5EZlc4{7>2=xeYn-@Vb@sY}>IsN?U|4K`Q>)RgB)!3Xn_~8F{{#HQlQPH+ zKpeXMI)`p-y6%bQTVoIt%EZ;JF|rhD`$BZ;nlhv4lsbm{NtBR*0S&NSUI$Y)vwv;9 zqk{-(HGdLw=EQBm*Q+{9td2301Gs2T`{+mVq!4)t@PGGBG(q(E;%!kaI4B&SRyyht53*O;I%mp%mX^IQmzA zvnpZHsj2V7-yqjgg3i5#sA%&o|YpPoBEeUR|t|J7$Pd2BJp| zGF`kM>z4jc`tj7Hi?pDrOmhl?olgz!cKByFJfVjg@sG=B{u5NCm&Jh%rCuskjhS*O zbR4$FG@z%sPllC&qY5s-jK;>Ps;P#Yo2o4&N^<~cY!EcC&;(6~;18}B%)%C?#e*C~ z*~|hndHd)$I#c%0trYiJBH}nI8ra1jwB`z<5qhy`2Df82i6hhq73< z&?0<)Y+UfVWsAJr$jR8vzJ^ELv^e%dVdudkfy95zCIFX*b+(1~!FZ~gDyzq>*-{+d zgfQ{x@~{SDNmKt|XISk#;K`R#`_-sD7q!cpL)b{7QkE1}%oI@qI`=nEYeoWCr!lmW zlA2#thVq}qlvOn3xcZ00Hq>1l(QT))RTW6*0-6zT&1o6P9X4BSzlb9o8TWN;7 z`{TVzA3s+bg(I2&u!A_wHm4^KD9LL}EIDr1TmxR%d%4~}SL(GZvF}sps&9EPH6R_< zAgCS$w*kuUMTSu>As;Hoz5k36eym20#m5N12*{^m`AfjHllMq~5gF*0oY*4$Jvkqm zig6Ihske!b6jEaB{kHPn2qbKksJy+xftjr#_zSX0!3M>cA)Ufbd??+$Bm2MHfsuf>*7ND@NC;P|@}gFZbwv2Ra` z6G1%p2WRfQJYLw2KG*n8)bMFnQ)h?DH?>3pi zJ4?+Fyr}3vS=iPC9uH2s=k`2Q;4RN32eyw%N9cWe7=F*K7RC-gcq4(A%Vq{YO$wa_ zgzQS=Fh4K@?vNLX^movC2#2)si`9O6`kecOEErqf`y`fvC+e=JL0+B5QaTg-1`34? zsh*2CcEshvZ?7~cBC3a~o|AcoPm*F7l$?lC=KzysQ8P6}LLV}vRK6Zf03VN!cCL1nrkkw=pu_*W%l_2g1HR%Z9F>if;>w!%9p?iLZ(;-z^Hu zb&PW@6yNT>JM7!bT-zk^t!4PPO#YT9zQs)p`&P`~x{Ggjd&0gg;rcB1k-e#?!Dq(0 zR5`;H)vxjRkr*OvbDNfjooKq*U@c^V0b~;h`~4{F_CvVpr0dpdTC2xlpPFm$ylm2 zT+sUQsHoRX)1w2OniIni;m=k)-bnbfn*L@od=JGx`^V!P|7^4rWZQGz{ zz>^!fo3%aXaM|G!tLtWfTCO-0u%Gu?TAvn@6TF{Y5Y<`2s+01-j}E1u6bVuyToNz>BEz@0i~6O+kgW@X zb)|+X*9umms|pm;0T!ybr+Hj;6A~4|Byd;%F;<0agEl}yR}nl`U6^Rp^tj?4$xIb` ze?0%k<2v+#KR>RS^~cr9<66>absFp~21GZd+-eRV+Kl;44Q-|dSrsu6Ow4e1b2PCp zF-X@g?4Oqxf<= z6~|!v;T`Df33i~P=)n9Z(1Ccr3vX_qd2Q`GDhm9G3XJvb7f&hFg4y*-JH9wrTIY|s zw4123mZNAZWjZ@L7&pNW6U$sJd$5Lj(8{++6#Fq%av2Kt^!V+OW;#DSbbHLCW+eG1 z;^!Om)8a3{&yOfyOaCzZJcyJK0+k!G|4?h)f zg&#`E9%t!i2Y)mC{15$XL#ZiUpwlmR@F2oakI@|nk=3Vn z)20I6r2eyEo!O1Sq{h7G)$mdfThKH9_*H>t?JY9RUH&FYQ2nSKr(uP~mKJEEU zk7EaU2x|}000mbUiZ6;ChUJBI26)G)k9=lbp6xc<5d7YQq(CB$noIA1hbOL8W`r4= z$b+_erU-Nz|3E#IY;D^gXX}EwRc|mh&+Ww7T2S-R;8!b1`0r8VrBUv4VLv@}8o^Ip zx9w;C(AUd7=$E%i@g z`(b{_KRUfLQ=>glJLMZk$DRgnujIGK$`RlF+PpAM>F_ioQi*d*kr$*gKaV&fz9r+E zeA#L59YSqG!QrpY3ubR7vY%KK%ATWU_bm=(e@7u}wH3cpk#04VvY)d3(AE?QGVXQWLy2w6Plf6vM zE_NEq-%6AJ)3E$??gsgLXsQ>j-|7x!pBNaTK1lY3>ZW_zcQkDtJgSnqnWbPn6~bqjgd&pybze)G+|s&81vtGWyRi1HzI^QIron|_73cuw^_ z&f5)@xZkNX6D20Tvw+J8__&N1;%%l;MUi0ici%R7nGf`^&=P6Pl>7W+G$*kJmS zaSUeHP^q-0=hGy;<;{9i~6;9ZYFCd+*n*#XtaRk z1(^7nOp8H1l4V-?2GjwQgG{oN1F~^u-bn7yoLOLf(HpWXk$yHpi_*zr7v)&qkLVpy z3ghNh#~cCutOWKvQcO7E8I`Jq05e8RY*ULoNcw@qD#)4up;}r=D-yBDdMF>o(uf8+ ztr*Dxkg;juVCZh+&~N4q2$(EYRV^K9+Z|Qdiqeibs@7U5YO#JTMMtixigTnL=Zn#* z%0x#R&alW`wZTf!ysOCux%@()6y_5Hjivf(+PE;-Fy`^Kx={@;>b}Fsw^E)ydH$0S^)3>5wT#555(i;7T zf;Ye+k=u8ptzj!S85*?Gs%@n~l4|4pL3 z^+u|>fkdEACbi|4$<}xtvWTH7_W#=8(o*DyM?OXeylX7Gsod<&sw=NElqTUuqqIYL zoxbcU+@KrjfOk3FA|X;0nd`N{Iud01PaC)2;;(FS9%n>y>;4njRO?d1Tc_>t?!Msz za9yT2QwDdG^B=Gzed9bcackxoh5h5gAeQrlN2^0W0vxUum%W*}^M5Yw1;KwzZpwk& z4A{UNcbfWrA>wqT?eJz~1p@s%v3!;0*tyTqf?`BvrRQcGDQS+d!2Uvl(6%_zvMe+L zZ=9nhB1sysMaE^aH*2o)TW-oBgq(DgAEAJ(TxlROUN3+;?$qQff8%Dr3);uYOUEx%QpVNoZQYweC5v&9SoFHzJwozC*6502KJsG%1pwm+WiBk#I(%~5KmNE;A z+$0y3SG94J@2^8b-@m&C0zn>R5eeg%2bo8$T0+|7h1wM9B1Ib06BXrlP^56Wy=z9s zy{4>fK-@+Fl_s+Lt^LZ;vC5azWF5v)t7u2_C23Q%7AZ_BCoCB0Gw^o=MDGsqG-C@` zb7_iwk$tPdezSeEp{zaqj-uaDWpQ@5VJk^H_Fjg~E@e~cR<=Pw-gd#fl;$y+W)Y?N zmC~?r^6o&V2QhRk`QZ0t{w;>|F8a;Npg^bL@^>nJ-ztAw@cS0}trvN3l<&=We~m1M zez%qHi}AY^rypAsf!`7IJ7O%V4s;@UP$<5niwYgih$26X;H`f7T(dCQ&YmQ#)(|Nk zdL5jb+%_Zk1fi(lu14q4l)6&0#v0J;@5O+Xh+_erV}3OnUSu8_==8M<^~>L5v*oR9 z#s=(f3{G=`Y7l{Z90kFzFqj26k0X*$laGZ`+R9cl}WrFHnl|*=8N?nbA-Ba3U=LEZM|)f0(y`l~QcpPGSI=RDr+V+#(QwPF%2D z;xM&Br{}xT7zl_XxR}jek}JdA5CX&z1Kq8p+$`?^6Gp0cfT(UCI|YC*U&x^u3rV*@ zgGW!xowMbEfb2fJHC}4OIwxR8B=DwCi^7g$D%mewo2yKL9D4`ua_bsXf@%tWkP8;J z`#*RmYYYBPTkr?>|H*8#+$6l<=;R5+zIjg#i7u+hs)slsZ z9tM?Fg{CRGLerjYwL4(0X_3LzqJ_dBheNRy!f*vftX9r%9v>%=!)gX=G@IqKt-8`H zhOou>SUO_{20(O!v0f!)r?qvXg^gQ3%p`0|GcJ@S+6l?Ke8V}rVh|1r{fz!!=;m1= z@eTm3IEg@F?kcXRp)A+QAVCC5hUa8Kb|N4y@NXau`weNE5F%6>)eb`a{WAlJ6Yda( zwg1~vpSWF?s?v>H20(Y@)uF_38_EVPIrZR^fFQHy17sVN4ul6sc1~WE?qykx=d?p3O!Kz~*>} zCc(paa@V=Y{@v3u|6#MlobrC$jF6vO!H2oGX}KY;e4pN#0(bz5-&b`M!dJgz&Z~2b z_JzIU>y~^$SIye-!mG9h>^mX)#3~w{K2gv`KfvS?5vQ)iz zudGe?YW}DOy}EH`uvZkw{{Ky{#&!EY_iAc>lf8OHk@;3cFrHukyiZ zEIL!gIX<-tlX38o8UQ5^va@v!0lYw@1 z%0g2?B$as^eXE`NmG#0zX{pDM)qpBhjkPHZTbyP zLZf9)OR&jU_=Ipo;?p+a7@4`tsb0#*3(p2z~qDZKLo`*c_ zpUbJS?vCLk!|A#}CXdWqILT;E+vI~TAt1h9O~64dJ_z(%n1ChFV&PCQ2)^^pF`u-V zrey0*nr25MM-&IR&N6ZY%qm}`W8x;5gVn)*tlvgQ=K+}B0p|LC0NR^y7a_#q?ClI% z2*O@0lfaMGvC2}tcRoSK;Pp7aBAf(STzxf4BS*v#H}e12HfLs{PWM1OIbnrIJ}TtN!V;`Bt=Z=PA$-Ny zl`nG1Q4131ufie|#OG3~ytkhX1ajSdX)$JL0H*}w?75FXL@G;rxb$8`j|w>9?*{l( zO#5k?_U)`A6$>2N4-2kE;Z<}#khltq#&4$IBG@GSdU~@BwoKZXyScaopmFrRbb;mr z!1H<7x8N95<xJI<(LV_X{)wKv}SAND+k^#Z6{EX4`B>lm?tAWA7NkQ*2 zWmWo}CUextdw|CkmxUcN>K6VPDeieOrd8fPCIMOrg;!Aw^tIc>@e?i}rcXB3Zif?6 zzH_G+p0ak+a?sYV;^fJe=DvXx^i^UZ&Nh?FRf-5OgRMIb)BS0H&F5C#NaDJL27HLI zy8N-~Q)qZJ^oFs7+3B4_L!;>51Kt*m>E4)Di3kKwVb(V}BAYv|rtM;LIDyWfV+(Of zc*1qWj(a47h!OmP99Hi(Qk${!ZqV+$l_1?at+e}^Szo@1NjCFjmT5|CH1ER&{BNGz zfR7cTv$r!acrXARX6AQn#z%7X>zy6Xvv(WLM@O7w4qOfGUqz*9{+lRV?8_TyH3~4# zfQXEML7-+bBDVh}#x2ZM){|@jI2=p4-zOM+@0yWwA3@NjIs^_aB!ek-0oiTzMS%UKRSI}j z?aehI`Op++&FOu;ZpII^3VBx0ai4!1uxLUyy=%>d@I}88rS>~UNouzjD)<~VhntO^ zeuUBgm1l6kwB~rn&4tPci(}#z@c)g~|C>^z0~IueMxxAkVt1b5agruGrPAREix?hy z;O}1W_ez8UzhJ~xxPjd#f-345g0Ui5k#LB*$IMy_2^?5T# z?e`7~%J}h_;!Y%9*xG1h_$J zXNKf~umfA1#3&psxXcQEpuZF*^i)n6P>a_j)p64R2w&=;*s6dAet-f2z1c0Y^d^Vr zg{1c&b8pCs2o%;tLZ}4}U8;!A>#gb%2oM~XY555{+U9>0p~DRT*1cmFv5Kf|Koy z6))+dcN|_K9d2Bs1)@!l{%WD%MsPV+P$^@cRwU8ACviU@ zikp^ib9~ZDO8uD&mnChaG|6I=P05SpsH>Q(HuocBUyb0YwqB2v(x;_%+NWuZRy;CK zMOOFp)4NQcR1%nKJ~^tE7kKFs@|c0|ybJ1dgz$h-pl*xH0j1{Ts|%L|SRFP;$6CsJGEY46bp@f_BL$mriIT(i4e~&&wEs>eG$wuZB;*; z>AYxfcEDDCKu^`=#qb65qxYM2qys%g=6QHMgBy6tJMPN}ZiR#0cdsljwCc(Wp;@YV zgvJ|2>pJ_wPt&o!wLze-B0iwIHrs+DS57y6ZHkZ)XUs7zg3nzRtjU6m=4 zF{g1M0D3U5OTnoO9pj7bTcOVF=f&S+E~TiByqwLpg>&0tv;foorX^BD<#X5<6-;fK zl7aJzE!~mM@oHS|893-+Qw^nR5>4U7okOL=K$!z019f8w3d@Z4>MgunQGg*`?>LFIe}B zzz;5^*hsMmXK?%~k{|F;EFS=co=o<;$rMXFc^Fvi(xieI!O!wy1V7`Yd!ULB1xQi zq%zMcACIAAj16oTTuK2$#koAMCRIiVmPAdXiR7jxi>BKIWM~R+X(=!t27AfpHIheV z6$}3-D%(hO0XhdCGBO{+J8PtB6j4X7^@2T-P4bHQ!HopH+2eif-3TytQ$_zMkuzDY z1Rfh;5ivMsd7(wOA;(JS!p>w^VlvnF{!&WY!j&NwhiFfx`LhiTN-4diektVOCJXYu)Mzp3nqnN~ zE6EiG+O&-kqQktL-7C|%Klco!_+NslI-w$RLfV5qr9;a|9ZeY3TNE*dj<~2V0M*JH z;I6Y!g0h{wJY|!VgSm>=8(&HVODfa0sB|4A%r|hn>0_{^sVkZ=lE#$ifcS%;4By`) zbs?S_DgbzjbXU;`AANyqSH&7;nCcDzf8Qa3V-qX%{%$3{CpnfZfeA`Hpw)HSLTbus z&?4wYc0v+0iv0N(%Q&H~q#1U1>0FK!YE{F<(L=IcU_+9p9X3{1MpBZgVz7u#ickaY zF4j!!MP*kgN2-n(scE$S;6Ip3qK0YymArNqGcDut(oCG{Wh3!%J*{Wn_dsj(8PtdB zh(06%rqWA@4j5A+H22#{>5(BKShR2kv))sVokytNV@wK(C(6t^@A{u;WM1I8VA=49 z9S#F%MjlhFSZ+=nf;^%LdBeQVeHEe07Za$VOPp`Kw@eR_03dvm90qRH+exnaG+~hhMS>cz0;0`M=mBwQv?Mtui=<)4st~bOo#3nH`G-vv{jQ?X$;U*#Ac}O8i2wqa-i>$`qBN?7 zCl<9n%M(mG&c$*zDtIYKrTjZPBSfUwj0G&OvBojVWk*>xEYgk3uAM%zd=5bzF7 zpg|IA!y9u2>7Ujg%Y{t|LVT#}uRm$zF1AwT14${W1a|UO|47Zmdh*Y}EIR3_Se@fj4hYSIcLjBSe_&DBOWgisj-3c=~R+ z{3$u}1fmypQ_AC)>U@!6@J9%=yReu5%R;M^n2V#=3*1w2(h;(Ck4~@AoSOBh-!|u8f)Z5y?nODPWL7Lb2gi_fBhYzrw}mwoD$q9i?LH=EWqr z6#Tnx5#8dq6k_vv=IV=i?7$TGoa0GY7-9%Z#pNuq2qhI=eZb(P<2T7C}OXg2N|O5^CF-1JB$C4-&Q#DK*S`GAq; z>Y(?^)wr{Gp1MWT!bg7Tx(4FZoGge)If}Jj5~&I5-?iVZ0 zid|dx zON^4JY4B8{e%YuY7du&7*wgryGi?X1SxVu~GfJ=hybH5Ls=$NZtt&~N^|gO5YJ+++ z8`HD2s$!$5qCzc^+2#fB4#+V+o228HC37aiCz_{5(O?T6_=4Q|ejxJVxuEk>G?Cfg zp+oWBRjLXVfy6_^#grN}%3E9-lE>|ItK-{oK?Gp6(&xd{fJ(W|ajBr7jra@AF(wc+ z`_x)^m}Bs^MQU4d8Rp0+ph*xU`M66`(BWklmvsQ*6Aw}snKJXB4rO(22T~ABTBE!iQdkrPx<391x``c9U z%*P!(|IE)Eno-XjUDqf_$1;zWtYCgjNZ8|-82EJl3m(9K?NxO|4m>N0x=E~^K};f3 zG6{!45){1%B)$zrpi({OY=o&IUY`1?!QNM<3i(GAQA6%-HVm|PM{AXIH-hh^JBj_|pBAzi?h%;vS(x~jk3EH&$=&5S37q6>V_oUK$ZSGr`PYNM{_){e|Jh)`r`@AaRX`L>ddB94TD-EegrXDjk7bAr}UW>YzG3WAwq)(~7A(r8fsh z0M5;EY&Itjyp1{Oy$Qer|PSmjKVj@OoD#7kKS?Q zSa`uB*c3o85v^|+bXmE{u*2<1`|}uBGYv9>iksnTAH!VdUr4>lWZcBxOyxbVkSAQ$ zuC3ul(*OjrVi67&%8{obdV%h^?l%J3+| zNh_$VfIooyI^Si~1Of*LB>sjgd|%`l&9U^SX2>}SIZZ9-osey>)p=W)1gjT2a9**x zl^w)!hVI+>jHB1Fo_@Ji9QCboZ{+R4W2h2Wu)UyNG*!GJBbo!tRWgW;v>Zm7#Kud^ z2>%uEo`+o}H{($0*#2<2U@nUbKauAU&1omj114XSMl0YLy?bg$AmFwLwhTSpBBN7i zU35|h<4JVVJWWP2#P=n}@pp!sg{Pl5+60Wg+X78@d0e46D6gh{L!GYbAdWPg+LKpc zGG|T@IfQ7h3T95FHQf~A0Gfk}3$@26=_o2B>A;mDvw>t&N&+(UKh(B#YSCI+{SrW~6(Sz?_O)a)imX}fa7dv!ZXjrbgH>K`Gz_^t>D)=LE~dQ=e1PmW$=i>G7H8e5D&!rSy= zrvGJ&YdG~x@HyF1xmyvYOfDheLQi(w=- zsIs}|gE{r?Im$chR5SPnM<;G`Fzuxror0T;%QNEy6Di&52$hMv-2psChSb=o$KJo= z*z3wz!`g+?E^hUT6Z3z!ybd}7^G%OXKalOBa@6~}4m-uFP{*5HAE#3%HmIw`NmHCc z;P-b$xOO$tG=F5G*rzB9jO^_0i5B<7c4T}t$vq_2QIlnaU^knT*~P#h+vx>sQ4fU- zT{+xn+mItTf<-R`60$Gzc5TVm?biyUFRzX}ffKg(2K?%kWh{w=JyEZ$*l9bItXTgS zL=DqXn?=+n+2LU@1GTnX1z5|Io2c!-v0PhcS=$ri)!M4?3w`;fSC)lpwDihqH*JfO z)y}`E{GoQbG6NZ&xJwLz!j>Yjl4YQgvOg%+dnIcIziLa=-(JqM+AGn`*k1m4sV;wtx z32Ek4Esn{-x<|75g_8|w9D{byF7?*k)9Jacf|QA*p+(#MINcK7o@7N*3nf*Jx59M5 zOrQ%piw#Jp9;6rOML+n6iu*FCINd@D398m&q-rfjtF0u}S`4XSD6TA^w!g#}RlLSu z5Ou<5wPk!!`b#d*Y0)*lxl{G$D1p>OIz?6492L5`TW!h)8?Ia4(3kmbb1qm*U5jv= z**jvo9o%{!k;D_j$Q;d)vANV_Pw$T7W4?(+NB^Omg{4UyAqLtPq67Z7!OAg6rCo@5 z;RJF!xUG0~Ctmq}#qiGowL!J@EgwxO_o@m&r5JSBmtp7Y&pCD|hHDkSL-dp;R z4uve5S!UchC#d`F+G6T}xRk29Q=VX6kmK+@HwWDQ2wYFt-W=qLSztlA;&dyimWdE! zEbj0$VzeR%cm7%I1)iQK^NEE4sO#uuENd)5eJ#OkI+J(Jj^qC6* zkwV_r3CzRbmn>R$TC&>BvGG2?3t=qtHD?$YFlIu%v{LJ$7{@K}k-!&k15+ z=OWXii4h@d0BraO<2j=pYvAlkT9_CMoSU6LI(Hsr?Kab5LXwUC3)DDw{;CRpEE!Is zb@aAaKN-D~O!MB;s~acZXtZC3&Vn?=+8ZmcTRTb{X?fT}HPj|1j}tUqcE#tl7KCP8 z5DvX8()J<3Q)lrA;F1sz{n@MI!t)MI$_r-Hm$hpoBa>@^%oluj zg7^nQ()Pc)Asuf39dD2XY|GdJa^5287%7QeEE4+%c6IQ9o%@Y@k@sVDBMr@Cbu~ zoF~B^GLJgK+LeqU#oS&$HZ=AqhGF<1#OI<*R5Nh%JJug>Fr$9!d9BV`( z((Kba4_jYF)+yi3WLlWF2?J{)GmMhqpp0Z2j>QVYa*8dq`whJ%xS8*26QrQ{sG_B|g7bwQS% z06##$zpKC)s~Z@fk1{rz=3Au%HAij?3-yiMmn_l$$@>y$o@{FZd@tU$*ATO2aYM8} zgPmNSj`gPbZemyva_rLjhR!~=QycW9S73<;m*l|!B)T7M8M{pLPs9k#wUxx)3DU@q zVn7qyfZI~b=WnBH*qP1a1n&IVYw0Ah&s6bQ46BW7guox56YfFpn6`NDHRQk+KSJwO1?;UVU+hF@j6BOI%<@6ygAsw_d*R^)?6Bk)DBP02CH!$e6-TIA{XfjOUvl-3Sf;~A%C`8L(Oh2<|$-$yBNVjE=^-u_%$ zsV2G**jX-iiOABvAb&PVemjZuED&M8Riv}(mybz?zRz3|~rBhNI<#)ld0Y^#NI`gpf$%|zzMNbSZ zTA+QviHgWSpJ9mTG^C8cvcHFx{U9v+>FMPA?ec_gd=6!j5GI1g$2=ibUE_i#Idu9k zRS;WpzYrAhWM`Cv%2(bGM#vSuj2kWFwP)E>?aubXNax*SB&)Gm-8LSs_u^={O526K z9DPF^pMt@G-T+fn4)Yv~4G1GoiF|p1kl_g88n%xU(xYC|2#c1|bgjVYnN8MxD)+Qv-U5&4wFSdmCL^`ye2|DbgS7qzK|X6}CGdB4jJGEPTR{MiitAZoqa0 zy6B(LwRpO^w~}ls#R7$qiGSb_*d5vQ5TgpV>K!v2)&ojFv`+{v2qzotxWh;hqGlD4 zWNU3BjQ5P#E&6Y?DFfSS$?dk`nkJIiCT=yn5An8gMVQG@8Sjy&?+sHnQR46K;r;aZ zM1jrLm-kaTV;;SdFU^Z>s#?x#LwsT0QB_-~lAhRG{R1y*f93pd=)@#)0Swd=^}++O zA$1)14XL(5n=!SIH{)5NSqXi`W;~kO6e^J5&9PL058jNnnX~X;7S>nGuG3myZMmL^ z@2qdZ*U&aJW)3EE%?iu)EOPmVel6_uSh8Q38oWmLMBVE$YsB9ewhbqQ9@0~IqK-c< zthP5sYHVIumobPyse8L8_l}Z&j%4A%~3qJ=jT`H85{@Fdm8C!Xz%jQ#!H@Mftfac&xyxcb&$oB_HgiQ-IOP2x0x!;M6210zI=ZqjH)%2C!P_%V#9L;s_O69t@fI5BOoo73m z&9?|U8rtx#zoK5`&>6zZD|6B0V*8@m#en6@Lv*5oke>q%xapB)Z5^JHJfVxc>^*5S z5ZA* zOyxII#hX}qGre~t-b@#7jP$02)0Bueuvj1mtFlOUR;fa!`^$66dPhL3Hm(e=P5W%{ z0fRi_G-Yp48cI3NkzGK(st?*lG-5rKFi^}pWaK`{UiTm zGnPl$YXV?QwLhBX>|xXCO{Rt4&=374cypTOF;mdjnC7wZj(a&bpKKVvL?qs80_tgJcnZdTVYPLH0}Y41?6 zbcw0-SNDU&Pk)4RoguwQg5%;dnaeyOiXXraeFU!^&JU^L;ZA2JWkD1Ef=hLrYwcQ;%4>71#1M+DeK|Vob+$KYw3S91eG|5IW$%8Y*BwHFz z@{eE9rV}>F-MCZ#sWUUN7&PUiHC@j04a>QV%ekA&NxYIr6Lw~QPh>)9#UGa>Hoyue zY%QnKlWxWU5HbPa48wyxDay>4lMeGTD_|yn|Xbdf#av zv_^8}V7{OLFth+j5~N#mdOj7qIUA$H)KGB%3?G66B**zoLZV0} zeB_&jydWYBEsGNYeP)qgd!BRdIl3D#Eij43x=1*O`aaQ)oYMOtA zULJ}P|4!dKd&p*GBDyvj7_mQLv;q)CX{bv32$Q}O-WU%#g1|2BK(=y#o8+6q7vId* z?MeB#5KpF%qApgHqXK-noqVNxo6JL#y3iKH+iEczO^Z7taeTojc)NHnh|3%0Ikr_z zrt@_&rG}&09JY#?TR|VtBQuU{IsDg zf?#`pRGKUOuvq$RDd2+oh=RsK+AX>q%=amj0rTstlw+Nz8>e2;tAFhD){7n!r<5b) z5l$s{T5;4&i2Hs1$%Q1Qcau`+(eq|q7>yd)%!DIiK}*<8$WRQ=3>U7N9LcY8Li{Sn zLd)igeHQ}n>q#^4K9h7-0nkNZK=Dv9*>3>SjTMnls;W1fWYR zp5=F2bvBAe{td_>)3kbD8?qP9119HJL@xz&ak5e;ood0vH?v&jHXX~z7gsnt zM6J9-oY?m2go%zKy_Y=F#|&z>jZ#M6rjs5(N4%%LzYw5SEEa8N6P?yqvY+})6#7|O z!}|2{HBX5u7bg)J!h!Vv|N@<1ByOL8Yc0Hmx3?l-UMzGl|p^e`7I)5N~j=+8m<3Xy}0TuD%zh?fgpNhZ2&7EWW|m@2#m)>G7; zB;(KdWa)`T(5n1`9+0k{sC@LDqIN{}my(m~U=V%nJ2B1d=!R4#HE)+MgLx&*;Q>JEQEz`m zga?0Ak|$ENt%&4e#}hWoq@?svo%EP2>wD>2QD2V>Y+2~@To8tX0AiTW8w|#fgXsar z*)*?6p1CBI48P%zs3cPszZ-|3T+eGl;es<@Z?KNEZ^ZPkVzUBM7TfB(lCa&h{6X5) z2(o!q7#XUZ8rGZ@`?;VagpRpgsU()2Np>t^tYkl7rx*3uUNJb>`lFI>XmUw*y1mgQ z=>l`9w-muMyc53>oznBkj!a60`J@Pa8c2+3O`I5LZM$GMMVo#u-PTie{oICEB+DQ` zsccmJ!S#Q3;ZhU4UyCNpV%y!QG1g|mLS*|ZrJ2-TT^MiS_)IM)Y>D9CmL__r$l^N? zm{s}ubFhP8kS|nqSJ%JN-gGXI35#3=Xg*EztIpES{emnLmuBvD%J7SO+@jn$+5_V=6&-k(Z9ZDg^9!)sxlp= zzkjjPx!}f193e|Q44YQx-1Qc|vSa((s5uvHZq%o%#lmh-q=AckAGb@-v!QI%h%T49 zqizD(D^BSJ=O9-ELg4-|`5WDaX=psep zMYwqyhOo>O3mON~8Qz)qM(C8PDj$4Iz9bK}?YM>4?}0#vLTXD|;l>b!tYlajl3fzt zrNMOW5&}b-OoY#lWUO1+>uXIl~ycaQNmQi2U4@!br&2l}3R%RSm zd(E`v!9WNX)bNS?|FQQk@Nre;-Z(y!>*Ts8C20pKFhB}Z3NqCK32kA9Cg~nJDT9;} zpgNzy?-FvUK*IIjBpUe08>W7G%OJREr8`mc?nH!fDp+y~S zr_z>0*gk4ohwYS6tyTadSIl!)kP&BK))I|{dQ&p zYgaNF1jXHcCK*l?V^-Vp>2OvRG2rZlVwxLf(DrBnkP(87Y31&99&tFk$-y!OUuKOB z=)Z^;O|q$tQjl)w1#9YP_jW!MXVp=#dz4YV$(_j7!GI z_Is!&&0S@U>jGq~nKSp{_<~(PmoP8#EG+AljkdMN!%IPmbVncMYTXU%c_y(QfD4in z`|Awwa&kmV`{S9&R5AFfQ_p(@=-Frt+%X5M8p#!5c@t&l(iZVo9;?L^9mIS(^hdYi zP5=C@xRf_7^+zATN)h>0gxbI#{WVq$C;fHks{|2-p7QPf2stTccV$=>!SxXzATmkvU-92(d-NOA3V` z%5;E)&-NFp%khOI_4qY`-h4s-3Y`Nyu@;ssrlY~>GwEn>=NuMjU-h2dB2H?Dw;Y9* z_^Yz$Y%Syrc$}7+vvqEy6U9FAgXPr4He()hA&g;D&lK^PiNtj=K7Ep2In?CU$^3ad5G-;VguBS_XEr%;$VpDR&a#D+>9~W}fjD+uCWlOgH$(K4 zPxnk;^dt=8Y7Ft+uxcHal%3`9EM{1HG2ki$as z^SaZ!)8op(`h><#19{7?nrT7gGXj^8Kh~oGFmMsB%JicdmmvU0FB*h2;e@Sp|vZ7>3sq3Qreav=@*W-rPwkK(~iCnc2ELeuH9W#p1*Q_Re5pqW!&p%|3ub;^u8)Q;2_;&XZ9~#;+6Hd zZ)->q_H>drJOb=5P|rZsyD# z#CL>Nzc3k9q%y|?TEU~q0~()9T*N=m6+QF`aR%>38)9hD9}d7|F|1A&+_jCvdm$^J zCk5NeuMlO{IflHt62Y$bdi3)VUYdpGAYSq>KjV zQ^(MLfQ3qJG47+1c5vaw1o6m|K{eAQkTtdq&C>_pasuO^GoxjeH(cWc-maxbL>?b} z7l^#p9tBs*@e15pdyF@-+!gQlM%TJ3p9N;Dp$fs-&T)vZe)I>$re8WRTbZ~&UkR4Z85uhlP0QGq>9CtT zCH_i#H3%ZmQDYBhm3P#XgrR>_b*u$8%p7q7#Tg#^3s|268{t5eZ5;aVK|Tt>fVy(t z6UFlh84p~TL1zpg^t-wI3b-}yO8_6@4S&lM7QduCg2W;n*ujEX0GMr|LqaY1)*zKv ztu=v^9NM4bIv9m8^9g+JX-5k#yYI&^2(qBCA!i08MsfTmLl^=f#}Zl9Aagvt2MC%_ z5mp@`kS&tPZzqgCM}e77Bx1J3=INCDo%~AO-P( z4Y)N92AbcRz#2G-Q0T&5KWI?{^m`SUAHc@<{BUjLsxI%)={OEH_(I?4he8BEh*}>; zyQE$~dLR7gx9lWlLCEp+p4!M6z25MeK5zJ{KU9a;{1GQ$jD|Mhj~?M={wA`x1|1 zptM43{I@jGx)q(GH5!d^dLT_0i>@`Z_n1u4+CHh7qI1mIXQ_hIA6e6E*?j|xp=r?I`DF3YeQCrmikMflp_ zSQZvT*cIMSEg78$TjI;CHe*j^h6Q-5I?MXznFC0N2C~vh02>r=w>FGh!L%<%RG?7^ z&H!`|xWB5!dAb!|dwO))S3gx!>R^}MkT-S7>oSOv;?wwp$@p5G5K4wbgwPdrTxtWU zk#%3nJgQmHp~GK~(EtuLuqknZ80DXnLQ_=Ea@4dMz}(S*b$CU(x$2dpTKnBdUi*h= zAPdTn7t{MKAQDU9`;K^M<16$7u9~wlx@}X{N0t-3SD+X%?3ZA|PMC~Yc@N2n1odlR%=%M!Q>=_+x1dUj)}aC|lVsf%CYLc+)ejbP zP|=CZsT=-f+Aux@JK60MaZu_uWJLouY}H0;)zp{!eXh*lzElR#W-4Ox!PcLvNmjB@hk#BDpUo{-TH8 zv94*xWnezY3cZmXF#UlW!P4nScgA6`ADjnAy6?Uuj&vRk9KG!DojQeb zOPj4vXtO<#T_XsL0u#at>547jls0!492_>z!BZAS(FT^1t0BGx_&6iq9;OAew)bme(-7N2EUn z)6e_?8Nsth^t|$TP%bJ=VELwB`16EGlXTxC1^xZf_t=bz7u|a(0qy`q)B+@^OzRLe z6AFo3Vi2%QLfODJUVFJ{_F{Nlkg;XJTfLBfNDO^4%& zvt1am{C*~aRs@j=U@ZymK}#!;CTv|^0=&@L*47fO`eQ)T0D*keGYyQWw&`G1O6N(8 z7yEIBU#or`OrwD8VlE!afl)TB1AA*LgzfQ6Q@67e_#9oPe32*E#9*&4$tN8x!LIDW zeZkBOv6NSfeSx913r#-=x_zCSQ0)a`$}_XzpL4Szj0-8~VPILw^x#|@H4hkWdUq~{ zIG=EO-GeEEhmEQZ5=y@IYFWc4?YI}H5UgkYAt?l=tfti{cD>SozgpXsiL@`SN2Lb3GdqT2lt{HrAF8%b$GK$=&IWgRj|Idd`kr7AQS0r#%kOsM~_Lp)f$+-sJCm04?FX zaC!nc3%#AfgRHm_hc@i8ZQw)hkIad$PsLW*Wo#rfv}#Lr^gA|XwL*`Kvf@-WWjEq9 z-~y4qaQ7+8Pgd|RtMC@smzX|5CVCk)mzO4M443E`s&bmhE*X&)>T`ce^uHE(WTbc8M4JacEEcC_?U%3#!RH=98u31fL9caS_`j!-pRwg&aY%dpQ5gCnjMJy2 zmqli{yOAYr*Jhldtj)81(ak~HF`w!3MbGu!K9AZ$6tjKZj)qpz8mw2c)LWwa@4!nIjmI)&4E-Dm(N8o^ctPrWE z1*cWR&D2JosKtngkBeadV*l#|sqq%_N$L&p954FH`?Zm=TJYP=CO4RC@RSj;kQq=R z#Kh6sQP~J5S-Yq09dQR_g?awUgciD&`dI0w#0d2Raff7%boW-eI}h%{X7)OgM1IiX z*AtKU<}bH5EddpcEx2I%gBvR2-hB(xO4C*~e79oetz2XS1yOt^77O}(F_sAB_)Bc@ zoaSAjOR~UzA2m4Xfo;%knwtFr(%vkbM_{Q?<-9yY7%r6MIP8Kk^r3g{s-bb6FS1vU zUg{vebl@3wik)=jLu>QtpcVUN2A-_pvPYRShenw}O2$23TPFMxLP`QTogm4E9(A+3zgSj6q zMNqssx<_m{SSf&8&KBTKpLOFOGw8rm0gM13J(&hlZ|i^#(m!`oPHkk~Q2bRPbHg=> zW{`#Oq0t`A*<33wHfDKuRh5@OSGdC}^s+GD*H~e{;)85FO(!9>W(Dv%_hrS81sl3( z7>}^?!_BlAfQ+>EH8LSCgWGVS10Ot)4B9!$1lXA52&q3Ed>ZUtI8$LRXms7-ae-tg zx1R=VChhug#|MOUx)yqxde}Q!sFHM)rE^HNxyxuKW2zmUuhxRGVdsCDebtC(fdzl5xt>)mx&KP&hO`v}6V&GByD{6JB zanO*ACSs(8#)Dq(DYG;4AMn@2(>gxPB9H1AFi}i-d%?ciIF$(X!M|yeTjaAw|;jZWPV$;qlBjahwG2q-v^HkSlIz>a17$M7CfkrIfBF|bATwxe?&~r0|`hmy2<^P4tw}3?2ncM zZ|@2eW9@LG;@iG3xD)#XzeJsJz5M6 zu$dx8EA%1hF@^$WD%NOJd=}xQIX6M{4NM;ppg6$NclBoBWf@`XKv-nk?j(0QVUlDl z{cQ$Oh(%t8vHE>HOtFO)IVS4&$dba^f~Q6MS_njzeF)S#elqSd4*Fc~T;3oRUf zm;!|nt3oRGV$S{8Y?GgFrKouGIp{ApZGV=A;vuoNbY?GP5A!O#A~*b zCsX#kFI@Y}IblbZ5MPQuK)i=!?`56Tt}Df|19JoR6K(T!L9_QI9f<2E&0;GE&Jm;gsE^h6Ji9D)@P803lrOnn_GCX7G7a` zxyE0&=x=qxg0GH?BvV87eFefo53^mBc^(eMu$iQhizAeim*2t4Nk4cGck#IHPRZ{u z6XU8siiWufwT4gOwk@)M(Y8IAvp5^~mq)y*wap@fQ&KBu-=vwdkzLx{O})yPIUlgjo6rQbo@=$7wzIvN{!+^;s3`ISX4|@C?u!wT5Ud< zd}7zJN)9dkYO+4h9@Z@i*6ydB<<+p^xx|B>B&!m2)XBj>NNal@PYY51<}8fzns^9K z88ZAxXLh`3|D!)>8vQr@j%Oit^v5p}T`8Giax)6ll9YtHRQ4@J>4wDnzD9OenSVxV zcJcLLHCrx)Rqs=jac~pH4rOM`e(8fMDs@<T9$Eon|Ybolm3A|i&`T&~zij@_YH zp--gQ*ht$^3*6ckd7;nJwR&BK>|o`NBKM7IOue&z3DJunR-@ zW8bAS+gA&ObzoG?mWi?tR51!nL-)u{j2>MM0k4+AzWrL4r{l|29m_%4d{Lery$Fn5 zy;g7JJzwRM&8@YaUx(A@O7LU70=5~KyK19zy}O3McU~XL5y#mNTaNXFug&xP3DSH5 z^Q-r6Yi;C}_#i(3_iT9IA6aXUmza^ia(feK-aqjIn-uul!%+_M@JBv`4B{c;rK|jl z_M<^h+hbs&5Dq|;@VYz*({0!9v2sjm*oQt09xtkG0|qk}fu6y(1sxzkT9Rxc12`>dB#il0U&^M zG6E&gKwvCPpc00S_a*S~Trh)gpG>5@=OC1{HdqDhR zv637MwtN?%@!n~cmP>e-h3fAkhP1X;8L(e zUh6>nv*%%WL>{6uQOeiu70O3A7(pwXlFF~xlwZ+PuizF1M8**MO6J!A`N4;U5&T=F zsLk_n|B?T>mBu`3ZWmMVQII`= zrSYl1)sbgsDBmi6G+eCwVg<Q_(jgHu8RvhSD5UGN3;A`h1cR{;9i_z^%|R7msW*~? zlsjlS#%cqw>8u{Wepfoa|-_z_{Sp{ zzzk%jhp+Q1Z}3fP6?`9677)z^A(eLjaA?orYf%u$re*Q#(4+_}{OsHTG**7L`4R}nUQ$(&Xuj7|@m}+vsw#Fj_kr>x z{twOxa`|C;F7^B5awz5k8E9>dFv=hkt?k>S>E9L~qoaRvX6Vdbo11c(-M_VHeJ;ut zPx&*xdJNCtsSbZ(?tXo4uY1v!?sIz@W%U02*kH2VpAw_-`chM)`#|};xd1h+8f01v z`}Z}z&c?*)75)r3c8|Bb1OLRoPEVn~dWYtL*6~0)^V3x|9r$Eo*jup&sQ4=$Zl33@ zc)$6C_^XuW-eeknzV!5t_4K@_;)&)w543w${7nqYybYTR8>%+vi!{`OIat4v`=@BA zc{%%SsPq25Pea{684ce@JA<=(1xZuV-Vb4J4ekTSybwE(zyhO*HR_8dL*mu%fS%Dp7bQ9Hc< zI{fg3ed@4^>X0Ssa3X=jpCMo;@Rd>Q1{>^_W-wA+3<6uS;`Qg?vWu#ZX}HdBodNw8 z^&xN>oIYbW!=X6kn(q)39@!_tghy^y;4cxlS89R4zYN+TG?CR(fbOs$Sch4_jd7a5 zH#U*kG96k6^zgfykJl5Aqw(aoo`5E{;jmsbV7IVzUXj1EIsI+NkMFCSjp#WpS2WY?Eywub2 z`-924jDj&WlaVp_P=h_f-Ket3MVG$j#jrZGpditKZqJ|;Xw+}JC)r0oCnQ<2 zI!nB=I^V=1AP1Bm*)xCnh@Di@RGTVz=^A{g9bW3d+MGodnS_eeVnn>RVK$2|OV8sX zQy!u!_9?4Exk6QD?zbw=l!i2V8f-Ub{R(G==xK>r=ii5h@4zbobpi|ClFH>-5Ii3C z2ykYM{YK1&N7MQ7jn7_l-}xn;C;F^y55s|6q??5EQ@o*axnrGU{_>gY4ys&kU+0;> zymTGz*ZzPvm%t_Mra`!--8A4Fu3Tkr!QjO8QZ263^~$rk%VM zV_oEtVx@AUu0Na1t0yE&C~InLNZ#o zn{;^(ddN0u7iuQvK3p9cGcJXoYaR|jS!TtmqF5d@CdQ3^HH=kzd~bXrc_v0+r04JG!v_ujARKQ9T%cH@{sYyJzNAI6yc_fWD(vq z3ZV$d7u8%o3$)cmtD2;?`Vw2LaO&*Fj33=&F83}f_i0+&KiNVP&DMp8n+pAHHt+DF zWV{+;W2YCp#hQ9ghJ23~Ovz4w_jq^h0NZ9L_HHW|8%n)=i7+n(Hv;pU_F6yZO$DYm zWt!jgP`~L-x0>Gc_8Ia`S>`wW;Pc+}i&STTl%_XbV1CotrZ-)ed{eghO|w7yO)c}~ zTe8h>`RCo@Ey6(<`<>}c4tP_HoKw?3JJ=`y4N)Nu(|tO`A~>(FE)*sV-Ks=H{diE$ z$XnP=8t=w#Vrp%1`8?C*tkmVxO_#G%m*?EAn8`#kV`Mnfx$q7fEt=ghiLA22qB)~K zO*z-VS~+xtfp*RHhA}=11yiSG2knM5`zG`k@gi4l=-2EzvI&J+A`CA1*U?CHi(zPd z?*fnjM1Lmy3Yj?As0Y(%a3&4-LcbBZnApA=L8xvxmJ47G+U`$4~K-$T_ zCJA3UegU;)#y>O!FoWrt;22*$mX>%L3cJm*DCeMrPRDYHU`a$ zp3J@om1w6v_--Y%)Bx)@AuQbQQNp=WyL{(Lt$yGGt#JTA<1nZRS88jY(vL7c)UKGB zxl+4g`%0~OaHaO##7a1rp1o4rumbfOaBhU3AcKc}X_a<=!e<@w9r2!zwOW(Lru7LF z51!`jtVvWIF&-I$oKRwq+G0@c;yd69WEJm){GW&XKWR_2=(-ieJp&LyZl^tl=ET0; zFZ&>fU35j}gs|a)^iJahHm$Tp>TEkbh35FY5nF68&4lR1jk;?Lo#Ob=t6h;*j{kyQ zkjh;T|AI`^C)_&Wef9XsThU3&vIB?=q9>pkm6?b6p_cmE&TE|{*$e)b)Wz-Oswh0s zFDq}Yja&mpwckQP!J!|0H3Q~p@5OA!-uzwYK@``1>r;cTvU@a&9e}?3T{!Hm{1eRl zPop%R7)CGp6a%7z{V#r3!MPYPTK;R2l+T$hN4TsCj=MDNGwry;U9#U zAb^5S44LN*ooa3QD$uyuxJrpKYcK46D<{?-iY$|Zac6411{>o^VE&I)C2$I?v0JGE zsr$`7+@}M58F{3DWsz_7P1yNMb?YO(Oe!;Sn~?y%u)~*m0|n%+e1B~T9Es>viN_-U zi~&Dh0tj}XFIcg0HtuLpd3M1561MK3U3Sw1FedyqH#>eYvDZwZl0%*O<;{R*WR5U{V2&HGC? zL2EU>s6h{Wg9JzS|2Mv?Kpa2837LY9mVmW3g$Z2@9$TkBN_DJYAux%OX;&${Q)(K~ zE`X%;Xs3-LDloYy76QYQpzay)Hn1-l#1lXc#kx(NNw!x$(qa{!`G3I`YLXoDBaaxj z{1F#G?Bi?gKt|sIBKfD^f@ElcFo^#4vFmSR`LSH$bm>sH9@i(~ko=<&d}&Q1v2mr? zVOb`IQ*-AcM@kDLba%%e0WF7I#%2MaLX(dXB>&-703Fch2YIqy3HRc{n#HV+$MPE ze2IbhNF7=QedPoEzV{E22x8U;nqarMeTdwUp`V=Y(C44-T$_VuxVSHxkr;+U;2Kb> z6bG-Y%V==~uX0(M3t+Ye!N(( z=P{i+lRtW@H@bPkN`6%<*u?-Sg@tM;l${MzMQFaYr3iIdIQ_@2Mt>o6WyNk| z10`h}E!*$1EjTtg=#C6Jebiq2?WrK8a-n2-BepG!)*w@`bh*G3G`{3Ob5 zhGQy{c4}>d$f6|8_1BlLu(WuS&hNNd;%5i3iX|1~TWpSqxFDBA19*Y+(X%{Kl9(=W| z_ze)bCte6YC*zrV;$g5X1xlgKxSwi&p}Ejod9h<%j(7gWGuK`U*bdmXE+25Awh4_L z(0$`ixD&0s*sg8HP&II`RNFjg6)bWNm`3x*aT?u;UX&=9d5a9+Y9r%`vN`t&LSWc? zfndH?t9m>3HhSoQFls$fQq$K@CZLa#0KwKSp|*q%biXzAfiNoOrp@w8QNCLH%}I|R z^?UXH0R@UKvU$L1r~%xQuH|aO*IhtO zREn!QEdOlY;t@4V>;y|C@=7U&)pxV`kMDcJQeRCD2M|*Y|GF?~ z{E^Qp0zJ-&Q)wtm%q`xDZR4Ue(tkew7ns-1nb0h>UjB94l=IrbG*j7#Tl?jBHcer` z$N$7s^Az?gZ{)G0C=+KUThgC1QTDw%VX6o%D7Uuci-G?%#(=sEMmo6Jz^dq|jRIE> z1Sg)2U#gJ=$&#?{p?>;6TKms=lkSLBXW(>pS@{B7@thEB(1tN*$?<{Kcran8jjn6( zMi2LbxENp+>cm3>nX3}sI={AP04_V=vLF7=#AyfqVn}+A7g-vrkg0faDLPp}gSlx5 zh0|1nUvS_1%YkuW2kd4cN@l&)SNZ9hYjOU`w(>0Wu5NwS8$E7oZRL)&XIH+s_Ds5K z5qEX#TX63txLiY*6X}t=9#e>ovKN~sB zel6aXrER_$eqp-JcUm}tBk*JVnz*B2g!{z^uY+@RqRjCi4jr@?!F=&-k=W5|1)7OB zp}`><#H1MLHuFF~jt6>UJ7*ha8I#35?ng+U^ za^u|*+1%M6G(`)AfuNwi*xwhyK%ZqH0sZ-R3->jrNdi2jHwYP>N-7H>3KjO>lr}RZ zMP|vkJ>IVtmPuk#PsV?Q_MRVUf+8;u1^*D-0`{;llxv)8Gl^X3$taRCb)E~+X$FED z>VO2hY6NyHKJE08#H^yb(j_aP9>%W2Y$YE{10&J0- z%xe7p9nfQdJLLjj=VH*5c~|%&mtgtDeUg_yek-=o5;ysnEU{tTPOpuUar|mGZgDHb zfcK*#;`@KW`QkKd%Q3iX^~Aii!C37E_Yi!%mK-B1_pU7gqP$qSm`fJWRbP~q!8V_0 zB9yJ=0G%RL;4hASH~hu1e;oY9vF}6zQ21L4e@n3s5M>*@L<`juPZM<9&?oE< zW`kM2)Wwxw0sF$pL*NuJZ*3kIFg`T2h-{}KtB<2$DU1|g7`U~~xc7n)cig&bu|oyO zIphU)(5_&c_rh}8W$ghz{yS*}u7FisLs|`N4#L6KnD2+=_0r^lMr?%-%F^#nSLlhQvD1Q@$gY zVi$-t-u6rQ+`tqeR%TO)6J;Czm|C6R!={McGfA&PB?4tc6H(jK$R64!3Nu7>0_dy} zIf0Dv;0W?D1lmfJ9eg|HwgWbOvOO0ar-$ZSn!ieO%p&Sz@uP)Yd` z<*!hQHXn+C{S93kRM{C;_1?Y069GTz0vFm(E6*fmU2~_M&QA4UN8MR==KC61mqt-@ z`jh*lLe)X*=ShB{>w-n~Z5J(82(4R?B5m zzVb|XrO54666~Ejl+0$nw{o#<-HBdgOg@2XX%xH$oiA0zc$v8T(LYR=ub#5z`>B=# zp!4~6^F39~x8k9+e9;;ET3d8! zA;`MzAcZ(AL`GdgMfz_#IW;H5@t6^(1N8EqP4)-;<&^$w2FzkiG=55GhKL$R^cGw71KCzaw zYr)4MQtp%T!bu{1<+in)ez%rNj|?!|&#sDIl+}50qN?(RCQfu4JQH_$JI^y;T!|MC z@^+q27aii_EK_dB;Rb0tG|qIav)fy_r^zFpda@Xj>eYgXsk-tJul9pMuWe6@E^aT! z+q2;|kU|Z5D?j#V-yf=SKhaVcKL(rQNVp{5cV4kt`uGiy-J1UBNmZ3EH60?Jd8H`z z%+a_>MnkB|$7MZ!0=MIbS3WE8HxO%8l{;nn*{1X^On(fdAF|}*&zbNux;QI(W?}T) z(&)NqGw=l{6Xl zAS(if0s*px_hI5~JGqOzq`_|xEVIFQ4X8xWmF@T#h)b73{Iw{I_}1c-%Nk%D!UFmBZ$3jEd9gm+Khw%*5<>&wgG#aUP;_j zYY)>`Z_hcSa~=d**;yFB6+fvcLxwN%_jn)G-w4}Lz_BC#Gtw%^=6Dy$QXojI}m;1XO8 z8rspNy|c0XJEb(ux4>_Ox0JA?0Adtc>J(F2$9Wd{xFTy%V2Xtv1* znuyo&vvFo#XV=p;4Ri}evzm1zV+JuP9D*^STX;%&f7^_d+tJLOQ(wB0>0$1&olWJT z5kE$2u)YocD#gsY=uIc@(YtFlZr}EKN}3bXKFV74gS_EfPzPtjY<~lBIRoEt$U1@K zYghDn93G~Jf8rZhEcEnbLAMKCv}mjoxr>+2&WCmkMg(lZv@wdb}!}{lI`qw5Gc^Y%c^?mimRYk`?Id`mdy7wWrQkT>jD7Lio ztnT&jH5PomV~CU&fiYg3WV9y>(@`E9QZ7nuwLceVsbhH4>T+*v9!fiT!MMwRDP$Pc zJkN#;9-TQpDr8Gto!C5`7-YjP6zcFLq*rcuPsTa1R{vE*tUkn_f>}?J`TggO=Pj~{ zZ;^$xsd(*})&^<^xwWze{&sOYcAsKjRyL37P(1Z!l0272`~fy7+#r;Grpfiwh&c1+ zB6Vz+;+0Q5T9COb$LHelvT2QX1l*>AVihj}m@byD$Sf{0DFQNKlZfob`MG!-AtzJ%v(HzfNWha1-^bo5sV zxvL%DD+$7OS^K5HJNf$)qFP?1dzp0W93jH74GnMTrX}^GrzOH-g7zpw%h(Zr1tKq* zTL^v${cgV3$vJ_gtIFeUNOlA~xb{`1*#|-CEiuy^?o+VI_`t_KM8~`V(jg( z9*qyVY{bRAU5#lt*7Wpn5)JlGK0_%!tV>g$D4=*-jlB^K4(1^zwPF-4%co@-Hd?Q3 z^cf&S3Sr-GJ1yJEP}!9~1AFEh%G*KP@DvY_{lMd4KSQsn{;(vdQV^h`F#92+pB1Bh-#}mZs`GZszRPcK2+lkwQg8V9o%Bw4PBVWAZI z5lM#c`{ON~jdfcF+J$EMv)#XC+UjP}SM=-Vo=Z5szU#wpO_H33elz5N|Da&)QQdvO zJe+r*y;%n7m;l2RfteS7SgbRs+QomQeZVb|Tf+4@k0MQQ3Y+!&oHDL-_#Zoc7(SzG)ZaAK@PDcYGuM96d)N z;yU6MK8m`%Zc*M;%awZw)IO67j4Gn9?6#U_?J>-{&&sBg{2vLa&VP)3PW?ute!r

S&C=?h!PVi4{f@#+l|?H=C=d$?Rd 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

**n27wNkN&Z6>Q^mA^nC;5s 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

^m|B-N0Aisu#srS`$*;!LcW!PE=m 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%0DO%nVxLK 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 z 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 diff --git a/docs/SHIELDED_CLIENT_INTEGRATION.md b/docs/SHIELDED_CLIENT_INTEGRATION.md index 619f3141c8b..8fb338fe932 100644 --- a/docs/SHIELDED_CLIENT_INTEGRATION.md +++ b/docs/SHIELDED_CLIENT_INTEGRATION.md @@ -693,39 +693,110 @@ The BulkAppendTree's epoch structure (epoch_size = 2048) enables efficient bulk ## 9. Trial Decryption -Light clients discover their notes by attempting to decrypt every encrypted note on-chain: +Light clients discover their notes by attempting to decrypt every encrypted note on-chain. The Orchard protocol uses standard `try_note_decryption` from `zcash_note_encryption`, parameterized with `OrchardDomain`. + +### 9.1 Decrypting from Bundle Actions + +When you have a full `Bundle` (e.g., from a state transition you submitted or received via P2P), use `try_note_decryption` directly on each action: ```rust -use grovedb_commitment_tree::{ - IncomingViewingKey, Note, TransmittedNoteCiphertext, - ExtractedNoteCommitment, PaymentAddress, - DashMemo, NoteBytesData, +use dash_sdk::grovedb_commitment_tree::{ + OrchardDomain, DashMemo, IncomingViewingKey, Note, PaymentAddress, + try_note_decryption, Bundle, Authorized, Action, }; -fn try_decrypt_note( +fn scan_bundle_for_owned_notes( ivk: &IncomingViewingKey, - encrypted_note: &[u8], // 216 bytes - cmx: &[u8; 32], + bundle: &Bundle, +) -> Vec<(Note, PaymentAddress, [u8; 36])> { + let mut found = Vec::new(); + for action in bundle.actions() { + // OrchardDomain binds the decryption to this action's Rho (nullifier-derived) + let domain = OrchardDomain::::for_action(action); + // Action implements ShieldedOutput>, + // so it can be passed directly to try_note_decryption + if let Some((note, address, memo)) = try_note_decryption(&domain, ivk, action) { + found.push((note, address, memo)); + } + } + found +} +``` + +### 9.2 Decrypting from RPC Encrypted Notes + +When syncing from the `GetShieldedEncryptedNotes` RPC, each entry includes: +- `nullifier` (32 bytes) -- the nullifier from the action that created this note (needed for Rho derivation) +- `cmx` (32 bytes) -- the extracted note commitment +- `encrypted_note` (216 bytes) -- `epk (32) || enc_ciphertext (104) || out_ciphertext (80)` + +The nullifier is essential because `OrchardDomain` uses `Rho::from_nf_old(nullifier)` to validate `RandomSeed` and construct the `Note` during decryption. + +#### Compact Trial Decryption (Fast Scanning) + +Compact decryption only uses the first 52 bytes of the enc_ciphertext (version + diversifier + value + rseed). It's faster for scanning but does not recover the memo: + +```rust +use dash_sdk::grovedb_commitment_tree::{ + OrchardDomain, DashMemo, IncomingViewingKey, Note, + CompactAction, try_compact_note_decryption, + ExtractedNoteCommitment, Nullifier, EphemeralKeyBytes, + COMPACT_NOTE_SIZE, +}; + +/// Attempt compact trial decryption on an entry from GetShieldedEncryptedNotes. +fn try_compact_decrypt( + ivk: &IncomingViewingKey, + nullifier_bytes: &[u8; 32], + cmx_bytes: &[u8; 32], + encrypted_note: &[u8], ) -> Option { - // Parse the encrypted note into its components + let nf = Nullifier::from_bytes(nullifier_bytes).into()?; + let cmx = ExtractedNoteCommitment::from_bytes(cmx_bytes).into()?; let epk_bytes: [u8; 32] = encrypted_note[0..32].try_into().ok()?; - let enc_ciphertext: [u8; 104] = encrypted_note[32..136].try_into().ok()?; - let out_ciphertext: [u8; 80] = encrypted_note[136..216].try_into().ok()?; - - // Use from_parts() — struct literal not available (private PhantomData field) - let transmitted = TransmittedNoteCiphertext::::from_parts( - epk_bytes, - NoteBytesData(enc_ciphertext), - out_ciphertext, - ); - - // Attempt decryption with our incoming viewing key - // Returns None if the note is not addressed to us - let (note, _address, _memo) = transmitted.decrypt(ivk, cmx)?; + + let enc_compact: [u8; COMPACT_NOTE_SIZE] = + encrypted_note[32..32 + COMPACT_NOTE_SIZE].try_into().ok()?; + + let compact = CompactAction::from_parts(nf, cmx, EphemeralKeyBytes(epk_bytes), enc_compact); + let domain = OrchardDomain::::for_compact_action(&compact); + let (note, _address) = try_compact_note_decryption(&domain, ivk, &compact)?; Some(note) } ``` +#### Full Sync Loop + +```rust +// Fetch notes from the RPC +let response = client.get_shielded_encrypted_notes(start_index, count, false).await?; +for (pos, entry) in response.entries.iter().enumerate() { + let position = start_index + pos as u64; + let nf: [u8; 32] = entry.nullifier.as_slice().try_into()?; + let cmx: [u8; 32] = entry.cmx.as_slice().try_into()?; + + if let Some(note) = try_compact_decrypt(&ivk, &nf, &cmx, &entry.encrypted_note) { + // This note belongs to us -- mark position in commitment tree for future spending + tree.mark_position(position); + wallet.add_note(note, position); + } + + // Always append the cmx to the commitment tree (even for non-owned notes) + tree.append(cmx); +} +``` + +### 9.3 Integration with ClientCommitmentTree + +After detecting an owned note via trial decryption, mark it in the `ClientCommitmentTree`: + +```rust +// After successful decryption at position `pos`: +tree.mark_position(pos); +``` + +This ensures the tree retains the witness (Merkle path) for this note, enabling future spend proofs. + Trial decryption is the core privacy guarantee: the server cannot determine which notes belong to which client. The client downloads all encrypted notes and tests each one locally. --- diff --git a/packages/dapi-grpc/clients/core/v0/nodejs/core_protoc.js b/packages/dapi-grpc/clients/core/v0/nodejs/core_protoc.js index 5bf2a3edaeb..5d91bb2c010 100644 --- a/packages/dapi-grpc/clients/core/v0/nodejs/core_protoc.js +++ b/packages/dapi-grpc/clients/core/v0/nodejs/core_protoc.js @@ -13,44 +13,44 @@ var jspb = require('google-protobuf'); var goog = jspb; -const proto = {}; - -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeaders', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksRequest.FromBlockCase', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksResponse.ResponsesCase', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BloomFilter', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastTransactionRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastTransactionResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBestBlockHeightRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBestBlockHeightResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockRequest.BlockCase', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Chain', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Network', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.NetworkFee', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Status', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Time', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Version', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetEstimatedTransactionFeeRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetEstimatedTransactionFeeResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusResponse.Status', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetTransactionRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetTransactionResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.InstantSendLockMessages', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.MasternodeListRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.MasternodeListResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.RawTransactions', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsRequest.FromBlockCase', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsResponse.ResponsesCase', null, { proto }); +var global = Function('return this')(); + +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeaders', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksRequest.FromBlockCase', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksResponse.ResponsesCase', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BloomFilter', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastTransactionRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastTransactionResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBestBlockHeightRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBestBlockHeightResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockRequest.BlockCase', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Chain', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Network', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.NetworkFee', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Status', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Time', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Version', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetEstimatedTransactionFeeRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetEstimatedTransactionFeeResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusResponse.Status', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetTransactionRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetTransactionResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.InstantSendLockMessages', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.MasternodeListRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.MasternodeListResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.RawTransactions', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsRequest.FromBlockCase', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsResponse.ResponsesCase', null, global); /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a diff --git a/packages/dapi-grpc/clients/core/v0/web/core_pb.js b/packages/dapi-grpc/clients/core/v0/web/core_pb.js index 5bf2a3edaeb..5d91bb2c010 100644 --- a/packages/dapi-grpc/clients/core/v0/web/core_pb.js +++ b/packages/dapi-grpc/clients/core/v0/web/core_pb.js @@ -13,44 +13,44 @@ var jspb = require('google-protobuf'); var goog = jspb; -const proto = {}; - -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeaders', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksRequest.FromBlockCase', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksResponse.ResponsesCase', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BloomFilter', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastTransactionRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastTransactionResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBestBlockHeightRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBestBlockHeightResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockRequest.BlockCase', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Chain', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Network', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.NetworkFee', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Status', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Time', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Version', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetEstimatedTransactionFeeRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetEstimatedTransactionFeeResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusResponse.Status', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetTransactionRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetTransactionResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.InstantSendLockMessages', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.MasternodeListRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.MasternodeListResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.RawTransactions', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsRequest.FromBlockCase', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsResponse', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsResponse.ResponsesCase', null, { proto }); +var global = Function('return this')(); + +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeaders', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksRequest.FromBlockCase', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksResponse.ResponsesCase', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BloomFilter', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastTransactionRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastTransactionResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBestBlockHeightRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBestBlockHeightResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockRequest.BlockCase', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Chain', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Network', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.NetworkFee', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Status', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Time', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Version', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetEstimatedTransactionFeeRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetEstimatedTransactionFeeResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusResponse.Status', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetTransactionRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetTransactionResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.InstantSendLockMessages', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.MasternodeListRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.MasternodeListResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.RawTransactions', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsRequest.FromBlockCase', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsResponse.ResponsesCase', null, global); /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a diff --git a/packages/dapi-grpc/clients/drive/v0/nodejs/drive_pbjs.js b/packages/dapi-grpc/clients/drive/v0/nodejs/drive_pbjs.js index 6a3c8772fbc..a3f48de6292 100644 --- a/packages/dapi-grpc/clients/drive/v0/nodejs/drive_pbjs.js +++ b/packages/dapi-grpc/clients/drive/v0/nodejs/drive_pbjs.js @@ -83715,6 +83715,7 @@ $root.org = (function() { * Properties of an EncryptedNote. * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 * @interface IEncryptedNote + * @property {Uint8Array|null} [nullifier] EncryptedNote nullifier * @property {Uint8Array|null} [cmx] EncryptedNote cmx * @property {Uint8Array|null} [encryptedNote] EncryptedNote encryptedNote */ @@ -83734,6 +83735,14 @@ $root.org = (function() { this[keys[i]] = properties[keys[i]]; } + /** + * EncryptedNote nullifier. + * @member {Uint8Array} nullifier + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @instance + */ + EncryptedNote.prototype.nullifier = $util.newBuffer([]); + /** * EncryptedNote cmx. * @member {Uint8Array} cmx @@ -83774,10 +83783,12 @@ $root.org = (function() { EncryptedNote.encode = function encode(message, writer) { if (!writer) writer = $Writer.create(); + if (message.nullifier != null && Object.hasOwnProperty.call(message, "nullifier")) + writer.uint32(/* id 1, wireType 2 =*/10).bytes(message.nullifier); if (message.cmx != null && Object.hasOwnProperty.call(message, "cmx")) - writer.uint32(/* id 1, wireType 2 =*/10).bytes(message.cmx); + writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.cmx); if (message.encryptedNote != null && Object.hasOwnProperty.call(message, "encryptedNote")) - writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.encryptedNote); + writer.uint32(/* id 3, wireType 2 =*/26).bytes(message.encryptedNote); return writer; }; @@ -83813,9 +83824,12 @@ $root.org = (function() { var tag = reader.uint32(); switch (tag >>> 3) { case 1: - message.cmx = reader.bytes(); + message.nullifier = reader.bytes(); break; case 2: + message.cmx = reader.bytes(); + break; + case 3: message.encryptedNote = reader.bytes(); break; default: @@ -83853,6 +83867,9 @@ $root.org = (function() { EncryptedNote.verify = function verify(message) { if (typeof message !== "object" || message === null) return "object expected"; + if (message.nullifier != null && message.hasOwnProperty("nullifier")) + if (!(message.nullifier && typeof message.nullifier.length === "number" || $util.isString(message.nullifier))) + return "nullifier: buffer expected"; if (message.cmx != null && message.hasOwnProperty("cmx")) if (!(message.cmx && typeof message.cmx.length === "number" || $util.isString(message.cmx))) return "cmx: buffer expected"; @@ -83874,6 +83891,11 @@ $root.org = (function() { if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote) return object; var message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote(); + if (object.nullifier != null) + if (typeof object.nullifier === "string") + $util.base64.decode(object.nullifier, message.nullifier = $util.newBuffer($util.base64.length(object.nullifier)), 0); + else if (object.nullifier.length >= 0) + message.nullifier = object.nullifier; if (object.cmx != null) if (typeof object.cmx === "string") $util.base64.decode(object.cmx, message.cmx = $util.newBuffer($util.base64.length(object.cmx)), 0); @@ -83901,6 +83923,13 @@ $root.org = (function() { options = {}; var object = {}; if (options.defaults) { + if (options.bytes === String) + object.nullifier = ""; + else { + object.nullifier = []; + if (options.bytes !== Array) + object.nullifier = $util.newBuffer(object.nullifier); + } if (options.bytes === String) object.cmx = ""; else { @@ -83916,6 +83945,8 @@ $root.org = (function() { object.encryptedNote = $util.newBuffer(object.encryptedNote); } } + if (message.nullifier != null && message.hasOwnProperty("nullifier")) + object.nullifier = options.bytes === String ? $util.base64.encode(message.nullifier, 0, message.nullifier.length) : options.bytes === Array ? Array.prototype.slice.call(message.nullifier) : message.nullifier; if (message.cmx != null && message.hasOwnProperty("cmx")) object.cmx = options.bytes === String ? $util.base64.encode(message.cmx, 0, message.cmx.length) : options.bytes === Array ? Array.prototype.slice.call(message.cmx) : message.cmx; if (message.encryptedNote != null && message.hasOwnProperty("encryptedNote")) diff --git a/packages/dapi-grpc/clients/drive/v0/nodejs/drive_protoc.js b/packages/dapi-grpc/clients/drive/v0/nodejs/drive_protoc.js index d43136990a8..1373c867d42 100644 --- a/packages/dapi-grpc/clients/drive/v0/nodejs/drive_protoc.js +++ b/packages/dapi-grpc/clients/drive/v0/nodejs/drive_protoc.js @@ -13,12 +13,12 @@ var jspb = require('google-protobuf'); var goog = jspb; -const proto = {}; +var global = Function('return this')(); -var platform_v0_platform_pb = require('../../../platform/v0/web/platform_pb.js'); +var platform_v0_platform_pb = require('./platform/v0/platform_pb.js'); goog.object.extend(proto, platform_v0_platform_pb); -goog.exportSymbol('proto.org.dash.platform.drive.v0.GetProofsRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.drive.v0.GetProofsResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.drive.v0.GetProofsRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.drive.v0.GetProofsResponse', null, global); /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a diff --git a/packages/dapi-grpc/clients/drive/v0/web/drive_pb.js b/packages/dapi-grpc/clients/drive/v0/web/drive_pb.js index d43136990a8..1373c867d42 100644 --- a/packages/dapi-grpc/clients/drive/v0/web/drive_pb.js +++ b/packages/dapi-grpc/clients/drive/v0/web/drive_pb.js @@ -13,12 +13,12 @@ var jspb = require('google-protobuf'); var goog = jspb; -const proto = {}; +var global = Function('return this')(); -var platform_v0_platform_pb = require('../../../platform/v0/web/platform_pb.js'); +var platform_v0_platform_pb = require('./platform/v0/platform_pb.js'); goog.object.extend(proto, platform_v0_platform_pb); -goog.exportSymbol('proto.org.dash.platform.drive.v0.GetProofsRequest', null, { proto }); -goog.exportSymbol('proto.org.dash.platform.drive.v0.GetProofsResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.drive.v0.GetProofsRequest', null, global); +goog.exportSymbol('proto.org.dash.platform.drive.v0.GetProofsResponse', null, global); /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a diff --git a/packages/dapi-grpc/clients/platform/v0/nodejs/platform_pbjs.js b/packages/dapi-grpc/clients/platform/v0/nodejs/platform_pbjs.js index 58b3dab7793..aa940b9324f 100644 --- a/packages/dapi-grpc/clients/platform/v0/nodejs/platform_pbjs.js +++ b/packages/dapi-grpc/clients/platform/v0/nodejs/platform_pbjs.js @@ -83207,6 +83207,7 @@ $root.org = (function() { * Properties of an EncryptedNote. * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0 * @interface IEncryptedNote + * @property {Uint8Array|null} [nullifier] EncryptedNote nullifier * @property {Uint8Array|null} [cmx] EncryptedNote cmx * @property {Uint8Array|null} [encryptedNote] EncryptedNote encryptedNote */ @@ -83226,6 +83227,14 @@ $root.org = (function() { this[keys[i]] = properties[keys[i]]; } + /** + * EncryptedNote nullifier. + * @member {Uint8Array} nullifier + * @memberof org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote + * @instance + */ + EncryptedNote.prototype.nullifier = $util.newBuffer([]); + /** * EncryptedNote cmx. * @member {Uint8Array} cmx @@ -83266,10 +83275,12 @@ $root.org = (function() { EncryptedNote.encode = function encode(message, writer) { if (!writer) writer = $Writer.create(); + if (message.nullifier != null && Object.hasOwnProperty.call(message, "nullifier")) + writer.uint32(/* id 1, wireType 2 =*/10).bytes(message.nullifier); if (message.cmx != null && Object.hasOwnProperty.call(message, "cmx")) - writer.uint32(/* id 1, wireType 2 =*/10).bytes(message.cmx); + writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.cmx); if (message.encryptedNote != null && Object.hasOwnProperty.call(message, "encryptedNote")) - writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.encryptedNote); + writer.uint32(/* id 3, wireType 2 =*/26).bytes(message.encryptedNote); return writer; }; @@ -83305,9 +83316,12 @@ $root.org = (function() { var tag = reader.uint32(); switch (tag >>> 3) { case 1: - message.cmx = reader.bytes(); + message.nullifier = reader.bytes(); break; case 2: + message.cmx = reader.bytes(); + break; + case 3: message.encryptedNote = reader.bytes(); break; default: @@ -83345,6 +83359,9 @@ $root.org = (function() { EncryptedNote.verify = function verify(message) { if (typeof message !== "object" || message === null) return "object expected"; + if (message.nullifier != null && message.hasOwnProperty("nullifier")) + if (!(message.nullifier && typeof message.nullifier.length === "number" || $util.isString(message.nullifier))) + return "nullifier: buffer expected"; if (message.cmx != null && message.hasOwnProperty("cmx")) if (!(message.cmx && typeof message.cmx.length === "number" || $util.isString(message.cmx))) return "cmx: buffer expected"; @@ -83366,6 +83383,11 @@ $root.org = (function() { if (object instanceof $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote) return object; var message = new $root.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote(); + if (object.nullifier != null) + if (typeof object.nullifier === "string") + $util.base64.decode(object.nullifier, message.nullifier = $util.newBuffer($util.base64.length(object.nullifier)), 0); + else if (object.nullifier.length >= 0) + message.nullifier = object.nullifier; if (object.cmx != null) if (typeof object.cmx === "string") $util.base64.decode(object.cmx, message.cmx = $util.newBuffer($util.base64.length(object.cmx)), 0); @@ -83393,6 +83415,13 @@ $root.org = (function() { options = {}; var object = {}; if (options.defaults) { + if (options.bytes === String) + object.nullifier = ""; + else { + object.nullifier = []; + if (options.bytes !== Array) + object.nullifier = $util.newBuffer(object.nullifier); + } if (options.bytes === String) object.cmx = ""; else { @@ -83408,6 +83437,8 @@ $root.org = (function() { object.encryptedNote = $util.newBuffer(object.encryptedNote); } } + if (message.nullifier != null && message.hasOwnProperty("nullifier")) + object.nullifier = options.bytes === String ? $util.base64.encode(message.nullifier, 0, message.nullifier.length) : options.bytes === Array ? Array.prototype.slice.call(message.nullifier) : message.nullifier; if (message.cmx != null && message.hasOwnProperty("cmx")) object.cmx = options.bytes === String ? $util.base64.encode(message.cmx, 0, message.cmx.length) : options.bytes === Array ? Array.prototype.slice.call(message.cmx) : message.cmx; if (message.encryptedNote != null && message.hasOwnProperty("encryptedNote")) diff --git a/packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js b/packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js index f38425b23af..b3961b34a2e 100644 --- a/packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js +++ b/packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js @@ -80852,6 +80852,7 @@ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEnc */ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.toObject = function(includeInstance, msg) { var f, obj = { + nullifier: msg.getNullifier_asB64(), cmx: msg.getCmx_asB64(), encryptedNote: msg.getEncryptedNote_asB64() }; @@ -80892,9 +80893,13 @@ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEnc switch (field) { case 1: var value = /** @type {!Uint8Array} */ (reader.readBytes()); - msg.setCmx(value); + msg.setNullifier(value); break; case 2: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setCmx(value); + break; + case 3: var value = /** @type {!Uint8Array} */ (reader.readBytes()); msg.setEncryptedNote(value); break; @@ -80927,34 +80932,83 @@ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEnc */ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.serializeBinaryToWriter = function(message, writer) { var f = undefined; - f = message.getCmx_asU8(); + f = message.getNullifier_asU8(); if (f.length > 0) { writer.writeBytes( 1, f ); } - f = message.getEncryptedNote_asU8(); + f = message.getCmx_asU8(); if (f.length > 0) { writer.writeBytes( 2, f ); } + f = message.getEncryptedNote_asU8(); + if (f.length > 0) { + writer.writeBytes( + 3, + f + ); + } }; /** - * optional bytes cmx = 1; + * optional bytes nullifier = 1; * @return {string} */ -proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getCmx = function() { +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getNullifier = function() { return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); }; /** - * optional bytes cmx = 1; + * optional bytes nullifier = 1; + * This is a type-conversion wrapper around `getNullifier()` + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getNullifier_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getNullifier())); +}; + + +/** + * optional bytes nullifier = 1; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getNullifier()` + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getNullifier_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getNullifier())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.setNullifier = function(value) { + return jspb.Message.setProto3BytesField(this, 1, value); +}; + + +/** + * optional bytes cmx = 2; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getCmx = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * optional bytes cmx = 2; * This is a type-conversion wrapper around `getCmx()` * @return {string} */ @@ -80965,7 +81019,7 @@ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEnc /** - * optional bytes cmx = 1; + * optional bytes cmx = 2; * Note that Uint8Array is not supported on all browsers. * @see http://caniuse.com/Uint8Array * This is a type-conversion wrapper around `getCmx()` @@ -80982,21 +81036,21 @@ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEnc * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} returns this */ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.setCmx = function(value) { - return jspb.Message.setProto3BytesField(this, 1, value); + return jspb.Message.setProto3BytesField(this, 2, value); }; /** - * optional bytes encrypted_note = 2; + * optional bytes encrypted_note = 3; * @return {string} */ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getEncryptedNote = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); }; /** - * optional bytes encrypted_note = 2; + * optional bytes encrypted_note = 3; * This is a type-conversion wrapper around `getEncryptedNote()` * @return {string} */ @@ -81007,7 +81061,7 @@ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEnc /** - * optional bytes encrypted_note = 2; + * optional bytes encrypted_note = 3; * Note that Uint8Array is not supported on all browsers. * @see http://caniuse.com/Uint8Array * This is a type-conversion wrapper around `getEncryptedNote()` @@ -81024,7 +81078,7 @@ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEnc * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} returns this */ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.setEncryptedNote = function(value) { - return jspb.Message.setProto3BytesField(this, 2, value); + return jspb.Message.setProto3BytesField(this, 3, value); }; diff --git a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h index 45b217f446f..e24b1dbd7cf 100644 --- a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h +++ b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h @@ -8663,14 +8663,20 @@ void GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_Clear #pragma mark - GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote typedef GPB_ENUM(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote_FieldNumber) { - GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote_FieldNumber_Cmx = 1, - GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote_FieldNumber_EncryptedNote = 2, + GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote_FieldNumber_Nullifier = 1, + GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote_FieldNumber_Cmx = 2, + GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote_FieldNumber_EncryptedNote = 3, }; GPB_FINAL @interface GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote : GPBMessage +/** 32-byte nullifier (needed for Rho derivation in trial decryption) */ +@property(nonatomic, readwrite, copy, null_resettable) NSData *nullifier; + +/** 32-byte extracted note commitment */ @property(nonatomic, readwrite, copy, null_resettable) NSData *cmx; +/** encrypted note payload (epk + enc_ciphertext + out_ciphertext) */ @property(nonatomic, readwrite, copy, null_resettable) NSData *encryptedNote; @end diff --git a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m index 8ff1491b2a4..8fa10b4b980 100644 --- a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m +++ b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m @@ -22550,11 +22550,13 @@ void GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_Clear @implementation GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote +@dynamic nullifier; @dynamic cmx; @dynamic encryptedNote; typedef struct GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote__storage_ { uint32_t _has_storage_[1]; + NSData *nullifier; NSData *cmx; NSData *encryptedNote; } GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote__storage_; @@ -22565,11 +22567,20 @@ + (GPBDescriptor *)descriptor { static GPBDescriptor *descriptor = nil; if (!descriptor) { static GPBMessageFieldDescription fields[] = { + { + .name = "nullifier", + .dataTypeSpecific.clazz = Nil, + .number = GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote_FieldNumber_Nullifier, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote__storage_, nullifier), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeBytes, + }, { .name = "cmx", .dataTypeSpecific.clazz = Nil, .number = GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote_FieldNumber_Cmx, - .hasIndex = 0, + .hasIndex = 1, .offset = (uint32_t)offsetof(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote__storage_, cmx), .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), .dataType = GPBDataTypeBytes, @@ -22578,7 +22589,7 @@ + (GPBDescriptor *)descriptor { .name = "encryptedNote", .dataTypeSpecific.clazz = Nil, .number = GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote_FieldNumber_EncryptedNote, - .hasIndex = 1, + .hasIndex = 2, .offset = (uint32_t)offsetof(GetShieldedEncryptedNotesResponse_GetShieldedEncryptedNotesResponseV0_EncryptedNote__storage_, encryptedNote), .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), .dataType = GPBDataTypeBytes, diff --git a/packages/dapi-grpc/clients/platform/v0/python/platform_pb2.py b/packages/dapi-grpc/clients/platform/v0/python/platform_pb2.py index 0b00b057655..bf369b20a0c 100644 --- a/packages/dapi-grpc/clients/platform/v0/python/platform_pb2.py +++ b/packages/dapi-grpc/clients/platform/v0/python/platform_pb2.py @@ -23,7 +23,7 @@ syntax='proto3', serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x0eplatform.proto\x12\x19org.dash.platform.dapi.v0\x1a\x1egoogle/protobuf/wrappers.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x81\x01\n\x05Proof\x12\x15\n\rgrovedb_proof\x18\x01 \x01(\x0c\x12\x13\n\x0bquorum_hash\x18\x02 \x01(\x0c\x12\x11\n\tsignature\x18\x03 \x01(\x0c\x12\r\n\x05round\x18\x04 \x01(\r\x12\x15\n\rblock_id_hash\x18\x05 \x01(\x0c\x12\x13\n\x0bquorum_type\x18\x06 \x01(\r\"\x98\x01\n\x10ResponseMetadata\x12\x12\n\x06height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12 \n\x18\x63ore_chain_locked_height\x18\x02 \x01(\r\x12\r\n\x05\x65poch\x18\x03 \x01(\r\x12\x13\n\x07time_ms\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x18\n\x10protocol_version\x18\x05 \x01(\r\x12\x10\n\x08\x63hain_id\x18\x06 \x01(\t\"L\n\x1dStateTransitionBroadcastError\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\";\n\x1f\x42roadcastStateTransitionRequest\x12\x18\n\x10state_transition\x18\x01 \x01(\x0c\"\"\n BroadcastStateTransitionResponse\"\xa4\x01\n\x12GetIdentityRequest\x12P\n\x02v0\x18\x01 \x01(\x0b\x32\x42.org.dash.platform.dapi.v0.GetIdentityRequest.GetIdentityRequestV0H\x00\x1a\x31\n\x14GetIdentityRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xc1\x01\n\x17GetIdentityNonceRequest\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetIdentityNonceRequest.GetIdentityNonceRequestV0H\x00\x1a?\n\x19GetIdentityNonceRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xf6\x01\n\x1fGetIdentityContractNonceRequest\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetIdentityContractNonceRequest.GetIdentityContractNonceRequestV0H\x00\x1a\\\n!GetIdentityContractNonceRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x13\n\x0b\x63ontract_id\x18\x02 \x01(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xc0\x01\n\x19GetIdentityBalanceRequest\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetIdentityBalanceRequest.GetIdentityBalanceRequestV0H\x00\x1a\x38\n\x1bGetIdentityBalanceRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xec\x01\n$GetIdentityBalanceAndRevisionRequest\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionRequest.GetIdentityBalanceAndRevisionRequestV0H\x00\x1a\x43\n&GetIdentityBalanceAndRevisionRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x9e\x02\n\x13GetIdentityResponse\x12R\n\x02v0\x18\x01 \x01(\x0b\x32\x44.org.dash.platform.dapi.v0.GetIdentityResponse.GetIdentityResponseV0H\x00\x1a\xa7\x01\n\x15GetIdentityResponseV0\x12\x12\n\x08identity\x18\x01 \x01(\x0cH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xbc\x02\n\x18GetIdentityNonceResponse\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetIdentityNonceResponse.GetIdentityNonceResponseV0H\x00\x1a\xb6\x01\n\x1aGetIdentityNonceResponseV0\x12\x1c\n\x0eidentity_nonce\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xe5\x02\n GetIdentityContractNonceResponse\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetIdentityContractNonceResponse.GetIdentityContractNonceResponseV0H\x00\x1a\xc7\x01\n\"GetIdentityContractNonceResponseV0\x12%\n\x17identity_contract_nonce\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xbd\x02\n\x1aGetIdentityBalanceResponse\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetIdentityBalanceResponse.GetIdentityBalanceResponseV0H\x00\x1a\xb1\x01\n\x1cGetIdentityBalanceResponseV0\x12\x15\n\x07\x62\x61lance\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xb1\x04\n%GetIdentityBalanceAndRevisionResponse\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionResponse.GetIdentityBalanceAndRevisionResponseV0H\x00\x1a\x84\x03\n\'GetIdentityBalanceAndRevisionResponseV0\x12\x9b\x01\n\x14\x62\x61lance_and_revision\x18\x01 \x01(\x0b\x32{.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionResponse.GetIdentityBalanceAndRevisionResponseV0.BalanceAndRevisionH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a?\n\x12\x42\x61lanceAndRevision\x12\x13\n\x07\x62\x61lance\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x14\n\x08revision\x18\x02 \x01(\x04\x42\x02\x30\x01\x42\x08\n\x06resultB\t\n\x07version\"\xd1\x01\n\x0eKeyRequestType\x12\x36\n\x08\x61ll_keys\x18\x01 \x01(\x0b\x32\".org.dash.platform.dapi.v0.AllKeysH\x00\x12@\n\rspecific_keys\x18\x02 \x01(\x0b\x32\'.org.dash.platform.dapi.v0.SpecificKeysH\x00\x12:\n\nsearch_key\x18\x03 \x01(\x0b\x32$.org.dash.platform.dapi.v0.SearchKeyH\x00\x42\t\n\x07request\"\t\n\x07\x41llKeys\"\x1f\n\x0cSpecificKeys\x12\x0f\n\x07key_ids\x18\x01 \x03(\r\"\xb6\x01\n\tSearchKey\x12I\n\x0bpurpose_map\x18\x01 \x03(\x0b\x32\x34.org.dash.platform.dapi.v0.SearchKey.PurposeMapEntry\x1a^\n\x0fPurposeMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12:\n\x05value\x18\x02 \x01(\x0b\x32+.org.dash.platform.dapi.v0.SecurityLevelMap:\x02\x38\x01\"\xbf\x02\n\x10SecurityLevelMap\x12]\n\x12security_level_map\x18\x01 \x03(\x0b\x32\x41.org.dash.platform.dapi.v0.SecurityLevelMap.SecurityLevelMapEntry\x1aw\n\x15SecurityLevelMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12M\n\x05value\x18\x02 \x01(\x0e\x32>.org.dash.platform.dapi.v0.SecurityLevelMap.KeyKindRequestType:\x02\x38\x01\"S\n\x12KeyKindRequestType\x12\x1f\n\x1b\x43URRENT_KEY_OF_KIND_REQUEST\x10\x00\x12\x1c\n\x18\x41LL_KEYS_OF_KIND_REQUEST\x10\x01\"\xda\x02\n\x16GetIdentityKeysRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetIdentityKeysRequest.GetIdentityKeysRequestV0H\x00\x1a\xda\x01\n\x18GetIdentityKeysRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12?\n\x0crequest_type\x18\x02 \x01(\x0b\x32).org.dash.platform.dapi.v0.KeyRequestType\x12+\n\x05limit\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12,\n\x06offset\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\t\n\x07version\"\x99\x03\n\x17GetIdentityKeysResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetIdentityKeysResponse.GetIdentityKeysResponseV0H\x00\x1a\x96\x02\n\x19GetIdentityKeysResponseV0\x12\x61\n\x04keys\x18\x01 \x01(\x0b\x32Q.org.dash.platform.dapi.v0.GetIdentityKeysResponse.GetIdentityKeysResponseV0.KeysH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1a\n\x04Keys\x12\x12\n\nkeys_bytes\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xef\x02\n GetIdentitiesContractKeysRequest\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetIdentitiesContractKeysRequest.GetIdentitiesContractKeysRequestV0H\x00\x1a\xd1\x01\n\"GetIdentitiesContractKeysRequestV0\x12\x16\n\x0eidentities_ids\x18\x01 \x03(\x0c\x12\x13\n\x0b\x63ontract_id\x18\x02 \x01(\x0c\x12\x1f\n\x12\x64ocument_type_name\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x37\n\x08purposes\x18\x04 \x03(\x0e\x32%.org.dash.platform.dapi.v0.KeyPurpose\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\x15\n\x13_document_type_nameB\t\n\x07version\"\xdf\x06\n!GetIdentitiesContractKeysResponse\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0H\x00\x1a\xbe\x05\n#GetIdentitiesContractKeysResponseV0\x12\x8a\x01\n\x0fidentities_keys\x18\x01 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0.IdentitiesKeysH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aY\n\x0bPurposeKeys\x12\x36\n\x07purpose\x18\x01 \x01(\x0e\x32%.org.dash.platform.dapi.v0.KeyPurpose\x12\x12\n\nkeys_bytes\x18\x02 \x03(\x0c\x1a\x9f\x01\n\x0cIdentityKeys\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12z\n\x04keys\x18\x02 \x03(\x0b\x32l.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0.PurposeKeys\x1a\x90\x01\n\x0eIdentitiesKeys\x12~\n\x07\x65ntries\x18\x01 \x03(\x0b\x32m.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0.IdentityKeysB\x08\n\x06resultB\t\n\x07version\"\xa4\x02\n*GetEvonodesProposedEpochBlocksByIdsRequest\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByIdsRequest.GetEvonodesProposedEpochBlocksByIdsRequestV0H\x00\x1ah\n,GetEvonodesProposedEpochBlocksByIdsRequestV0\x12\x12\n\x05\x65poch\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x0b\n\x03ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\x08\n\x06_epochB\t\n\x07version\"\x92\x06\n&GetEvonodesProposedEpochBlocksResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse.GetEvonodesProposedEpochBlocksResponseV0H\x00\x1a\xe2\x04\n(GetEvonodesProposedEpochBlocksResponseV0\x12\xb1\x01\n#evonodes_proposed_block_counts_info\x18\x01 \x01(\x0b\x32\x81\x01.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse.GetEvonodesProposedEpochBlocksResponseV0.EvonodesProposedBlocksH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a?\n\x15\x45vonodeProposedBlocks\x12\x13\n\x0bpro_tx_hash\x18\x01 \x01(\x0c\x12\x11\n\x05\x63ount\x18\x02 \x01(\x04\x42\x02\x30\x01\x1a\xc4\x01\n\x16\x45vonodesProposedBlocks\x12\xa9\x01\n\x1e\x65vonodes_proposed_block_counts\x18\x01 \x03(\x0b\x32\x80\x01.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse.GetEvonodesProposedEpochBlocksResponseV0.EvonodeProposedBlocksB\x08\n\x06resultB\t\n\x07version\"\xf2\x02\n,GetEvonodesProposedEpochBlocksByRangeRequest\x12\x84\x01\n\x02v0\x18\x01 \x01(\x0b\x32v.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByRangeRequest.GetEvonodesProposedEpochBlocksByRangeRequestV0H\x00\x1a\xaf\x01\n.GetEvonodesProposedEpochBlocksByRangeRequestV0\x12\x12\n\x05\x65poch\x18\x01 \x01(\rH\x01\x88\x01\x01\x12\x12\n\x05limit\x18\x02 \x01(\rH\x02\x88\x01\x01\x12\x15\n\x0bstart_after\x18\x03 \x01(\x0cH\x00\x12\x12\n\x08start_at\x18\x04 \x01(\x0cH\x00\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\x07\n\x05startB\x08\n\x06_epochB\x08\n\x06_limitB\t\n\x07version\"\xcd\x01\n\x1cGetIdentitiesBalancesRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetIdentitiesBalancesRequest.GetIdentitiesBalancesRequestV0H\x00\x1a<\n\x1eGetIdentitiesBalancesRequestV0\x12\x0b\n\x03ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x9f\x05\n\x1dGetIdentitiesBalancesResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse.GetIdentitiesBalancesResponseV0H\x00\x1a\x8a\x04\n\x1fGetIdentitiesBalancesResponseV0\x12\x8a\x01\n\x13identities_balances\x18\x01 \x01(\x0b\x32k.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse.GetIdentitiesBalancesResponseV0.IdentitiesBalancesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aL\n\x0fIdentityBalance\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x18\n\x07\x62\x61lance\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x88\x01\x01\x42\n\n\x08_balance\x1a\x8f\x01\n\x12IdentitiesBalances\x12y\n\x07\x65ntries\x18\x01 \x03(\x0b\x32h.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse.GetIdentitiesBalancesResponseV0.IdentityBalanceB\x08\n\x06resultB\t\n\x07version\"\xb4\x01\n\x16GetDataContractRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetDataContractRequest.GetDataContractRequestV0H\x00\x1a\x35\n\x18GetDataContractRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xb3\x02\n\x17GetDataContractResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetDataContractResponse.GetDataContractResponseV0H\x00\x1a\xb0\x01\n\x19GetDataContractResponseV0\x12\x17\n\rdata_contract\x18\x01 \x01(\x0cH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xb9\x01\n\x17GetDataContractsRequest\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetDataContractsRequest.GetDataContractsRequestV0H\x00\x1a\x37\n\x19GetDataContractsRequestV0\x12\x0b\n\x03ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xcf\x04\n\x18GetDataContractsResponse\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetDataContractsResponse.GetDataContractsResponseV0H\x00\x1a[\n\x11\x44\x61taContractEntry\x12\x12\n\nidentifier\x18\x01 \x01(\x0c\x12\x32\n\rdata_contract\x18\x02 \x01(\x0b\x32\x1b.google.protobuf.BytesValue\x1au\n\rDataContracts\x12\x64\n\x15\x64\x61ta_contract_entries\x18\x01 \x03(\x0b\x32\x45.org.dash.platform.dapi.v0.GetDataContractsResponse.DataContractEntry\x1a\xf5\x01\n\x1aGetDataContractsResponseV0\x12[\n\x0e\x64\x61ta_contracts\x18\x01 \x01(\x0b\x32\x41.org.dash.platform.dapi.v0.GetDataContractsResponse.DataContractsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc5\x02\n\x1dGetDataContractHistoryRequest\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetDataContractHistoryRequest.GetDataContractHistoryRequestV0H\x00\x1a\xb0\x01\n\x1fGetDataContractHistoryRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12+\n\x05limit\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12,\n\x06offset\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\x17\n\x0bstart_at_ms\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\t\n\x07version\"\xb2\x05\n\x1eGetDataContractHistoryResponse\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetDataContractHistoryResponse.GetDataContractHistoryResponseV0H\x00\x1a\x9a\x04\n GetDataContractHistoryResponseV0\x12\x8f\x01\n\x15\x64\x61ta_contract_history\x18\x01 \x01(\x0b\x32n.org.dash.platform.dapi.v0.GetDataContractHistoryResponse.GetDataContractHistoryResponseV0.DataContractHistoryH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a;\n\x18\x44\x61taContractHistoryEntry\x12\x10\n\x04\x64\x61te\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05value\x18\x02 \x01(\x0c\x1a\xaa\x01\n\x13\x44\x61taContractHistory\x12\x92\x01\n\x15\x64\x61ta_contract_entries\x18\x01 \x03(\x0b\x32s.org.dash.platform.dapi.v0.GetDataContractHistoryResponse.GetDataContractHistoryResponseV0.DataContractHistoryEntryB\x08\n\x06resultB\t\n\x07version\"\xb2\x02\n\x13GetDocumentsRequest\x12R\n\x02v0\x18\x01 \x01(\x0b\x32\x44.org.dash.platform.dapi.v0.GetDocumentsRequest.GetDocumentsRequestV0H\x00\x1a\xbb\x01\n\x15GetDocumentsRequestV0\x12\x18\n\x10\x64\x61ta_contract_id\x18\x01 \x01(\x0c\x12\x15\n\rdocument_type\x18\x02 \x01(\t\x12\r\n\x05where\x18\x03 \x01(\x0c\x12\x10\n\x08order_by\x18\x04 \x01(\x0c\x12\r\n\x05limit\x18\x05 \x01(\r\x12\x15\n\x0bstart_after\x18\x06 \x01(\x0cH\x00\x12\x12\n\x08start_at\x18\x07 \x01(\x0cH\x00\x12\r\n\x05prove\x18\x08 \x01(\x08\x42\x07\n\x05startB\t\n\x07version\"\x95\x03\n\x14GetDocumentsResponse\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetDocumentsResponse.GetDocumentsResponseV0H\x00\x1a\x9b\x02\n\x16GetDocumentsResponseV0\x12\x65\n\tdocuments\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetDocumentsResponse.GetDocumentsResponseV0.DocumentsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1e\n\tDocuments\x12\x11\n\tdocuments\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xed\x01\n!GetIdentityByPublicKeyHashRequest\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashRequest.GetIdentityByPublicKeyHashRequestV0H\x00\x1aM\n#GetIdentityByPublicKeyHashRequestV0\x12\x17\n\x0fpublic_key_hash\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xda\x02\n\"GetIdentityByPublicKeyHashResponse\x12p\n\x02v0\x18\x01 \x01(\x0b\x32\x62.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashResponse.GetIdentityByPublicKeyHashResponseV0H\x00\x1a\xb6\x01\n$GetIdentityByPublicKeyHashResponseV0\x12\x12\n\x08identity\x18\x01 \x01(\x0cH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xbd\x02\n*GetIdentityByNonUniquePublicKeyHashRequest\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashRequest.GetIdentityByNonUniquePublicKeyHashRequestV0H\x00\x1a\x80\x01\n,GetIdentityByNonUniquePublicKeyHashRequestV0\x12\x17\n\x0fpublic_key_hash\x18\x01 \x01(\x0c\x12\x18\n\x0bstart_after\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\x0e\n\x0c_start_afterB\t\n\x07version\"\xd6\x06\n+GetIdentityByNonUniquePublicKeyHashResponse\x12\x82\x01\n\x02v0\x18\x01 \x01(\x0b\x32t.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse.GetIdentityByNonUniquePublicKeyHashResponseV0H\x00\x1a\x96\x05\n-GetIdentityByNonUniquePublicKeyHashResponseV0\x12\x9a\x01\n\x08identity\x18\x01 \x01(\x0b\x32\x85\x01.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse.GetIdentityByNonUniquePublicKeyHashResponseV0.IdentityResponseH\x00\x12\x9d\x01\n\x05proof\x18\x02 \x01(\x0b\x32\x8b\x01.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse.GetIdentityByNonUniquePublicKeyHashResponseV0.IdentityProvedResponseH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x36\n\x10IdentityResponse\x12\x15\n\x08identity\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\x0b\n\t_identity\x1a\xa6\x01\n\x16IdentityProvedResponse\x12P\n&grovedb_identity_public_key_hash_proof\x18\x01 \x01(\x0b\x32 .org.dash.platform.dapi.v0.Proof\x12!\n\x14identity_proof_bytes\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x42\x17\n\x15_identity_proof_bytesB\x08\n\x06resultB\t\n\x07version\"\xfb\x01\n#WaitForStateTransitionResultRequest\x12r\n\x02v0\x18\x01 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.WaitForStateTransitionResultRequest.WaitForStateTransitionResultRequestV0H\x00\x1aU\n%WaitForStateTransitionResultRequestV0\x12\x1d\n\x15state_transition_hash\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x99\x03\n$WaitForStateTransitionResultResponse\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.WaitForStateTransitionResultResponse.WaitForStateTransitionResultResponseV0H\x00\x1a\xef\x01\n&WaitForStateTransitionResultResponseV0\x12I\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x38.org.dash.platform.dapi.v0.StateTransitionBroadcastErrorH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc4\x01\n\x19GetConsensusParamsRequest\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetConsensusParamsRequest.GetConsensusParamsRequestV0H\x00\x1a<\n\x1bGetConsensusParamsRequestV0\x12\x0e\n\x06height\x18\x01 \x01(\x05\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x9c\x04\n\x1aGetConsensusParamsResponse\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetConsensusParamsResponse.GetConsensusParamsResponseV0H\x00\x1aP\n\x14\x43onsensusParamsBlock\x12\x11\n\tmax_bytes\x18\x01 \x01(\t\x12\x0f\n\x07max_gas\x18\x02 \x01(\t\x12\x14\n\x0ctime_iota_ms\x18\x03 \x01(\t\x1a\x62\n\x17\x43onsensusParamsEvidence\x12\x1a\n\x12max_age_num_blocks\x18\x01 \x01(\t\x12\x18\n\x10max_age_duration\x18\x02 \x01(\t\x12\x11\n\tmax_bytes\x18\x03 \x01(\t\x1a\xda\x01\n\x1cGetConsensusParamsResponseV0\x12Y\n\x05\x62lock\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetConsensusParamsResponse.ConsensusParamsBlock\x12_\n\x08\x65vidence\x18\x02 \x01(\x0b\x32M.org.dash.platform.dapi.v0.GetConsensusParamsResponse.ConsensusParamsEvidenceB\t\n\x07version\"\xe4\x01\n%GetProtocolVersionUpgradeStateRequest\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateRequest.GetProtocolVersionUpgradeStateRequestV0H\x00\x1a\x38\n\'GetProtocolVersionUpgradeStateRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xb5\x05\n&GetProtocolVersionUpgradeStateResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse.GetProtocolVersionUpgradeStateResponseV0H\x00\x1a\x85\x04\n(GetProtocolVersionUpgradeStateResponseV0\x12\x87\x01\n\x08versions\x18\x01 \x01(\x0b\x32s.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse.GetProtocolVersionUpgradeStateResponseV0.VersionsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x96\x01\n\x08Versions\x12\x89\x01\n\x08versions\x18\x01 \x03(\x0b\x32w.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse.GetProtocolVersionUpgradeStateResponseV0.VersionEntry\x1a:\n\x0cVersionEntry\x12\x16\n\x0eversion_number\x18\x01 \x01(\r\x12\x12\n\nvote_count\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xa3\x02\n*GetProtocolVersionUpgradeVoteStatusRequest\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusRequest.GetProtocolVersionUpgradeVoteStatusRequestV0H\x00\x1ag\n,GetProtocolVersionUpgradeVoteStatusRequestV0\x12\x19\n\x11start_pro_tx_hash\x18\x01 \x01(\x0c\x12\r\n\x05\x63ount\x18\x02 \x01(\r\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xef\x05\n+GetProtocolVersionUpgradeVoteStatusResponse\x12\x82\x01\n\x02v0\x18\x01 \x01(\x0b\x32t.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse.GetProtocolVersionUpgradeVoteStatusResponseV0H\x00\x1a\xaf\x04\n-GetProtocolVersionUpgradeVoteStatusResponseV0\x12\x98\x01\n\x08versions\x18\x01 \x01(\x0b\x32\x83\x01.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse.GetProtocolVersionUpgradeVoteStatusResponseV0.VersionSignalsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xaf\x01\n\x0eVersionSignals\x12\x9c\x01\n\x0fversion_signals\x18\x01 \x03(\x0b\x32\x82\x01.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse.GetProtocolVersionUpgradeVoteStatusResponseV0.VersionSignal\x1a\x35\n\rVersionSignal\x12\x13\n\x0bpro_tx_hash\x18\x01 \x01(\x0c\x12\x0f\n\x07version\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xf5\x01\n\x14GetEpochsInfoRequest\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetEpochsInfoRequest.GetEpochsInfoRequestV0H\x00\x1a|\n\x16GetEpochsInfoRequestV0\x12\x31\n\x0bstart_epoch\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\r\n\x05\x63ount\x18\x02 \x01(\r\x12\x11\n\tascending\x18\x03 \x01(\x08\x12\r\n\x05prove\x18\x04 \x01(\x08\x42\t\n\x07version\"\x99\x05\n\x15GetEpochsInfoResponse\x12V\n\x02v0\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetEpochsInfoResponse.GetEpochsInfoResponseV0H\x00\x1a\x9c\x04\n\x17GetEpochsInfoResponseV0\x12\x65\n\x06\x65pochs\x18\x01 \x01(\x0b\x32S.org.dash.platform.dapi.v0.GetEpochsInfoResponse.GetEpochsInfoResponseV0.EpochInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1au\n\nEpochInfos\x12g\n\x0b\x65poch_infos\x18\x01 \x03(\x0b\x32R.org.dash.platform.dapi.v0.GetEpochsInfoResponse.GetEpochsInfoResponseV0.EpochInfo\x1a\xa6\x01\n\tEpochInfo\x12\x0e\n\x06number\x18\x01 \x01(\r\x12\x1e\n\x12\x66irst_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x1f\n\x17\x66irst_core_block_height\x18\x03 \x01(\r\x12\x16\n\nstart_time\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x16\n\x0e\x66\x65\x65_multiplier\x18\x05 \x01(\x01\x12\x18\n\x10protocol_version\x18\x06 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xbf\x02\n\x1dGetFinalizedEpochInfosRequest\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetFinalizedEpochInfosRequest.GetFinalizedEpochInfosRequestV0H\x00\x1a\xaa\x01\n\x1fGetFinalizedEpochInfosRequestV0\x12\x19\n\x11start_epoch_index\x18\x01 \x01(\r\x12\"\n\x1astart_epoch_index_included\x18\x02 \x01(\x08\x12\x17\n\x0f\x65nd_epoch_index\x18\x03 \x01(\r\x12 \n\x18\x65nd_epoch_index_included\x18\x04 \x01(\x08\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\t\n\x07version\"\xbd\t\n\x1eGetFinalizedEpochInfosResponse\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0H\x00\x1a\xa5\x08\n GetFinalizedEpochInfosResponseV0\x12\x80\x01\n\x06\x65pochs\x18\x01 \x01(\x0b\x32n.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0.FinalizedEpochInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xa4\x01\n\x13\x46inalizedEpochInfos\x12\x8c\x01\n\x15\x66inalized_epoch_infos\x18\x01 \x03(\x0b\x32m.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0.FinalizedEpochInfo\x1a\x9f\x04\n\x12\x46inalizedEpochInfo\x12\x0e\n\x06number\x18\x01 \x01(\r\x12\x1e\n\x12\x66irst_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x1f\n\x17\x66irst_core_block_height\x18\x03 \x01(\r\x12\x1c\n\x10\x66irst_block_time\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x16\n\x0e\x66\x65\x65_multiplier\x18\x05 \x01(\x01\x12\x18\n\x10protocol_version\x18\x06 \x01(\r\x12!\n\x15total_blocks_in_epoch\x18\x07 \x01(\x04\x42\x02\x30\x01\x12*\n\"next_epoch_start_core_block_height\x18\x08 \x01(\r\x12!\n\x15total_processing_fees\x18\t \x01(\x04\x42\x02\x30\x01\x12*\n\x1etotal_distributed_storage_fees\x18\n \x01(\x04\x42\x02\x30\x01\x12&\n\x1atotal_created_storage_fees\x18\x0b \x01(\x04\x42\x02\x30\x01\x12\x1e\n\x12\x63ore_block_rewards\x18\x0c \x01(\x04\x42\x02\x30\x01\x12\x81\x01\n\x0f\x62lock_proposers\x18\r \x03(\x0b\x32h.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0.BlockProposer\x1a\x39\n\rBlockProposer\x12\x13\n\x0bproposer_id\x18\x01 \x01(\x0c\x12\x13\n\x0b\x62lock_count\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xde\x04\n\x1cGetContestedResourcesRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetContestedResourcesRequest.GetContestedResourcesRequestV0H\x00\x1a\xcc\x03\n\x1eGetContestedResourcesRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\x12\n\nindex_name\x18\x03 \x01(\t\x12\x1a\n\x12start_index_values\x18\x04 \x03(\x0c\x12\x18\n\x10\x65nd_index_values\x18\x05 \x03(\x0c\x12\x89\x01\n\x13start_at_value_info\x18\x06 \x01(\x0b\x32g.org.dash.platform.dapi.v0.GetContestedResourcesRequest.GetContestedResourcesRequestV0.StartAtValueInfoH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x07 \x01(\rH\x01\x88\x01\x01\x12\x17\n\x0forder_ascending\x18\x08 \x01(\x08\x12\r\n\x05prove\x18\t \x01(\x08\x1a\x45\n\x10StartAtValueInfo\x12\x13\n\x0bstart_value\x18\x01 \x01(\x0c\x12\x1c\n\x14start_value_included\x18\x02 \x01(\x08\x42\x16\n\x14_start_at_value_infoB\x08\n\x06_countB\t\n\x07version\"\x88\x04\n\x1dGetContestedResourcesResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetContestedResourcesResponse.GetContestedResourcesResponseV0H\x00\x1a\xf3\x02\n\x1fGetContestedResourcesResponseV0\x12\x95\x01\n\x19\x63ontested_resource_values\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetContestedResourcesResponse.GetContestedResourcesResponseV0.ContestedResourceValuesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a<\n\x17\x43ontestedResourceValues\x12!\n\x19\x63ontested_resource_values\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xd2\x05\n\x1cGetVotePollsByEndDateRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest.GetVotePollsByEndDateRequestV0H\x00\x1a\xc0\x04\n\x1eGetVotePollsByEndDateRequestV0\x12\x84\x01\n\x0fstart_time_info\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest.GetVotePollsByEndDateRequestV0.StartAtTimeInfoH\x00\x88\x01\x01\x12\x80\x01\n\rend_time_info\x18\x02 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest.GetVotePollsByEndDateRequestV0.EndAtTimeInfoH\x01\x88\x01\x01\x12\x12\n\x05limit\x18\x03 \x01(\rH\x02\x88\x01\x01\x12\x13\n\x06offset\x18\x04 \x01(\rH\x03\x88\x01\x01\x12\x11\n\tascending\x18\x05 \x01(\x08\x12\r\n\x05prove\x18\x06 \x01(\x08\x1aI\n\x0fStartAtTimeInfo\x12\x19\n\rstart_time_ms\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1b\n\x13start_time_included\x18\x02 \x01(\x08\x1a\x43\n\rEndAtTimeInfo\x12\x17\n\x0b\x65nd_time_ms\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x19\n\x11\x65nd_time_included\x18\x02 \x01(\x08\x42\x12\n\x10_start_time_infoB\x10\n\x0e_end_time_infoB\x08\n\x06_limitB\t\n\x07_offsetB\t\n\x07version\"\x83\x06\n\x1dGetVotePollsByEndDateResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse.GetVotePollsByEndDateResponseV0H\x00\x1a\xee\x04\n\x1fGetVotePollsByEndDateResponseV0\x12\x9c\x01\n\x18vote_polls_by_timestamps\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse.GetVotePollsByEndDateResponseV0.SerializedVotePollsByTimestampsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aV\n\x1eSerializedVotePollsByTimestamp\x12\x15\n\ttimestamp\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1d\n\x15serialized_vote_polls\x18\x02 \x03(\x0c\x1a\xd7\x01\n\x1fSerializedVotePollsByTimestamps\x12\x99\x01\n\x18vote_polls_by_timestamps\x18\x01 \x03(\x0b\x32w.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse.GetVotePollsByEndDateResponseV0.SerializedVotePollsByTimestamp\x12\x18\n\x10\x66inished_results\x18\x02 \x01(\x08\x42\x08\n\x06resultB\t\n\x07version\"\xff\x06\n$GetContestedResourceVoteStateRequest\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest.GetContestedResourceVoteStateRequestV0H\x00\x1a\xd5\x05\n&GetContestedResourceVoteStateRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\x12\n\nindex_name\x18\x03 \x01(\t\x12\x14\n\x0cindex_values\x18\x04 \x03(\x0c\x12\x86\x01\n\x0bresult_type\x18\x05 \x01(\x0e\x32q.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest.GetContestedResourceVoteStateRequestV0.ResultType\x12\x36\n.allow_include_locked_and_abstaining_vote_tally\x18\x06 \x01(\x08\x12\xa3\x01\n\x18start_at_identifier_info\x18\x07 \x01(\x0b\x32|.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest.GetContestedResourceVoteStateRequestV0.StartAtIdentifierInfoH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x08 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\t \x01(\x08\x1aT\n\x15StartAtIdentifierInfo\x12\x18\n\x10start_identifier\x18\x01 \x01(\x0c\x12!\n\x19start_identifier_included\x18\x02 \x01(\x08\"I\n\nResultType\x12\r\n\tDOCUMENTS\x10\x00\x12\x0e\n\nVOTE_TALLY\x10\x01\x12\x1c\n\x18\x44OCUMENTS_AND_VOTE_TALLY\x10\x02\x42\x1b\n\x19_start_at_identifier_infoB\x08\n\x06_countB\t\n\x07version\"\x94\x0c\n%GetContestedResourceVoteStateResponse\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0H\x00\x1a\xe7\n\n\'GetContestedResourceVoteStateResponseV0\x12\xae\x01\n\x1d\x63ontested_resource_contenders\x18\x01 \x01(\x0b\x32\x84\x01.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.ContestedResourceContendersH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xda\x03\n\x10\x46inishedVoteInfo\x12\xad\x01\n\x15\x66inished_vote_outcome\x18\x01 \x01(\x0e\x32\x8d\x01.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.FinishedVoteInfo.FinishedVoteOutcome\x12\x1f\n\x12won_by_identity_id\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12$\n\x18\x66inished_at_block_height\x18\x03 \x01(\x04\x42\x02\x30\x01\x12%\n\x1d\x66inished_at_core_block_height\x18\x04 \x01(\r\x12%\n\x19\x66inished_at_block_time_ms\x18\x05 \x01(\x04\x42\x02\x30\x01\x12\x19\n\x11\x66inished_at_epoch\x18\x06 \x01(\r\"O\n\x13\x46inishedVoteOutcome\x12\x14\n\x10TOWARDS_IDENTITY\x10\x00\x12\n\n\x06LOCKED\x10\x01\x12\x16\n\x12NO_PREVIOUS_WINNER\x10\x02\x42\x15\n\x13_won_by_identity_id\x1a\xc4\x03\n\x1b\x43ontestedResourceContenders\x12\x86\x01\n\ncontenders\x18\x01 \x03(\x0b\x32r.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.Contender\x12\x1f\n\x12\x61\x62stain_vote_tally\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x1c\n\x0flock_vote_tally\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x9a\x01\n\x12\x66inished_vote_info\x18\x04 \x01(\x0b\x32y.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.FinishedVoteInfoH\x02\x88\x01\x01\x42\x15\n\x13_abstain_vote_tallyB\x12\n\x10_lock_vote_tallyB\x15\n\x13_finished_vote_info\x1ak\n\tContender\x12\x12\n\nidentifier\x18\x01 \x01(\x0c\x12\x17\n\nvote_count\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x15\n\x08\x64ocument\x18\x03 \x01(\x0cH\x01\x88\x01\x01\x42\r\n\x0b_vote_countB\x0b\n\t_documentB\x08\n\x06resultB\t\n\x07version\"\xd5\x05\n,GetContestedResourceVotersForIdentityRequest\x12\x84\x01\n\x02v0\x18\x01 \x01(\x0b\x32v.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityRequest.GetContestedResourceVotersForIdentityRequestV0H\x00\x1a\x92\x04\n.GetContestedResourceVotersForIdentityRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\x12\n\nindex_name\x18\x03 \x01(\t\x12\x14\n\x0cindex_values\x18\x04 \x03(\x0c\x12\x15\n\rcontestant_id\x18\x05 \x01(\x0c\x12\xb4\x01\n\x18start_at_identifier_info\x18\x06 \x01(\x0b\x32\x8c\x01.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityRequest.GetContestedResourceVotersForIdentityRequestV0.StartAtIdentifierInfoH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x07 \x01(\rH\x01\x88\x01\x01\x12\x17\n\x0forder_ascending\x18\x08 \x01(\x08\x12\r\n\x05prove\x18\t \x01(\x08\x1aT\n\x15StartAtIdentifierInfo\x12\x18\n\x10start_identifier\x18\x01 \x01(\x0c\x12!\n\x19start_identifier_included\x18\x02 \x01(\x08\x42\x1b\n\x19_start_at_identifier_infoB\x08\n\x06_countB\t\n\x07version\"\xf1\x04\n-GetContestedResourceVotersForIdentityResponse\x12\x86\x01\n\x02v0\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityResponse.GetContestedResourceVotersForIdentityResponseV0H\x00\x1a\xab\x03\n/GetContestedResourceVotersForIdentityResponseV0\x12\xb6\x01\n\x19\x63ontested_resource_voters\x18\x01 \x01(\x0b\x32\x90\x01.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityResponse.GetContestedResourceVotersForIdentityResponseV0.ContestedResourceVotersH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x43\n\x17\x43ontestedResourceVoters\x12\x0e\n\x06voters\x18\x01 \x03(\x0c\x12\x18\n\x10\x66inished_results\x18\x02 \x01(\x08\x42\x08\n\x06resultB\t\n\x07version\"\xad\x05\n(GetContestedResourceIdentityVotesRequest\x12|\n\x02v0\x18\x01 \x01(\x0b\x32n.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesRequest.GetContestedResourceIdentityVotesRequestV0H\x00\x1a\xf7\x03\n*GetContestedResourceIdentityVotesRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12+\n\x05limit\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12,\n\x06offset\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\x17\n\x0forder_ascending\x18\x04 \x01(\x08\x12\xae\x01\n\x1astart_at_vote_poll_id_info\x18\x05 \x01(\x0b\x32\x84\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesRequest.GetContestedResourceIdentityVotesRequestV0.StartAtVotePollIdInfoH\x00\x88\x01\x01\x12\r\n\x05prove\x18\x06 \x01(\x08\x1a\x61\n\x15StartAtVotePollIdInfo\x12 \n\x18start_at_poll_identifier\x18\x01 \x01(\x0c\x12&\n\x1estart_poll_identifier_included\x18\x02 \x01(\x08\x42\x1d\n\x1b_start_at_vote_poll_id_infoB\t\n\x07version\"\xc8\n\n)GetContestedResourceIdentityVotesResponse\x12~\n\x02v0\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0H\x00\x1a\x8f\t\n+GetContestedResourceIdentityVotesResponseV0\x12\xa1\x01\n\x05votes\x18\x01 \x01(\x0b\x32\x8f\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ContestedResourceIdentityVotesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xf7\x01\n\x1e\x43ontestedResourceIdentityVotes\x12\xba\x01\n!contested_resource_identity_votes\x18\x01 \x03(\x0b\x32\x8e\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ContestedResourceIdentityVote\x12\x18\n\x10\x66inished_results\x18\x02 \x01(\x08\x1a\xad\x02\n\x12ResourceVoteChoice\x12\xad\x01\n\x10vote_choice_type\x18\x01 \x01(\x0e\x32\x92\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ResourceVoteChoice.VoteChoiceType\x12\x18\n\x0bidentity_id\x18\x02 \x01(\x0cH\x00\x88\x01\x01\"=\n\x0eVoteChoiceType\x12\x14\n\x10TOWARDS_IDENTITY\x10\x00\x12\x0b\n\x07\x41\x42STAIN\x10\x01\x12\x08\n\x04LOCK\x10\x02\x42\x0e\n\x0c_identity_id\x1a\x95\x02\n\x1d\x43ontestedResourceIdentityVote\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\'\n\x1fserialized_index_storage_values\x18\x03 \x03(\x0c\x12\x99\x01\n\x0bvote_choice\x18\x04 \x01(\x0b\x32\x83\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ResourceVoteChoiceB\x08\n\x06resultB\t\n\x07version\"\xf0\x01\n%GetPrefundedSpecializedBalanceRequest\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceRequest.GetPrefundedSpecializedBalanceRequestV0H\x00\x1a\x44\n\'GetPrefundedSpecializedBalanceRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xed\x02\n&GetPrefundedSpecializedBalanceResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceResponse.GetPrefundedSpecializedBalanceResponseV0H\x00\x1a\xbd\x01\n(GetPrefundedSpecializedBalanceResponseV0\x12\x15\n\x07\x62\x61lance\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xd0\x01\n GetTotalCreditsInPlatformRequest\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformRequest.GetTotalCreditsInPlatformRequestV0H\x00\x1a\x33\n\"GetTotalCreditsInPlatformRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xd9\x02\n!GetTotalCreditsInPlatformResponse\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformResponse.GetTotalCreditsInPlatformResponseV0H\x00\x1a\xb8\x01\n#GetTotalCreditsInPlatformResponseV0\x12\x15\n\x07\x63redits\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc4\x01\n\x16GetPathElementsRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetPathElementsRequest.GetPathElementsRequestV0H\x00\x1a\x45\n\x18GetPathElementsRequestV0\x12\x0c\n\x04path\x18\x01 \x03(\x0c\x12\x0c\n\x04keys\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xa3\x03\n\x17GetPathElementsResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetPathElementsResponse.GetPathElementsResponseV0H\x00\x1a\xa0\x02\n\x19GetPathElementsResponseV0\x12i\n\x08\x65lements\x18\x01 \x01(\x0b\x32U.org.dash.platform.dapi.v0.GetPathElementsResponse.GetPathElementsResponseV0.ElementsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1c\n\x08\x45lements\x12\x10\n\x08\x65lements\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\x81\x01\n\x10GetStatusRequest\x12L\n\x02v0\x18\x01 \x01(\x0b\x32>.org.dash.platform.dapi.v0.GetStatusRequest.GetStatusRequestV0H\x00\x1a\x14\n\x12GetStatusRequestV0B\t\n\x07version\"\xe4\x10\n\x11GetStatusResponse\x12N\n\x02v0\x18\x01 \x01(\x0b\x32@.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0H\x00\x1a\xf3\x0f\n\x13GetStatusResponseV0\x12Y\n\x07version\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version\x12S\n\x04node\x18\x02 \x01(\x0b\x32\x45.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Node\x12U\n\x05\x63hain\x18\x03 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Chain\x12Y\n\x07network\x18\x04 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Network\x12^\n\nstate_sync\x18\x05 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.StateSync\x12S\n\x04time\x18\x06 \x01(\x0b\x32\x45.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Time\x1a\x82\x05\n\x07Version\x12\x63\n\x08software\x18\x01 \x01(\x0b\x32Q.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Software\x12\x63\n\x08protocol\x18\x02 \x01(\x0b\x32Q.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Protocol\x1a^\n\x08Software\x12\x0c\n\x04\x64\x61pi\x18\x01 \x01(\t\x12\x12\n\x05\x64rive\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x17\n\ntenderdash\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_driveB\r\n\x0b_tenderdash\x1a\xcc\x02\n\x08Protocol\x12p\n\ntenderdash\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Protocol.Tenderdash\x12\x66\n\x05\x64rive\x18\x02 \x01(\x0b\x32W.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Protocol.Drive\x1a(\n\nTenderdash\x12\x0b\n\x03p2p\x18\x01 \x01(\r\x12\r\n\x05\x62lock\x18\x02 \x01(\r\x1a<\n\x05\x44rive\x12\x0e\n\x06latest\x18\x03 \x01(\r\x12\x0f\n\x07\x63urrent\x18\x04 \x01(\r\x12\x12\n\nnext_epoch\x18\x05 \x01(\r\x1a\x7f\n\x04Time\x12\x11\n\x05local\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x16\n\x05\x62lock\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x88\x01\x01\x12\x18\n\x07genesis\x18\x03 \x01(\x04\x42\x02\x30\x01H\x01\x88\x01\x01\x12\x12\n\x05\x65poch\x18\x04 \x01(\rH\x02\x88\x01\x01\x42\x08\n\x06_blockB\n\n\x08_genesisB\x08\n\x06_epoch\x1a<\n\x04Node\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x18\n\x0bpro_tx_hash\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x42\x0e\n\x0c_pro_tx_hash\x1a\xb3\x02\n\x05\x43hain\x12\x13\n\x0b\x63\x61tching_up\x18\x01 \x01(\x08\x12\x19\n\x11latest_block_hash\x18\x02 \x01(\x0c\x12\x17\n\x0flatest_app_hash\x18\x03 \x01(\x0c\x12\x1f\n\x13latest_block_height\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x1b\n\x13\x65\x61rliest_block_hash\x18\x05 \x01(\x0c\x12\x19\n\x11\x65\x61rliest_app_hash\x18\x06 \x01(\x0c\x12!\n\x15\x65\x61rliest_block_height\x18\x07 \x01(\x04\x42\x02\x30\x01\x12!\n\x15max_peer_block_height\x18\t \x01(\x04\x42\x02\x30\x01\x12%\n\x18\x63ore_chain_locked_height\x18\n \x01(\rH\x00\x88\x01\x01\x42\x1b\n\x19_core_chain_locked_height\x1a\x43\n\x07Network\x12\x10\n\x08\x63hain_id\x18\x01 \x01(\t\x12\x13\n\x0bpeers_count\x18\x02 \x01(\r\x12\x11\n\tlistening\x18\x03 \x01(\x08\x1a\x85\x02\n\tStateSync\x12\x1d\n\x11total_synced_time\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1a\n\x0eremaining_time\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x17\n\x0ftotal_snapshots\x18\x03 \x01(\r\x12\"\n\x16\x63hunk_process_avg_time\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x1b\n\x0fsnapshot_height\x18\x05 \x01(\x04\x42\x02\x30\x01\x12!\n\x15snapshot_chunks_count\x18\x06 \x01(\x04\x42\x02\x30\x01\x12\x1d\n\x11\x62\x61\x63kfilled_blocks\x18\x07 \x01(\x04\x42\x02\x30\x01\x12!\n\x15\x62\x61\x63kfill_blocks_total\x18\x08 \x01(\x04\x42\x02\x30\x01\x42\t\n\x07version\"\xb1\x01\n\x1cGetCurrentQuorumsInfoRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoRequest.GetCurrentQuorumsInfoRequestV0H\x00\x1a \n\x1eGetCurrentQuorumsInfoRequestV0B\t\n\x07version\"\xa1\x05\n\x1dGetCurrentQuorumsInfoResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse.GetCurrentQuorumsInfoResponseV0H\x00\x1a\x46\n\x0bValidatorV0\x12\x13\n\x0bpro_tx_hash\x18\x01 \x01(\x0c\x12\x0f\n\x07node_ip\x18\x02 \x01(\t\x12\x11\n\tis_banned\x18\x03 \x01(\x08\x1a\xaf\x01\n\x0eValidatorSetV0\x12\x13\n\x0bquorum_hash\x18\x01 \x01(\x0c\x12\x13\n\x0b\x63ore_height\x18\x02 \x01(\r\x12U\n\x07members\x18\x03 \x03(\x0b\x32\x44.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse.ValidatorV0\x12\x1c\n\x14threshold_public_key\x18\x04 \x01(\x0c\x1a\x92\x02\n\x1fGetCurrentQuorumsInfoResponseV0\x12\x15\n\rquorum_hashes\x18\x01 \x03(\x0c\x12\x1b\n\x13\x63urrent_quorum_hash\x18\x02 \x01(\x0c\x12_\n\x0evalidator_sets\x18\x03 \x03(\x0b\x32G.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse.ValidatorSetV0\x12\x1b\n\x13last_block_proposer\x18\x04 \x01(\x0c\x12=\n\x08metadata\x18\x05 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\t\n\x07version\"\xf4\x01\n\x1fGetIdentityTokenBalancesRequest\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetIdentityTokenBalancesRequest.GetIdentityTokenBalancesRequestV0H\x00\x1aZ\n!GetIdentityTokenBalancesRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x11\n\ttoken_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xad\x05\n GetIdentityTokenBalancesResponse\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse.GetIdentityTokenBalancesResponseV0H\x00\x1a\x8f\x04\n\"GetIdentityTokenBalancesResponseV0\x12\x86\x01\n\x0etoken_balances\x18\x01 \x01(\x0b\x32l.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse.GetIdentityTokenBalancesResponseV0.TokenBalancesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aG\n\x11TokenBalanceEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x14\n\x07\x62\x61lance\x18\x02 \x01(\x04H\x00\x88\x01\x01\x42\n\n\x08_balance\x1a\x9a\x01\n\rTokenBalances\x12\x88\x01\n\x0etoken_balances\x18\x01 \x03(\x0b\x32p.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse.GetIdentityTokenBalancesResponseV0.TokenBalanceEntryB\x08\n\x06resultB\t\n\x07version\"\xfc\x01\n!GetIdentitiesTokenBalancesRequest\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesRequest.GetIdentitiesTokenBalancesRequestV0H\x00\x1a\\\n#GetIdentitiesTokenBalancesRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x14\n\x0cidentity_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xf2\x05\n\"GetIdentitiesTokenBalancesResponse\x12p\n\x02v0\x18\x01 \x01(\x0b\x32\x62.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse.GetIdentitiesTokenBalancesResponseV0H\x00\x1a\xce\x04\n$GetIdentitiesTokenBalancesResponseV0\x12\x9b\x01\n\x17identity_token_balances\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse.GetIdentitiesTokenBalancesResponseV0.IdentityTokenBalancesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aR\n\x19IdentityTokenBalanceEntry\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x14\n\x07\x62\x61lance\x18\x02 \x01(\x04H\x00\x88\x01\x01\x42\n\n\x08_balance\x1a\xb7\x01\n\x15IdentityTokenBalances\x12\x9d\x01\n\x17identity_token_balances\x18\x01 \x03(\x0b\x32|.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse.GetIdentitiesTokenBalancesResponseV0.IdentityTokenBalanceEntryB\x08\n\x06resultB\t\n\x07version\"\xe8\x01\n\x1cGetIdentityTokenInfosRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetIdentityTokenInfosRequest.GetIdentityTokenInfosRequestV0H\x00\x1aW\n\x1eGetIdentityTokenInfosRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x11\n\ttoken_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\x98\x06\n\x1dGetIdentityTokenInfosResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0H\x00\x1a\x83\x05\n\x1fGetIdentityTokenInfosResponseV0\x12z\n\x0btoken_infos\x18\x01 \x01(\x0b\x32\x63.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a(\n\x16TokenIdentityInfoEntry\x12\x0e\n\x06\x66rozen\x18\x01 \x01(\x08\x1a\xb0\x01\n\x0eTokenInfoEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x82\x01\n\x04info\x18\x02 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenIdentityInfoEntryH\x00\x88\x01\x01\x42\x07\n\x05_info\x1a\x8a\x01\n\nTokenInfos\x12|\n\x0btoken_infos\x18\x01 \x03(\x0b\x32g.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenInfoEntryB\x08\n\x06resultB\t\n\x07version\"\xf0\x01\n\x1eGetIdentitiesTokenInfosRequest\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosRequest.GetIdentitiesTokenInfosRequestV0H\x00\x1aY\n GetIdentitiesTokenInfosRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x14\n\x0cidentity_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xca\x06\n\x1fGetIdentitiesTokenInfosResponse\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0H\x00\x1a\xaf\x05\n!GetIdentitiesTokenInfosResponseV0\x12\x8f\x01\n\x14identity_token_infos\x18\x01 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0.IdentityTokenInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a(\n\x16TokenIdentityInfoEntry\x12\x0e\n\x06\x66rozen\x18\x01 \x01(\x08\x1a\xb7\x01\n\x0eTokenInfoEntry\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x86\x01\n\x04info\x18\x02 \x01(\x0b\x32s.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0.TokenIdentityInfoEntryH\x00\x88\x01\x01\x42\x07\n\x05_info\x1a\x97\x01\n\x12IdentityTokenInfos\x12\x80\x01\n\x0btoken_infos\x18\x01 \x03(\x0b\x32k.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0.TokenInfoEntryB\x08\n\x06resultB\t\n\x07version\"\xbf\x01\n\x17GetTokenStatusesRequest\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetTokenStatusesRequest.GetTokenStatusesRequestV0H\x00\x1a=\n\x19GetTokenStatusesRequestV0\x12\x11\n\ttoken_ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xe7\x04\n\x18GetTokenStatusesResponse\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetTokenStatusesResponse.GetTokenStatusesResponseV0H\x00\x1a\xe1\x03\n\x1aGetTokenStatusesResponseV0\x12v\n\x0etoken_statuses\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetTokenStatusesResponse.GetTokenStatusesResponseV0.TokenStatusesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x44\n\x10TokenStatusEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x13\n\x06paused\x18\x02 \x01(\x08H\x00\x88\x01\x01\x42\t\n\x07_paused\x1a\x88\x01\n\rTokenStatuses\x12w\n\x0etoken_statuses\x18\x01 \x03(\x0b\x32_.org.dash.platform.dapi.v0.GetTokenStatusesResponse.GetTokenStatusesResponseV0.TokenStatusEntryB\x08\n\x06resultB\t\n\x07version\"\xef\x01\n#GetTokenDirectPurchasePricesRequest\x12r\n\x02v0\x18\x01 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesRequest.GetTokenDirectPurchasePricesRequestV0H\x00\x1aI\n%GetTokenDirectPurchasePricesRequestV0\x12\x11\n\ttoken_ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x8b\t\n$GetTokenDirectPurchasePricesResponse\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0H\x00\x1a\xe1\x07\n&GetTokenDirectPurchasePricesResponseV0\x12\xa9\x01\n\x1ctoken_direct_purchase_prices\x18\x01 \x01(\x0b\x32\x80\x01.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.TokenDirectPurchasePricesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x33\n\x10PriceForQuantity\x12\x10\n\x08quantity\x18\x01 \x01(\x04\x12\r\n\x05price\x18\x02 \x01(\x04\x1a\xa7\x01\n\x0fPricingSchedule\x12\x93\x01\n\x12price_for_quantity\x18\x01 \x03(\x0b\x32w.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.PriceForQuantity\x1a\xe4\x01\n\x1dTokenDirectPurchasePriceEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x15\n\x0b\x66ixed_price\x18\x02 \x01(\x04H\x00\x12\x90\x01\n\x0evariable_price\x18\x03 \x01(\x0b\x32v.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.PricingScheduleH\x00\x42\x07\n\x05price\x1a\xc8\x01\n\x19TokenDirectPurchasePrices\x12\xaa\x01\n\x1btoken_direct_purchase_price\x18\x01 \x03(\x0b\x32\x84\x01.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.TokenDirectPurchasePriceEntryB\x08\n\x06resultB\t\n\x07version\"\xce\x01\n\x1bGetTokenContractInfoRequest\x12\x62\n\x02v0\x18\x01 \x01(\x0b\x32T.org.dash.platform.dapi.v0.GetTokenContractInfoRequest.GetTokenContractInfoRequestV0H\x00\x1a@\n\x1dGetTokenContractInfoRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xfb\x03\n\x1cGetTokenContractInfoResponse\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetTokenContractInfoResponse.GetTokenContractInfoResponseV0H\x00\x1a\xe9\x02\n\x1eGetTokenContractInfoResponseV0\x12|\n\x04\x64\x61ta\x18\x01 \x01(\x0b\x32l.org.dash.platform.dapi.v0.GetTokenContractInfoResponse.GetTokenContractInfoResponseV0.TokenContractInfoDataH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aM\n\x15TokenContractInfoData\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17token_contract_position\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xef\x04\n)GetTokenPreProgrammedDistributionsRequest\x12~\n\x02v0\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsRequest.GetTokenPreProgrammedDistributionsRequestV0H\x00\x1a\xb6\x03\n+GetTokenPreProgrammedDistributionsRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x98\x01\n\rstart_at_info\x18\x02 \x01(\x0b\x32|.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsRequest.GetTokenPreProgrammedDistributionsRequestV0.StartAtInfoH\x00\x88\x01\x01\x12\x12\n\x05limit\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\x04 \x01(\x08\x1a\x9a\x01\n\x0bStartAtInfo\x12\x15\n\rstart_time_ms\x18\x01 \x01(\x04\x12\x1c\n\x0fstart_recipient\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12%\n\x18start_recipient_included\x18\x03 \x01(\x08H\x01\x88\x01\x01\x42\x12\n\x10_start_recipientB\x1b\n\x19_start_recipient_includedB\x10\n\x0e_start_at_infoB\x08\n\x06_limitB\t\n\x07version\"\xec\x07\n*GetTokenPreProgrammedDistributionsResponse\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0H\x00\x1a\xaf\x06\n,GetTokenPreProgrammedDistributionsResponseV0\x12\xa5\x01\n\x13token_distributions\x18\x01 \x01(\x0b\x32\x85\x01.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0.TokenDistributionsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a>\n\x16TokenDistributionEntry\x12\x14\n\x0crecipient_id\x18\x01 \x01(\x0c\x12\x0e\n\x06\x61mount\x18\x02 \x01(\x04\x1a\xd4\x01\n\x1bTokenTimedDistributionEntry\x12\x11\n\ttimestamp\x18\x01 \x01(\x04\x12\xa1\x01\n\rdistributions\x18\x02 \x03(\x0b\x32\x89\x01.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0.TokenDistributionEntry\x1a\xc3\x01\n\x12TokenDistributions\x12\xac\x01\n\x13token_distributions\x18\x01 \x03(\x0b\x32\x8e\x01.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0.TokenTimedDistributionEntryB\x08\n\x06resultB\t\n\x07version\"\x82\x04\n-GetTokenPerpetualDistributionLastClaimRequest\x12\x86\x01\n\x02v0\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimRequest.GetTokenPerpetualDistributionLastClaimRequestV0H\x00\x1aI\n\x11\x43ontractTokenInfo\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17token_contract_position\x18\x02 \x01(\r\x1a\xf1\x01\n/GetTokenPerpetualDistributionLastClaimRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12v\n\rcontract_info\x18\x02 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimRequest.ContractTokenInfoH\x00\x88\x01\x01\x12\x13\n\x0bidentity_id\x18\x04 \x01(\x0c\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\x10\n\x0e_contract_infoB\t\n\x07version\"\x93\x05\n.GetTokenPerpetualDistributionLastClaimResponse\x12\x88\x01\n\x02v0\x18\x01 \x01(\x0b\x32z.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimResponse.GetTokenPerpetualDistributionLastClaimResponseV0H\x00\x1a\xca\x03\n0GetTokenPerpetualDistributionLastClaimResponseV0\x12\x9f\x01\n\nlast_claim\x18\x01 \x01(\x0b\x32\x88\x01.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimResponse.GetTokenPerpetualDistributionLastClaimResponseV0.LastClaimInfoH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1ax\n\rLastClaimInfo\x12\x1a\n\x0ctimestamp_ms\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x1a\n\x0c\x62lock_height\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x12\x0f\n\x05\x65poch\x18\x03 \x01(\rH\x00\x12\x13\n\traw_bytes\x18\x04 \x01(\x0cH\x00\x42\t\n\x07paid_atB\x08\n\x06resultB\t\n\x07version\"\xca\x01\n\x1aGetTokenTotalSupplyRequest\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetTokenTotalSupplyRequest.GetTokenTotalSupplyRequestV0H\x00\x1a?\n\x1cGetTokenTotalSupplyRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xaf\x04\n\x1bGetTokenTotalSupplyResponse\x12\x62\n\x02v0\x18\x01 \x01(\x0b\x32T.org.dash.platform.dapi.v0.GetTokenTotalSupplyResponse.GetTokenTotalSupplyResponseV0H\x00\x1a\xa0\x03\n\x1dGetTokenTotalSupplyResponseV0\x12\x88\x01\n\x12token_total_supply\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetTokenTotalSupplyResponse.GetTokenTotalSupplyResponseV0.TokenTotalSupplyEntryH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1ax\n\x15TokenTotalSupplyEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x30\n(total_aggregated_amount_in_user_accounts\x18\x02 \x01(\x04\x12\x1b\n\x13total_system_amount\x18\x03 \x01(\x04\x42\x08\n\x06resultB\t\n\x07version\"\xd2\x01\n\x13GetGroupInfoRequest\x12R\n\x02v0\x18\x01 \x01(\x0b\x32\x44.org.dash.platform.dapi.v0.GetGroupInfoRequest.GetGroupInfoRequestV0H\x00\x1a\\\n\x15GetGroupInfoRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17group_contract_position\x18\x02 \x01(\r\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xd4\x05\n\x14GetGroupInfoResponse\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0H\x00\x1a\xda\x04\n\x16GetGroupInfoResponseV0\x12\x66\n\ngroup_info\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0.GroupInfoH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x04 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x34\n\x10GroupMemberEntry\x12\x11\n\tmember_id\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x02 \x01(\r\x1a\x98\x01\n\x0eGroupInfoEntry\x12h\n\x07members\x18\x01 \x03(\x0b\x32W.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0.GroupMemberEntry\x12\x1c\n\x14group_required_power\x18\x02 \x01(\r\x1a\x8a\x01\n\tGroupInfo\x12n\n\ngroup_info\x18\x01 \x01(\x0b\x32U.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0.GroupInfoEntryH\x00\x88\x01\x01\x42\r\n\x0b_group_infoB\x08\n\x06resultB\t\n\x07version\"\xed\x03\n\x14GetGroupInfosRequest\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetGroupInfosRequest.GetGroupInfosRequestV0H\x00\x1au\n\x1cStartAtGroupContractPosition\x12%\n\x1dstart_group_contract_position\x18\x01 \x01(\r\x12.\n&start_group_contract_position_included\x18\x02 \x01(\x08\x1a\xfc\x01\n\x16GetGroupInfosRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12{\n start_at_group_contract_position\x18\x02 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetGroupInfosRequest.StartAtGroupContractPositionH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\x04 \x01(\x08\x42#\n!_start_at_group_contract_positionB\x08\n\x06_countB\t\n\x07version\"\xff\x05\n\x15GetGroupInfosResponse\x12V\n\x02v0\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0H\x00\x1a\x82\x05\n\x17GetGroupInfosResponseV0\x12j\n\x0bgroup_infos\x18\x01 \x01(\x0b\x32S.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0.GroupInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x04 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x34\n\x10GroupMemberEntry\x12\x11\n\tmember_id\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x02 \x01(\r\x1a\xc3\x01\n\x16GroupPositionInfoEntry\x12\x1f\n\x17group_contract_position\x18\x01 \x01(\r\x12j\n\x07members\x18\x02 \x03(\x0b\x32Y.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0.GroupMemberEntry\x12\x1c\n\x14group_required_power\x18\x03 \x01(\r\x1a\x82\x01\n\nGroupInfos\x12t\n\x0bgroup_infos\x18\x01 \x03(\x0b\x32_.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0.GroupPositionInfoEntryB\x08\n\x06resultB\t\n\x07version\"\xbe\x04\n\x16GetGroupActionsRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetGroupActionsRequest.GetGroupActionsRequestV0H\x00\x1aL\n\x0fStartAtActionId\x12\x17\n\x0fstart_action_id\x18\x01 \x01(\x0c\x12 \n\x18start_action_id_included\x18\x02 \x01(\x08\x1a\xc8\x02\n\x18GetGroupActionsRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17group_contract_position\x18\x02 \x01(\r\x12N\n\x06status\x18\x03 \x01(\x0e\x32>.org.dash.platform.dapi.v0.GetGroupActionsRequest.ActionStatus\x12\x62\n\x12start_at_action_id\x18\x04 \x01(\x0b\x32\x41.org.dash.platform.dapi.v0.GetGroupActionsRequest.StartAtActionIdH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x05 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\x06 \x01(\x08\x42\x15\n\x13_start_at_action_idB\x08\n\x06_count\"&\n\x0c\x41\x63tionStatus\x12\n\n\x06\x41\x43TIVE\x10\x00\x12\n\n\x06\x43LOSED\x10\x01\x42\t\n\x07version\"\xd6\x1e\n\x17GetGroupActionsResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0H\x00\x1a\xd3\x1d\n\x19GetGroupActionsResponseV0\x12r\n\rgroup_actions\x18\x01 \x01(\x0b\x32Y.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.GroupActionsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a[\n\tMintEvent\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x04\x12\x14\n\x0crecipient_id\x18\x02 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a[\n\tBurnEvent\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x04\x12\x14\n\x0c\x62urn_from_id\x18\x02 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1aJ\n\x0b\x46reezeEvent\x12\x11\n\tfrozen_id\x18\x01 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1aL\n\rUnfreezeEvent\x12\x11\n\tfrozen_id\x18\x01 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a\x66\n\x17\x44\x65stroyFrozenFundsEvent\x12\x11\n\tfrozen_id\x18\x01 \x01(\x0c\x12\x0e\n\x06\x61mount\x18\x02 \x01(\x04\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a\x64\n\x13SharedEncryptedNote\x12\x18\n\x10sender_key_index\x18\x01 \x01(\r\x12\x1b\n\x13recipient_key_index\x18\x02 \x01(\r\x12\x16\n\x0e\x65ncrypted_data\x18\x03 \x01(\x0c\x1a{\n\x15PersonalEncryptedNote\x12!\n\x19root_encryption_key_index\x18\x01 \x01(\r\x12\'\n\x1f\x64\x65rivation_encryption_key_index\x18\x02 \x01(\r\x12\x16\n\x0e\x65ncrypted_data\x18\x03 \x01(\x0c\x1a\xe9\x01\n\x14\x45mergencyActionEvent\x12\x81\x01\n\x0b\x61\x63tion_type\x18\x01 \x01(\x0e\x32l.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.EmergencyActionEvent.ActionType\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\"#\n\nActionType\x12\t\n\x05PAUSE\x10\x00\x12\n\n\x06RESUME\x10\x01\x42\x0e\n\x0c_public_note\x1a\x64\n\x16TokenConfigUpdateEvent\x12 \n\x18token_config_update_item\x18\x01 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a\xe6\x03\n\x1eUpdateDirectPurchasePriceEvent\x12\x15\n\x0b\x66ixed_price\x18\x01 \x01(\x04H\x00\x12\x95\x01\n\x0evariable_price\x18\x02 \x01(\x0b\x32{.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UpdateDirectPurchasePriceEvent.PricingScheduleH\x00\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x01\x88\x01\x01\x1a\x33\n\x10PriceForQuantity\x12\x10\n\x08quantity\x18\x01 \x01(\x04\x12\r\n\x05price\x18\x02 \x01(\x04\x1a\xac\x01\n\x0fPricingSchedule\x12\x98\x01\n\x12price_for_quantity\x18\x01 \x03(\x0b\x32|.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UpdateDirectPurchasePriceEvent.PriceForQuantityB\x07\n\x05priceB\x0e\n\x0c_public_note\x1a\xfc\x02\n\x10GroupActionEvent\x12n\n\x0btoken_event\x18\x01 \x01(\x0b\x32W.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.TokenEventH\x00\x12t\n\x0e\x64ocument_event\x18\x02 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.DocumentEventH\x00\x12t\n\x0e\x63ontract_event\x18\x03 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.ContractEventH\x00\x42\x0c\n\nevent_type\x1a\x8b\x01\n\rDocumentEvent\x12r\n\x06\x63reate\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.DocumentCreateEventH\x00\x42\x06\n\x04type\x1a/\n\x13\x44ocumentCreateEvent\x12\x18\n\x10\x63reated_document\x18\x01 \x01(\x0c\x1a/\n\x13\x43ontractUpdateEvent\x12\x18\n\x10updated_contract\x18\x01 \x01(\x0c\x1a\x8b\x01\n\rContractEvent\x12r\n\x06update\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.ContractUpdateEventH\x00\x42\x06\n\x04type\x1a\xd1\x07\n\nTokenEvent\x12\x66\n\x04mint\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.MintEventH\x00\x12\x66\n\x04\x62urn\x18\x02 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.BurnEventH\x00\x12j\n\x06\x66reeze\x18\x03 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.FreezeEventH\x00\x12n\n\x08unfreeze\x18\x04 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UnfreezeEventH\x00\x12\x84\x01\n\x14\x64\x65stroy_frozen_funds\x18\x05 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.DestroyFrozenFundsEventH\x00\x12}\n\x10\x65mergency_action\x18\x06 \x01(\x0b\x32\x61.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.EmergencyActionEventH\x00\x12\x82\x01\n\x13token_config_update\x18\x07 \x01(\x0b\x32\x63.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.TokenConfigUpdateEventH\x00\x12\x83\x01\n\x0cupdate_price\x18\x08 \x01(\x0b\x32k.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UpdateDirectPurchasePriceEventH\x00\x42\x06\n\x04type\x1a\x93\x01\n\x10GroupActionEntry\x12\x11\n\taction_id\x18\x01 \x01(\x0c\x12l\n\x05\x65vent\x18\x02 \x01(\x0b\x32].org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.GroupActionEvent\x1a\x84\x01\n\x0cGroupActions\x12t\n\rgroup_actions\x18\x01 \x03(\x0b\x32].org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.GroupActionEntryB\x08\n\x06resultB\t\n\x07version\"\x88\x03\n\x1cGetGroupActionSignersRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetGroupActionSignersRequest.GetGroupActionSignersRequestV0H\x00\x1a\xce\x01\n\x1eGetGroupActionSignersRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17group_contract_position\x18\x02 \x01(\r\x12T\n\x06status\x18\x03 \x01(\x0e\x32\x44.org.dash.platform.dapi.v0.GetGroupActionSignersRequest.ActionStatus\x12\x11\n\taction_id\x18\x04 \x01(\x0c\x12\r\n\x05prove\x18\x05 \x01(\x08\"&\n\x0c\x41\x63tionStatus\x12\n\n\x06\x41\x43TIVE\x10\x00\x12\n\n\x06\x43LOSED\x10\x01\x42\t\n\x07version\"\x8b\x05\n\x1dGetGroupActionSignersResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetGroupActionSignersResponse.GetGroupActionSignersResponseV0H\x00\x1a\xf6\x03\n\x1fGetGroupActionSignersResponseV0\x12\x8b\x01\n\x14group_action_signers\x18\x01 \x01(\x0b\x32k.org.dash.platform.dapi.v0.GetGroupActionSignersResponse.GetGroupActionSignersResponseV0.GroupActionSignersH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x35\n\x11GroupActionSigner\x12\x11\n\tsigner_id\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x02 \x01(\r\x1a\x91\x01\n\x12GroupActionSigners\x12{\n\x07signers\x18\x01 \x03(\x0b\x32j.org.dash.platform.dapi.v0.GetGroupActionSignersResponse.GetGroupActionSignersResponseV0.GroupActionSignerB\x08\n\x06resultB\t\n\x07version\"\xb5\x01\n\x15GetAddressInfoRequest\x12V\n\x02v0\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetAddressInfoRequest.GetAddressInfoRequestV0H\x00\x1a\x39\n\x17GetAddressInfoRequestV0\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x85\x01\n\x10\x41\x64\x64ressInfoEntry\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12J\n\x11\x62\x61lance_and_nonce\x18\x02 \x01(\x0b\x32*.org.dash.platform.dapi.v0.BalanceAndNonceH\x00\x88\x01\x01\x42\x14\n\x12_balance_and_nonce\"1\n\x0f\x42\x61lanceAndNonce\x12\x0f\n\x07\x62\x61lance\x18\x01 \x01(\x04\x12\r\n\x05nonce\x18\x02 \x01(\r\"_\n\x12\x41\x64\x64ressInfoEntries\x12I\n\x14\x61\x64\x64ress_info_entries\x18\x01 \x03(\x0b\x32+.org.dash.platform.dapi.v0.AddressInfoEntry\"m\n\x14\x41\x64\x64ressBalanceChange\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x19\n\x0bset_balance\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x12\x1c\n\x0e\x61\x64\x64_to_balance\x18\x03 \x01(\x04\x42\x02\x30\x01H\x00\x42\x0b\n\toperation\"x\n\x1a\x42lockAddressBalanceChanges\x12\x18\n\x0c\x62lock_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12@\n\x07\x63hanges\x18\x02 \x03(\x0b\x32/.org.dash.platform.dapi.v0.AddressBalanceChange\"k\n\x1b\x41\x64\x64ressBalanceUpdateEntries\x12L\n\rblock_changes\x18\x01 \x03(\x0b\x32\x35.org.dash.platform.dapi.v0.BlockAddressBalanceChanges\"\xe1\x02\n\x16GetAddressInfoResponse\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetAddressInfoResponse.GetAddressInfoResponseV0H\x00\x1a\xe1\x01\n\x18GetAddressInfoResponseV0\x12I\n\x12\x61\x64\x64ress_info_entry\x18\x01 \x01(\x0b\x32+.org.dash.platform.dapi.v0.AddressInfoEntryH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc3\x01\n\x18GetAddressesInfosRequest\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetAddressesInfosRequest.GetAddressesInfosRequestV0H\x00\x1a>\n\x1aGetAddressesInfosRequestV0\x12\x11\n\taddresses\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xf1\x02\n\x19GetAddressesInfosResponse\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetAddressesInfosResponse.GetAddressesInfosResponseV0H\x00\x1a\xe8\x01\n\x1bGetAddressesInfosResponseV0\x12M\n\x14\x61\x64\x64ress_info_entries\x18\x01 \x01(\x0b\x32-.org.dash.platform.dapi.v0.AddressInfoEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xb5\x01\n\x1dGetAddressesTrunkStateRequest\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetAddressesTrunkStateRequest.GetAddressesTrunkStateRequestV0H\x00\x1a!\n\x1fGetAddressesTrunkStateRequestV0B\t\n\x07version\"\xaa\x02\n\x1eGetAddressesTrunkStateResponse\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetAddressesTrunkStateResponse.GetAddressesTrunkStateResponseV0H\x00\x1a\x92\x01\n GetAddressesTrunkStateResponseV0\x12/\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.Proof\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\t\n\x07version\"\xf0\x01\n\x1eGetAddressesBranchStateRequest\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetAddressesBranchStateRequest.GetAddressesBranchStateRequestV0H\x00\x1aY\n GetAddressesBranchStateRequestV0\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\r\n\x05\x64\x65pth\x18\x02 \x01(\r\x12\x19\n\x11\x63heckpoint_height\x18\x03 \x01(\x04\x42\t\n\x07version\"\xd1\x01\n\x1fGetAddressesBranchStateResponse\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetAddressesBranchStateResponse.GetAddressesBranchStateResponseV0H\x00\x1a\x37\n!GetAddressesBranchStateResponseV0\x12\x12\n\nmerk_proof\x18\x02 \x01(\x0c\x42\t\n\x07version\"\xfe\x01\n%GetRecentAddressBalanceChangesRequest\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesRequest.GetRecentAddressBalanceChangesRequestV0H\x00\x1aR\n\'GetRecentAddressBalanceChangesRequestV0\x12\x18\n\x0cstart_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xb8\x03\n&GetRecentAddressBalanceChangesResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesResponse.GetRecentAddressBalanceChangesResponseV0H\x00\x1a\x88\x02\n(GetRecentAddressBalanceChangesResponseV0\x12`\n\x1e\x61\x64\x64ress_balance_update_entries\x18\x01 \x01(\x0b\x32\x36.org.dash.platform.dapi.v0.AddressBalanceUpdateEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"G\n\x16\x42lockHeightCreditEntry\x12\x18\n\x0c\x62lock_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x13\n\x07\x63redits\x18\x02 \x01(\x04\x42\x02\x30\x01\"\xb0\x01\n\x1d\x43ompactedAddressBalanceChange\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x19\n\x0bset_credits\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x12V\n\x19\x61\x64\x64_to_credits_operations\x18\x03 \x01(\x0b\x32\x31.org.dash.platform.dapi.v0.AddToCreditsOperationsH\x00\x42\x0b\n\toperation\"\\\n\x16\x41\x64\x64ToCreditsOperations\x12\x42\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x31.org.dash.platform.dapi.v0.BlockHeightCreditEntry\"\xae\x01\n#CompactedBlockAddressBalanceChanges\x12\x1e\n\x12start_block_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1c\n\x10\x65nd_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12I\n\x07\x63hanges\x18\x03 \x03(\x0b\x32\x38.org.dash.platform.dapi.v0.CompactedAddressBalanceChange\"\x87\x01\n$CompactedAddressBalanceUpdateEntries\x12_\n\x17\x63ompacted_block_changes\x18\x01 \x03(\x0b\x32>.org.dash.platform.dapi.v0.CompactedBlockAddressBalanceChanges\"\xa9\x02\n.GetRecentCompactedAddressBalanceChangesRequest\x12\x88\x01\n\x02v0\x18\x01 \x01(\x0b\x32z.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesRequest.GetRecentCompactedAddressBalanceChangesRequestV0H\x00\x1a\x61\n0GetRecentCompactedAddressBalanceChangesRequestV0\x12\x1e\n\x12start_block_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xf0\x03\n/GetRecentCompactedAddressBalanceChangesResponse\x12\x8a\x01\n\x02v0\x18\x01 \x01(\x0b\x32|.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0H\x00\x1a\xa4\x02\n1GetRecentCompactedAddressBalanceChangesResponseV0\x12s\n(compacted_address_balance_update_entries\x18\x01 \x01(\x0b\x32?.org.dash.platform.dapi.v0.CompactedAddressBalanceUpdateEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xf4\x01\n GetShieldedEncryptedNotesRequest\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0H\x00\x1aW\n\"GetShieldedEncryptedNotesRequestV0\x12\x13\n\x0bstart_index\x18\x01 \x01(\x04\x12\r\n\x05\x63ount\x18\x02 \x01(\r\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\x99\x05\n!GetShieldedEncryptedNotesResponse\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0H\x00\x1a\xf8\x03\n#GetShieldedEncryptedNotesResponseV0\x12\x8a\x01\n\x0f\x65ncrypted_notes\x18\x01 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x34\n\rEncryptedNote\x12\x0b\n\x03\x63mx\x18\x01 \x01(\x0c\x12\x16\n\x0e\x65ncrypted_note\x18\x02 \x01(\x0c\x1a\x91\x01\n\x0e\x45ncryptedNotes\x12\x7f\n\x07\x65ntries\x18\x01 \x03(\x0b\x32n.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNoteB\x08\n\x06resultB\t\n\x07version\"\xb4\x01\n\x19GetShieldedAnchorsRequest\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0H\x00\x1a,\n\x1bGetShieldedAnchorsRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xb1\x03\n\x1aGetShieldedAnchorsResponse\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0H\x00\x1a\xa5\x02\n\x1cGetShieldedAnchorsResponseV0\x12m\n\x07\x61nchors\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.AnchorsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1a\n\x07\x41nchors\x12\x0f\n\x07\x61nchors\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xbc\x01\n\x1bGetShieldedPoolStateRequest\x12\x62\n\x02v0\x18\x01 \x01(\x0b\x32T.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0H\x00\x1a.\n\x1dGetShieldedPoolStateRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xcb\x02\n\x1cGetShieldedPoolStateResponse\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0H\x00\x1a\xb9\x01\n\x1eGetShieldedPoolStateResponseV0\x12\x1b\n\rtotal_balance\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xd4\x01\n\x1cGetShieldedNullifiersRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0H\x00\x1a\x43\n\x1eGetShieldedNullifiersRequestV0\x12\x12\n\nnullifiers\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x86\x05\n\x1dGetShieldedNullifiersResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0H\x00\x1a\xf1\x03\n\x1fGetShieldedNullifiersResponseV0\x12\x88\x01\n\x12nullifier_statuses\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatusesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x36\n\x0fNullifierStatus\x12\x11\n\tnullifier\x18\x01 \x01(\x0c\x12\x10\n\x08is_spent\x18\x02 \x01(\x08\x1a\x8e\x01\n\x11NullifierStatuses\x12y\n\x07\x65ntries\x18\x01 \x03(\x0b\x32h.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatusB\x08\n\x06resultB\t\n\x07version*Z\n\nKeyPurpose\x12\x12\n\x0e\x41UTHENTICATION\x10\x00\x12\x0e\n\nENCRYPTION\x10\x01\x12\x0e\n\nDECRYPTION\x10\x02\x12\x0c\n\x08TRANSFER\x10\x03\x12\n\n\x06VOTING\x10\x05\x32\x9e\x41\n\x08Platform\x12\x93\x01\n\x18\x62roadcastStateTransition\x12:.org.dash.platform.dapi.v0.BroadcastStateTransitionRequest\x1a;.org.dash.platform.dapi.v0.BroadcastStateTransitionResponse\x12l\n\x0bgetIdentity\x12-.org.dash.platform.dapi.v0.GetIdentityRequest\x1a..org.dash.platform.dapi.v0.GetIdentityResponse\x12x\n\x0fgetIdentityKeys\x12\x31.org.dash.platform.dapi.v0.GetIdentityKeysRequest\x1a\x32.org.dash.platform.dapi.v0.GetIdentityKeysResponse\x12\x96\x01\n\x19getIdentitiesContractKeys\x12;.org.dash.platform.dapi.v0.GetIdentitiesContractKeysRequest\x1a<.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse\x12{\n\x10getIdentityNonce\x12\x32.org.dash.platform.dapi.v0.GetIdentityNonceRequest\x1a\x33.org.dash.platform.dapi.v0.GetIdentityNonceResponse\x12\x93\x01\n\x18getIdentityContractNonce\x12:.org.dash.platform.dapi.v0.GetIdentityContractNonceRequest\x1a;.org.dash.platform.dapi.v0.GetIdentityContractNonceResponse\x12\x81\x01\n\x12getIdentityBalance\x12\x34.org.dash.platform.dapi.v0.GetIdentityBalanceRequest\x1a\x35.org.dash.platform.dapi.v0.GetIdentityBalanceResponse\x12\x8a\x01\n\x15getIdentitiesBalances\x12\x37.org.dash.platform.dapi.v0.GetIdentitiesBalancesRequest\x1a\x38.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse\x12\xa2\x01\n\x1dgetIdentityBalanceAndRevision\x12?.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionRequest\x1a@.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionResponse\x12\xaf\x01\n#getEvonodesProposedEpochBlocksByIds\x12\x45.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByIdsRequest\x1a\x41.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse\x12\xb3\x01\n%getEvonodesProposedEpochBlocksByRange\x12G.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByRangeRequest\x1a\x41.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse\x12x\n\x0fgetDataContract\x12\x31.org.dash.platform.dapi.v0.GetDataContractRequest\x1a\x32.org.dash.platform.dapi.v0.GetDataContractResponse\x12\x8d\x01\n\x16getDataContractHistory\x12\x38.org.dash.platform.dapi.v0.GetDataContractHistoryRequest\x1a\x39.org.dash.platform.dapi.v0.GetDataContractHistoryResponse\x12{\n\x10getDataContracts\x12\x32.org.dash.platform.dapi.v0.GetDataContractsRequest\x1a\x33.org.dash.platform.dapi.v0.GetDataContractsResponse\x12o\n\x0cgetDocuments\x12..org.dash.platform.dapi.v0.GetDocumentsRequest\x1a/.org.dash.platform.dapi.v0.GetDocumentsResponse\x12\x99\x01\n\x1agetIdentityByPublicKeyHash\x12<.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashRequest\x1a=.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashResponse\x12\xb4\x01\n#getIdentityByNonUniquePublicKeyHash\x12\x45.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashRequest\x1a\x46.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse\x12\x9f\x01\n\x1cwaitForStateTransitionResult\x12>.org.dash.platform.dapi.v0.WaitForStateTransitionResultRequest\x1a?.org.dash.platform.dapi.v0.WaitForStateTransitionResultResponse\x12\x81\x01\n\x12getConsensusParams\x12\x34.org.dash.platform.dapi.v0.GetConsensusParamsRequest\x1a\x35.org.dash.platform.dapi.v0.GetConsensusParamsResponse\x12\xa5\x01\n\x1egetProtocolVersionUpgradeState\x12@.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateRequest\x1a\x41.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse\x12\xb4\x01\n#getProtocolVersionUpgradeVoteStatus\x12\x45.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusRequest\x1a\x46.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse\x12r\n\rgetEpochsInfo\x12/.org.dash.platform.dapi.v0.GetEpochsInfoRequest\x1a\x30.org.dash.platform.dapi.v0.GetEpochsInfoResponse\x12\x8d\x01\n\x16getFinalizedEpochInfos\x12\x38.org.dash.platform.dapi.v0.GetFinalizedEpochInfosRequest\x1a\x39.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse\x12\x8a\x01\n\x15getContestedResources\x12\x37.org.dash.platform.dapi.v0.GetContestedResourcesRequest\x1a\x38.org.dash.platform.dapi.v0.GetContestedResourcesResponse\x12\xa2\x01\n\x1dgetContestedResourceVoteState\x12?.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest\x1a@.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse\x12\xba\x01\n%getContestedResourceVotersForIdentity\x12G.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityRequest\x1aH.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityResponse\x12\xae\x01\n!getContestedResourceIdentityVotes\x12\x43.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesRequest\x1a\x44.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse\x12\x8a\x01\n\x15getVotePollsByEndDate\x12\x37.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest\x1a\x38.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse\x12\xa5\x01\n\x1egetPrefundedSpecializedBalance\x12@.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceRequest\x1a\x41.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceResponse\x12\x96\x01\n\x19getTotalCreditsInPlatform\x12;.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformRequest\x1a<.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformResponse\x12x\n\x0fgetPathElements\x12\x31.org.dash.platform.dapi.v0.GetPathElementsRequest\x1a\x32.org.dash.platform.dapi.v0.GetPathElementsResponse\x12\x66\n\tgetStatus\x12+.org.dash.platform.dapi.v0.GetStatusRequest\x1a,.org.dash.platform.dapi.v0.GetStatusResponse\x12\x8a\x01\n\x15getCurrentQuorumsInfo\x12\x37.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoRequest\x1a\x38.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse\x12\x93\x01\n\x18getIdentityTokenBalances\x12:.org.dash.platform.dapi.v0.GetIdentityTokenBalancesRequest\x1a;.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse\x12\x99\x01\n\x1agetIdentitiesTokenBalances\x12<.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesRequest\x1a=.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse\x12\x8a\x01\n\x15getIdentityTokenInfos\x12\x37.org.dash.platform.dapi.v0.GetIdentityTokenInfosRequest\x1a\x38.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse\x12\x90\x01\n\x17getIdentitiesTokenInfos\x12\x39.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosRequest\x1a:.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse\x12{\n\x10getTokenStatuses\x12\x32.org.dash.platform.dapi.v0.GetTokenStatusesRequest\x1a\x33.org.dash.platform.dapi.v0.GetTokenStatusesResponse\x12\x9f\x01\n\x1cgetTokenDirectPurchasePrices\x12>.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesRequest\x1a?.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse\x12\x87\x01\n\x14getTokenContractInfo\x12\x36.org.dash.platform.dapi.v0.GetTokenContractInfoRequest\x1a\x37.org.dash.platform.dapi.v0.GetTokenContractInfoResponse\x12\xb1\x01\n\"getTokenPreProgrammedDistributions\x12\x44.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsRequest\x1a\x45.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse\x12\xbd\x01\n&getTokenPerpetualDistributionLastClaim\x12H.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimRequest\x1aI.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimResponse\x12\x84\x01\n\x13getTokenTotalSupply\x12\x35.org.dash.platform.dapi.v0.GetTokenTotalSupplyRequest\x1a\x36.org.dash.platform.dapi.v0.GetTokenTotalSupplyResponse\x12o\n\x0cgetGroupInfo\x12..org.dash.platform.dapi.v0.GetGroupInfoRequest\x1a/.org.dash.platform.dapi.v0.GetGroupInfoResponse\x12r\n\rgetGroupInfos\x12/.org.dash.platform.dapi.v0.GetGroupInfosRequest\x1a\x30.org.dash.platform.dapi.v0.GetGroupInfosResponse\x12x\n\x0fgetGroupActions\x12\x31.org.dash.platform.dapi.v0.GetGroupActionsRequest\x1a\x32.org.dash.platform.dapi.v0.GetGroupActionsResponse\x12\x8a\x01\n\x15getGroupActionSigners\x12\x37.org.dash.platform.dapi.v0.GetGroupActionSignersRequest\x1a\x38.org.dash.platform.dapi.v0.GetGroupActionSignersResponse\x12u\n\x0egetAddressInfo\x12\x30.org.dash.platform.dapi.v0.GetAddressInfoRequest\x1a\x31.org.dash.platform.dapi.v0.GetAddressInfoResponse\x12~\n\x11getAddressesInfos\x12\x33.org.dash.platform.dapi.v0.GetAddressesInfosRequest\x1a\x34.org.dash.platform.dapi.v0.GetAddressesInfosResponse\x12\x8d\x01\n\x16getAddressesTrunkState\x12\x38.org.dash.platform.dapi.v0.GetAddressesTrunkStateRequest\x1a\x39.org.dash.platform.dapi.v0.GetAddressesTrunkStateResponse\x12\x90\x01\n\x17getAddressesBranchState\x12\x39.org.dash.platform.dapi.v0.GetAddressesBranchStateRequest\x1a:.org.dash.platform.dapi.v0.GetAddressesBranchStateResponse\x12\xa5\x01\n\x1egetRecentAddressBalanceChanges\x12@.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesRequest\x1a\x41.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesResponse\x12\xc0\x01\n\'getRecentCompactedAddressBalanceChanges\x12I.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesRequest\x1aJ.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse\x12\x96\x01\n\x19getShieldedEncryptedNotes\x12;.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest\x1a<.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse\x12\x81\x01\n\x12getShieldedAnchors\x12\x34.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest\x1a\x35.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse\x12\x87\x01\n\x14getShieldedPoolState\x12\x36.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest\x1a\x37.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse\x12\x8a\x01\n\x15getShieldedNullifiers\x12\x37.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest\x1a\x38.org.dash.platform.dapi.v0.GetShieldedNullifiersResponseb\x06proto3' + serialized_pb=b'\n\x0eplatform.proto\x12\x19org.dash.platform.dapi.v0\x1a\x1egoogle/protobuf/wrappers.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x81\x01\n\x05Proof\x12\x15\n\rgrovedb_proof\x18\x01 \x01(\x0c\x12\x13\n\x0bquorum_hash\x18\x02 \x01(\x0c\x12\x11\n\tsignature\x18\x03 \x01(\x0c\x12\r\n\x05round\x18\x04 \x01(\r\x12\x15\n\rblock_id_hash\x18\x05 \x01(\x0c\x12\x13\n\x0bquorum_type\x18\x06 \x01(\r\"\x98\x01\n\x10ResponseMetadata\x12\x12\n\x06height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12 \n\x18\x63ore_chain_locked_height\x18\x02 \x01(\r\x12\r\n\x05\x65poch\x18\x03 \x01(\r\x12\x13\n\x07time_ms\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x18\n\x10protocol_version\x18\x05 \x01(\r\x12\x10\n\x08\x63hain_id\x18\x06 \x01(\t\"L\n\x1dStateTransitionBroadcastError\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\";\n\x1f\x42roadcastStateTransitionRequest\x12\x18\n\x10state_transition\x18\x01 \x01(\x0c\"\"\n BroadcastStateTransitionResponse\"\xa4\x01\n\x12GetIdentityRequest\x12P\n\x02v0\x18\x01 \x01(\x0b\x32\x42.org.dash.platform.dapi.v0.GetIdentityRequest.GetIdentityRequestV0H\x00\x1a\x31\n\x14GetIdentityRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xc1\x01\n\x17GetIdentityNonceRequest\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetIdentityNonceRequest.GetIdentityNonceRequestV0H\x00\x1a?\n\x19GetIdentityNonceRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xf6\x01\n\x1fGetIdentityContractNonceRequest\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetIdentityContractNonceRequest.GetIdentityContractNonceRequestV0H\x00\x1a\\\n!GetIdentityContractNonceRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x13\n\x0b\x63ontract_id\x18\x02 \x01(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xc0\x01\n\x19GetIdentityBalanceRequest\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetIdentityBalanceRequest.GetIdentityBalanceRequestV0H\x00\x1a\x38\n\x1bGetIdentityBalanceRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xec\x01\n$GetIdentityBalanceAndRevisionRequest\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionRequest.GetIdentityBalanceAndRevisionRequestV0H\x00\x1a\x43\n&GetIdentityBalanceAndRevisionRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x9e\x02\n\x13GetIdentityResponse\x12R\n\x02v0\x18\x01 \x01(\x0b\x32\x44.org.dash.platform.dapi.v0.GetIdentityResponse.GetIdentityResponseV0H\x00\x1a\xa7\x01\n\x15GetIdentityResponseV0\x12\x12\n\x08identity\x18\x01 \x01(\x0cH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xbc\x02\n\x18GetIdentityNonceResponse\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetIdentityNonceResponse.GetIdentityNonceResponseV0H\x00\x1a\xb6\x01\n\x1aGetIdentityNonceResponseV0\x12\x1c\n\x0eidentity_nonce\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xe5\x02\n GetIdentityContractNonceResponse\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetIdentityContractNonceResponse.GetIdentityContractNonceResponseV0H\x00\x1a\xc7\x01\n\"GetIdentityContractNonceResponseV0\x12%\n\x17identity_contract_nonce\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xbd\x02\n\x1aGetIdentityBalanceResponse\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetIdentityBalanceResponse.GetIdentityBalanceResponseV0H\x00\x1a\xb1\x01\n\x1cGetIdentityBalanceResponseV0\x12\x15\n\x07\x62\x61lance\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xb1\x04\n%GetIdentityBalanceAndRevisionResponse\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionResponse.GetIdentityBalanceAndRevisionResponseV0H\x00\x1a\x84\x03\n\'GetIdentityBalanceAndRevisionResponseV0\x12\x9b\x01\n\x14\x62\x61lance_and_revision\x18\x01 \x01(\x0b\x32{.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionResponse.GetIdentityBalanceAndRevisionResponseV0.BalanceAndRevisionH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a?\n\x12\x42\x61lanceAndRevision\x12\x13\n\x07\x62\x61lance\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x14\n\x08revision\x18\x02 \x01(\x04\x42\x02\x30\x01\x42\x08\n\x06resultB\t\n\x07version\"\xd1\x01\n\x0eKeyRequestType\x12\x36\n\x08\x61ll_keys\x18\x01 \x01(\x0b\x32\".org.dash.platform.dapi.v0.AllKeysH\x00\x12@\n\rspecific_keys\x18\x02 \x01(\x0b\x32\'.org.dash.platform.dapi.v0.SpecificKeysH\x00\x12:\n\nsearch_key\x18\x03 \x01(\x0b\x32$.org.dash.platform.dapi.v0.SearchKeyH\x00\x42\t\n\x07request\"\t\n\x07\x41llKeys\"\x1f\n\x0cSpecificKeys\x12\x0f\n\x07key_ids\x18\x01 \x03(\r\"\xb6\x01\n\tSearchKey\x12I\n\x0bpurpose_map\x18\x01 \x03(\x0b\x32\x34.org.dash.platform.dapi.v0.SearchKey.PurposeMapEntry\x1a^\n\x0fPurposeMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12:\n\x05value\x18\x02 \x01(\x0b\x32+.org.dash.platform.dapi.v0.SecurityLevelMap:\x02\x38\x01\"\xbf\x02\n\x10SecurityLevelMap\x12]\n\x12security_level_map\x18\x01 \x03(\x0b\x32\x41.org.dash.platform.dapi.v0.SecurityLevelMap.SecurityLevelMapEntry\x1aw\n\x15SecurityLevelMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12M\n\x05value\x18\x02 \x01(\x0e\x32>.org.dash.platform.dapi.v0.SecurityLevelMap.KeyKindRequestType:\x02\x38\x01\"S\n\x12KeyKindRequestType\x12\x1f\n\x1b\x43URRENT_KEY_OF_KIND_REQUEST\x10\x00\x12\x1c\n\x18\x41LL_KEYS_OF_KIND_REQUEST\x10\x01\"\xda\x02\n\x16GetIdentityKeysRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetIdentityKeysRequest.GetIdentityKeysRequestV0H\x00\x1a\xda\x01\n\x18GetIdentityKeysRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12?\n\x0crequest_type\x18\x02 \x01(\x0b\x32).org.dash.platform.dapi.v0.KeyRequestType\x12+\n\x05limit\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12,\n\x06offset\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\t\n\x07version\"\x99\x03\n\x17GetIdentityKeysResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetIdentityKeysResponse.GetIdentityKeysResponseV0H\x00\x1a\x96\x02\n\x19GetIdentityKeysResponseV0\x12\x61\n\x04keys\x18\x01 \x01(\x0b\x32Q.org.dash.platform.dapi.v0.GetIdentityKeysResponse.GetIdentityKeysResponseV0.KeysH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1a\n\x04Keys\x12\x12\n\nkeys_bytes\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xef\x02\n GetIdentitiesContractKeysRequest\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetIdentitiesContractKeysRequest.GetIdentitiesContractKeysRequestV0H\x00\x1a\xd1\x01\n\"GetIdentitiesContractKeysRequestV0\x12\x16\n\x0eidentities_ids\x18\x01 \x03(\x0c\x12\x13\n\x0b\x63ontract_id\x18\x02 \x01(\x0c\x12\x1f\n\x12\x64ocument_type_name\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x37\n\x08purposes\x18\x04 \x03(\x0e\x32%.org.dash.platform.dapi.v0.KeyPurpose\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\x15\n\x13_document_type_nameB\t\n\x07version\"\xdf\x06\n!GetIdentitiesContractKeysResponse\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0H\x00\x1a\xbe\x05\n#GetIdentitiesContractKeysResponseV0\x12\x8a\x01\n\x0fidentities_keys\x18\x01 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0.IdentitiesKeysH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aY\n\x0bPurposeKeys\x12\x36\n\x07purpose\x18\x01 \x01(\x0e\x32%.org.dash.platform.dapi.v0.KeyPurpose\x12\x12\n\nkeys_bytes\x18\x02 \x03(\x0c\x1a\x9f\x01\n\x0cIdentityKeys\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12z\n\x04keys\x18\x02 \x03(\x0b\x32l.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0.PurposeKeys\x1a\x90\x01\n\x0eIdentitiesKeys\x12~\n\x07\x65ntries\x18\x01 \x03(\x0b\x32m.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0.IdentityKeysB\x08\n\x06resultB\t\n\x07version\"\xa4\x02\n*GetEvonodesProposedEpochBlocksByIdsRequest\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByIdsRequest.GetEvonodesProposedEpochBlocksByIdsRequestV0H\x00\x1ah\n,GetEvonodesProposedEpochBlocksByIdsRequestV0\x12\x12\n\x05\x65poch\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x0b\n\x03ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\x08\n\x06_epochB\t\n\x07version\"\x92\x06\n&GetEvonodesProposedEpochBlocksResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse.GetEvonodesProposedEpochBlocksResponseV0H\x00\x1a\xe2\x04\n(GetEvonodesProposedEpochBlocksResponseV0\x12\xb1\x01\n#evonodes_proposed_block_counts_info\x18\x01 \x01(\x0b\x32\x81\x01.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse.GetEvonodesProposedEpochBlocksResponseV0.EvonodesProposedBlocksH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a?\n\x15\x45vonodeProposedBlocks\x12\x13\n\x0bpro_tx_hash\x18\x01 \x01(\x0c\x12\x11\n\x05\x63ount\x18\x02 \x01(\x04\x42\x02\x30\x01\x1a\xc4\x01\n\x16\x45vonodesProposedBlocks\x12\xa9\x01\n\x1e\x65vonodes_proposed_block_counts\x18\x01 \x03(\x0b\x32\x80\x01.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse.GetEvonodesProposedEpochBlocksResponseV0.EvonodeProposedBlocksB\x08\n\x06resultB\t\n\x07version\"\xf2\x02\n,GetEvonodesProposedEpochBlocksByRangeRequest\x12\x84\x01\n\x02v0\x18\x01 \x01(\x0b\x32v.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByRangeRequest.GetEvonodesProposedEpochBlocksByRangeRequestV0H\x00\x1a\xaf\x01\n.GetEvonodesProposedEpochBlocksByRangeRequestV0\x12\x12\n\x05\x65poch\x18\x01 \x01(\rH\x01\x88\x01\x01\x12\x12\n\x05limit\x18\x02 \x01(\rH\x02\x88\x01\x01\x12\x15\n\x0bstart_after\x18\x03 \x01(\x0cH\x00\x12\x12\n\x08start_at\x18\x04 \x01(\x0cH\x00\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\x07\n\x05startB\x08\n\x06_epochB\x08\n\x06_limitB\t\n\x07version\"\xcd\x01\n\x1cGetIdentitiesBalancesRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetIdentitiesBalancesRequest.GetIdentitiesBalancesRequestV0H\x00\x1a<\n\x1eGetIdentitiesBalancesRequestV0\x12\x0b\n\x03ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x9f\x05\n\x1dGetIdentitiesBalancesResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse.GetIdentitiesBalancesResponseV0H\x00\x1a\x8a\x04\n\x1fGetIdentitiesBalancesResponseV0\x12\x8a\x01\n\x13identities_balances\x18\x01 \x01(\x0b\x32k.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse.GetIdentitiesBalancesResponseV0.IdentitiesBalancesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aL\n\x0fIdentityBalance\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x18\n\x07\x62\x61lance\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x88\x01\x01\x42\n\n\x08_balance\x1a\x8f\x01\n\x12IdentitiesBalances\x12y\n\x07\x65ntries\x18\x01 \x03(\x0b\x32h.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse.GetIdentitiesBalancesResponseV0.IdentityBalanceB\x08\n\x06resultB\t\n\x07version\"\xb4\x01\n\x16GetDataContractRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetDataContractRequest.GetDataContractRequestV0H\x00\x1a\x35\n\x18GetDataContractRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xb3\x02\n\x17GetDataContractResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetDataContractResponse.GetDataContractResponseV0H\x00\x1a\xb0\x01\n\x19GetDataContractResponseV0\x12\x17\n\rdata_contract\x18\x01 \x01(\x0cH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xb9\x01\n\x17GetDataContractsRequest\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetDataContractsRequest.GetDataContractsRequestV0H\x00\x1a\x37\n\x19GetDataContractsRequestV0\x12\x0b\n\x03ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xcf\x04\n\x18GetDataContractsResponse\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetDataContractsResponse.GetDataContractsResponseV0H\x00\x1a[\n\x11\x44\x61taContractEntry\x12\x12\n\nidentifier\x18\x01 \x01(\x0c\x12\x32\n\rdata_contract\x18\x02 \x01(\x0b\x32\x1b.google.protobuf.BytesValue\x1au\n\rDataContracts\x12\x64\n\x15\x64\x61ta_contract_entries\x18\x01 \x03(\x0b\x32\x45.org.dash.platform.dapi.v0.GetDataContractsResponse.DataContractEntry\x1a\xf5\x01\n\x1aGetDataContractsResponseV0\x12[\n\x0e\x64\x61ta_contracts\x18\x01 \x01(\x0b\x32\x41.org.dash.platform.dapi.v0.GetDataContractsResponse.DataContractsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc5\x02\n\x1dGetDataContractHistoryRequest\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetDataContractHistoryRequest.GetDataContractHistoryRequestV0H\x00\x1a\xb0\x01\n\x1fGetDataContractHistoryRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12+\n\x05limit\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12,\n\x06offset\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\x17\n\x0bstart_at_ms\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\t\n\x07version\"\xb2\x05\n\x1eGetDataContractHistoryResponse\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetDataContractHistoryResponse.GetDataContractHistoryResponseV0H\x00\x1a\x9a\x04\n GetDataContractHistoryResponseV0\x12\x8f\x01\n\x15\x64\x61ta_contract_history\x18\x01 \x01(\x0b\x32n.org.dash.platform.dapi.v0.GetDataContractHistoryResponse.GetDataContractHistoryResponseV0.DataContractHistoryH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a;\n\x18\x44\x61taContractHistoryEntry\x12\x10\n\x04\x64\x61te\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05value\x18\x02 \x01(\x0c\x1a\xaa\x01\n\x13\x44\x61taContractHistory\x12\x92\x01\n\x15\x64\x61ta_contract_entries\x18\x01 \x03(\x0b\x32s.org.dash.platform.dapi.v0.GetDataContractHistoryResponse.GetDataContractHistoryResponseV0.DataContractHistoryEntryB\x08\n\x06resultB\t\n\x07version\"\xb2\x02\n\x13GetDocumentsRequest\x12R\n\x02v0\x18\x01 \x01(\x0b\x32\x44.org.dash.platform.dapi.v0.GetDocumentsRequest.GetDocumentsRequestV0H\x00\x1a\xbb\x01\n\x15GetDocumentsRequestV0\x12\x18\n\x10\x64\x61ta_contract_id\x18\x01 \x01(\x0c\x12\x15\n\rdocument_type\x18\x02 \x01(\t\x12\r\n\x05where\x18\x03 \x01(\x0c\x12\x10\n\x08order_by\x18\x04 \x01(\x0c\x12\r\n\x05limit\x18\x05 \x01(\r\x12\x15\n\x0bstart_after\x18\x06 \x01(\x0cH\x00\x12\x12\n\x08start_at\x18\x07 \x01(\x0cH\x00\x12\r\n\x05prove\x18\x08 \x01(\x08\x42\x07\n\x05startB\t\n\x07version\"\x95\x03\n\x14GetDocumentsResponse\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetDocumentsResponse.GetDocumentsResponseV0H\x00\x1a\x9b\x02\n\x16GetDocumentsResponseV0\x12\x65\n\tdocuments\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetDocumentsResponse.GetDocumentsResponseV0.DocumentsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1e\n\tDocuments\x12\x11\n\tdocuments\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xed\x01\n!GetIdentityByPublicKeyHashRequest\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashRequest.GetIdentityByPublicKeyHashRequestV0H\x00\x1aM\n#GetIdentityByPublicKeyHashRequestV0\x12\x17\n\x0fpublic_key_hash\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xda\x02\n\"GetIdentityByPublicKeyHashResponse\x12p\n\x02v0\x18\x01 \x01(\x0b\x32\x62.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashResponse.GetIdentityByPublicKeyHashResponseV0H\x00\x1a\xb6\x01\n$GetIdentityByPublicKeyHashResponseV0\x12\x12\n\x08identity\x18\x01 \x01(\x0cH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xbd\x02\n*GetIdentityByNonUniquePublicKeyHashRequest\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashRequest.GetIdentityByNonUniquePublicKeyHashRequestV0H\x00\x1a\x80\x01\n,GetIdentityByNonUniquePublicKeyHashRequestV0\x12\x17\n\x0fpublic_key_hash\x18\x01 \x01(\x0c\x12\x18\n\x0bstart_after\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\x0e\n\x0c_start_afterB\t\n\x07version\"\xd6\x06\n+GetIdentityByNonUniquePublicKeyHashResponse\x12\x82\x01\n\x02v0\x18\x01 \x01(\x0b\x32t.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse.GetIdentityByNonUniquePublicKeyHashResponseV0H\x00\x1a\x96\x05\n-GetIdentityByNonUniquePublicKeyHashResponseV0\x12\x9a\x01\n\x08identity\x18\x01 \x01(\x0b\x32\x85\x01.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse.GetIdentityByNonUniquePublicKeyHashResponseV0.IdentityResponseH\x00\x12\x9d\x01\n\x05proof\x18\x02 \x01(\x0b\x32\x8b\x01.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse.GetIdentityByNonUniquePublicKeyHashResponseV0.IdentityProvedResponseH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x36\n\x10IdentityResponse\x12\x15\n\x08identity\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\x0b\n\t_identity\x1a\xa6\x01\n\x16IdentityProvedResponse\x12P\n&grovedb_identity_public_key_hash_proof\x18\x01 \x01(\x0b\x32 .org.dash.platform.dapi.v0.Proof\x12!\n\x14identity_proof_bytes\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x42\x17\n\x15_identity_proof_bytesB\x08\n\x06resultB\t\n\x07version\"\xfb\x01\n#WaitForStateTransitionResultRequest\x12r\n\x02v0\x18\x01 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.WaitForStateTransitionResultRequest.WaitForStateTransitionResultRequestV0H\x00\x1aU\n%WaitForStateTransitionResultRequestV0\x12\x1d\n\x15state_transition_hash\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x99\x03\n$WaitForStateTransitionResultResponse\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.WaitForStateTransitionResultResponse.WaitForStateTransitionResultResponseV0H\x00\x1a\xef\x01\n&WaitForStateTransitionResultResponseV0\x12I\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x38.org.dash.platform.dapi.v0.StateTransitionBroadcastErrorH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc4\x01\n\x19GetConsensusParamsRequest\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetConsensusParamsRequest.GetConsensusParamsRequestV0H\x00\x1a<\n\x1bGetConsensusParamsRequestV0\x12\x0e\n\x06height\x18\x01 \x01(\x05\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x9c\x04\n\x1aGetConsensusParamsResponse\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetConsensusParamsResponse.GetConsensusParamsResponseV0H\x00\x1aP\n\x14\x43onsensusParamsBlock\x12\x11\n\tmax_bytes\x18\x01 \x01(\t\x12\x0f\n\x07max_gas\x18\x02 \x01(\t\x12\x14\n\x0ctime_iota_ms\x18\x03 \x01(\t\x1a\x62\n\x17\x43onsensusParamsEvidence\x12\x1a\n\x12max_age_num_blocks\x18\x01 \x01(\t\x12\x18\n\x10max_age_duration\x18\x02 \x01(\t\x12\x11\n\tmax_bytes\x18\x03 \x01(\t\x1a\xda\x01\n\x1cGetConsensusParamsResponseV0\x12Y\n\x05\x62lock\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetConsensusParamsResponse.ConsensusParamsBlock\x12_\n\x08\x65vidence\x18\x02 \x01(\x0b\x32M.org.dash.platform.dapi.v0.GetConsensusParamsResponse.ConsensusParamsEvidenceB\t\n\x07version\"\xe4\x01\n%GetProtocolVersionUpgradeStateRequest\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateRequest.GetProtocolVersionUpgradeStateRequestV0H\x00\x1a\x38\n\'GetProtocolVersionUpgradeStateRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xb5\x05\n&GetProtocolVersionUpgradeStateResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse.GetProtocolVersionUpgradeStateResponseV0H\x00\x1a\x85\x04\n(GetProtocolVersionUpgradeStateResponseV0\x12\x87\x01\n\x08versions\x18\x01 \x01(\x0b\x32s.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse.GetProtocolVersionUpgradeStateResponseV0.VersionsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x96\x01\n\x08Versions\x12\x89\x01\n\x08versions\x18\x01 \x03(\x0b\x32w.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse.GetProtocolVersionUpgradeStateResponseV0.VersionEntry\x1a:\n\x0cVersionEntry\x12\x16\n\x0eversion_number\x18\x01 \x01(\r\x12\x12\n\nvote_count\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xa3\x02\n*GetProtocolVersionUpgradeVoteStatusRequest\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusRequest.GetProtocolVersionUpgradeVoteStatusRequestV0H\x00\x1ag\n,GetProtocolVersionUpgradeVoteStatusRequestV0\x12\x19\n\x11start_pro_tx_hash\x18\x01 \x01(\x0c\x12\r\n\x05\x63ount\x18\x02 \x01(\r\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xef\x05\n+GetProtocolVersionUpgradeVoteStatusResponse\x12\x82\x01\n\x02v0\x18\x01 \x01(\x0b\x32t.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse.GetProtocolVersionUpgradeVoteStatusResponseV0H\x00\x1a\xaf\x04\n-GetProtocolVersionUpgradeVoteStatusResponseV0\x12\x98\x01\n\x08versions\x18\x01 \x01(\x0b\x32\x83\x01.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse.GetProtocolVersionUpgradeVoteStatusResponseV0.VersionSignalsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xaf\x01\n\x0eVersionSignals\x12\x9c\x01\n\x0fversion_signals\x18\x01 \x03(\x0b\x32\x82\x01.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse.GetProtocolVersionUpgradeVoteStatusResponseV0.VersionSignal\x1a\x35\n\rVersionSignal\x12\x13\n\x0bpro_tx_hash\x18\x01 \x01(\x0c\x12\x0f\n\x07version\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xf5\x01\n\x14GetEpochsInfoRequest\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetEpochsInfoRequest.GetEpochsInfoRequestV0H\x00\x1a|\n\x16GetEpochsInfoRequestV0\x12\x31\n\x0bstart_epoch\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\r\n\x05\x63ount\x18\x02 \x01(\r\x12\x11\n\tascending\x18\x03 \x01(\x08\x12\r\n\x05prove\x18\x04 \x01(\x08\x42\t\n\x07version\"\x99\x05\n\x15GetEpochsInfoResponse\x12V\n\x02v0\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetEpochsInfoResponse.GetEpochsInfoResponseV0H\x00\x1a\x9c\x04\n\x17GetEpochsInfoResponseV0\x12\x65\n\x06\x65pochs\x18\x01 \x01(\x0b\x32S.org.dash.platform.dapi.v0.GetEpochsInfoResponse.GetEpochsInfoResponseV0.EpochInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1au\n\nEpochInfos\x12g\n\x0b\x65poch_infos\x18\x01 \x03(\x0b\x32R.org.dash.platform.dapi.v0.GetEpochsInfoResponse.GetEpochsInfoResponseV0.EpochInfo\x1a\xa6\x01\n\tEpochInfo\x12\x0e\n\x06number\x18\x01 \x01(\r\x12\x1e\n\x12\x66irst_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x1f\n\x17\x66irst_core_block_height\x18\x03 \x01(\r\x12\x16\n\nstart_time\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x16\n\x0e\x66\x65\x65_multiplier\x18\x05 \x01(\x01\x12\x18\n\x10protocol_version\x18\x06 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xbf\x02\n\x1dGetFinalizedEpochInfosRequest\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetFinalizedEpochInfosRequest.GetFinalizedEpochInfosRequestV0H\x00\x1a\xaa\x01\n\x1fGetFinalizedEpochInfosRequestV0\x12\x19\n\x11start_epoch_index\x18\x01 \x01(\r\x12\"\n\x1astart_epoch_index_included\x18\x02 \x01(\x08\x12\x17\n\x0f\x65nd_epoch_index\x18\x03 \x01(\r\x12 \n\x18\x65nd_epoch_index_included\x18\x04 \x01(\x08\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\t\n\x07version\"\xbd\t\n\x1eGetFinalizedEpochInfosResponse\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0H\x00\x1a\xa5\x08\n GetFinalizedEpochInfosResponseV0\x12\x80\x01\n\x06\x65pochs\x18\x01 \x01(\x0b\x32n.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0.FinalizedEpochInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xa4\x01\n\x13\x46inalizedEpochInfos\x12\x8c\x01\n\x15\x66inalized_epoch_infos\x18\x01 \x03(\x0b\x32m.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0.FinalizedEpochInfo\x1a\x9f\x04\n\x12\x46inalizedEpochInfo\x12\x0e\n\x06number\x18\x01 \x01(\r\x12\x1e\n\x12\x66irst_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x1f\n\x17\x66irst_core_block_height\x18\x03 \x01(\r\x12\x1c\n\x10\x66irst_block_time\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x16\n\x0e\x66\x65\x65_multiplier\x18\x05 \x01(\x01\x12\x18\n\x10protocol_version\x18\x06 \x01(\r\x12!\n\x15total_blocks_in_epoch\x18\x07 \x01(\x04\x42\x02\x30\x01\x12*\n\"next_epoch_start_core_block_height\x18\x08 \x01(\r\x12!\n\x15total_processing_fees\x18\t \x01(\x04\x42\x02\x30\x01\x12*\n\x1etotal_distributed_storage_fees\x18\n \x01(\x04\x42\x02\x30\x01\x12&\n\x1atotal_created_storage_fees\x18\x0b \x01(\x04\x42\x02\x30\x01\x12\x1e\n\x12\x63ore_block_rewards\x18\x0c \x01(\x04\x42\x02\x30\x01\x12\x81\x01\n\x0f\x62lock_proposers\x18\r \x03(\x0b\x32h.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0.BlockProposer\x1a\x39\n\rBlockProposer\x12\x13\n\x0bproposer_id\x18\x01 \x01(\x0c\x12\x13\n\x0b\x62lock_count\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xde\x04\n\x1cGetContestedResourcesRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetContestedResourcesRequest.GetContestedResourcesRequestV0H\x00\x1a\xcc\x03\n\x1eGetContestedResourcesRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\x12\n\nindex_name\x18\x03 \x01(\t\x12\x1a\n\x12start_index_values\x18\x04 \x03(\x0c\x12\x18\n\x10\x65nd_index_values\x18\x05 \x03(\x0c\x12\x89\x01\n\x13start_at_value_info\x18\x06 \x01(\x0b\x32g.org.dash.platform.dapi.v0.GetContestedResourcesRequest.GetContestedResourcesRequestV0.StartAtValueInfoH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x07 \x01(\rH\x01\x88\x01\x01\x12\x17\n\x0forder_ascending\x18\x08 \x01(\x08\x12\r\n\x05prove\x18\t \x01(\x08\x1a\x45\n\x10StartAtValueInfo\x12\x13\n\x0bstart_value\x18\x01 \x01(\x0c\x12\x1c\n\x14start_value_included\x18\x02 \x01(\x08\x42\x16\n\x14_start_at_value_infoB\x08\n\x06_countB\t\n\x07version\"\x88\x04\n\x1dGetContestedResourcesResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetContestedResourcesResponse.GetContestedResourcesResponseV0H\x00\x1a\xf3\x02\n\x1fGetContestedResourcesResponseV0\x12\x95\x01\n\x19\x63ontested_resource_values\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetContestedResourcesResponse.GetContestedResourcesResponseV0.ContestedResourceValuesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a<\n\x17\x43ontestedResourceValues\x12!\n\x19\x63ontested_resource_values\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xd2\x05\n\x1cGetVotePollsByEndDateRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest.GetVotePollsByEndDateRequestV0H\x00\x1a\xc0\x04\n\x1eGetVotePollsByEndDateRequestV0\x12\x84\x01\n\x0fstart_time_info\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest.GetVotePollsByEndDateRequestV0.StartAtTimeInfoH\x00\x88\x01\x01\x12\x80\x01\n\rend_time_info\x18\x02 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest.GetVotePollsByEndDateRequestV0.EndAtTimeInfoH\x01\x88\x01\x01\x12\x12\n\x05limit\x18\x03 \x01(\rH\x02\x88\x01\x01\x12\x13\n\x06offset\x18\x04 \x01(\rH\x03\x88\x01\x01\x12\x11\n\tascending\x18\x05 \x01(\x08\x12\r\n\x05prove\x18\x06 \x01(\x08\x1aI\n\x0fStartAtTimeInfo\x12\x19\n\rstart_time_ms\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1b\n\x13start_time_included\x18\x02 \x01(\x08\x1a\x43\n\rEndAtTimeInfo\x12\x17\n\x0b\x65nd_time_ms\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x19\n\x11\x65nd_time_included\x18\x02 \x01(\x08\x42\x12\n\x10_start_time_infoB\x10\n\x0e_end_time_infoB\x08\n\x06_limitB\t\n\x07_offsetB\t\n\x07version\"\x83\x06\n\x1dGetVotePollsByEndDateResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse.GetVotePollsByEndDateResponseV0H\x00\x1a\xee\x04\n\x1fGetVotePollsByEndDateResponseV0\x12\x9c\x01\n\x18vote_polls_by_timestamps\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse.GetVotePollsByEndDateResponseV0.SerializedVotePollsByTimestampsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aV\n\x1eSerializedVotePollsByTimestamp\x12\x15\n\ttimestamp\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1d\n\x15serialized_vote_polls\x18\x02 \x03(\x0c\x1a\xd7\x01\n\x1fSerializedVotePollsByTimestamps\x12\x99\x01\n\x18vote_polls_by_timestamps\x18\x01 \x03(\x0b\x32w.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse.GetVotePollsByEndDateResponseV0.SerializedVotePollsByTimestamp\x12\x18\n\x10\x66inished_results\x18\x02 \x01(\x08\x42\x08\n\x06resultB\t\n\x07version\"\xff\x06\n$GetContestedResourceVoteStateRequest\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest.GetContestedResourceVoteStateRequestV0H\x00\x1a\xd5\x05\n&GetContestedResourceVoteStateRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\x12\n\nindex_name\x18\x03 \x01(\t\x12\x14\n\x0cindex_values\x18\x04 \x03(\x0c\x12\x86\x01\n\x0bresult_type\x18\x05 \x01(\x0e\x32q.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest.GetContestedResourceVoteStateRequestV0.ResultType\x12\x36\n.allow_include_locked_and_abstaining_vote_tally\x18\x06 \x01(\x08\x12\xa3\x01\n\x18start_at_identifier_info\x18\x07 \x01(\x0b\x32|.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest.GetContestedResourceVoteStateRequestV0.StartAtIdentifierInfoH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x08 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\t \x01(\x08\x1aT\n\x15StartAtIdentifierInfo\x12\x18\n\x10start_identifier\x18\x01 \x01(\x0c\x12!\n\x19start_identifier_included\x18\x02 \x01(\x08\"I\n\nResultType\x12\r\n\tDOCUMENTS\x10\x00\x12\x0e\n\nVOTE_TALLY\x10\x01\x12\x1c\n\x18\x44OCUMENTS_AND_VOTE_TALLY\x10\x02\x42\x1b\n\x19_start_at_identifier_infoB\x08\n\x06_countB\t\n\x07version\"\x94\x0c\n%GetContestedResourceVoteStateResponse\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0H\x00\x1a\xe7\n\n\'GetContestedResourceVoteStateResponseV0\x12\xae\x01\n\x1d\x63ontested_resource_contenders\x18\x01 \x01(\x0b\x32\x84\x01.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.ContestedResourceContendersH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xda\x03\n\x10\x46inishedVoteInfo\x12\xad\x01\n\x15\x66inished_vote_outcome\x18\x01 \x01(\x0e\x32\x8d\x01.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.FinishedVoteInfo.FinishedVoteOutcome\x12\x1f\n\x12won_by_identity_id\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12$\n\x18\x66inished_at_block_height\x18\x03 \x01(\x04\x42\x02\x30\x01\x12%\n\x1d\x66inished_at_core_block_height\x18\x04 \x01(\r\x12%\n\x19\x66inished_at_block_time_ms\x18\x05 \x01(\x04\x42\x02\x30\x01\x12\x19\n\x11\x66inished_at_epoch\x18\x06 \x01(\r\"O\n\x13\x46inishedVoteOutcome\x12\x14\n\x10TOWARDS_IDENTITY\x10\x00\x12\n\n\x06LOCKED\x10\x01\x12\x16\n\x12NO_PREVIOUS_WINNER\x10\x02\x42\x15\n\x13_won_by_identity_id\x1a\xc4\x03\n\x1b\x43ontestedResourceContenders\x12\x86\x01\n\ncontenders\x18\x01 \x03(\x0b\x32r.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.Contender\x12\x1f\n\x12\x61\x62stain_vote_tally\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x1c\n\x0flock_vote_tally\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x9a\x01\n\x12\x66inished_vote_info\x18\x04 \x01(\x0b\x32y.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.FinishedVoteInfoH\x02\x88\x01\x01\x42\x15\n\x13_abstain_vote_tallyB\x12\n\x10_lock_vote_tallyB\x15\n\x13_finished_vote_info\x1ak\n\tContender\x12\x12\n\nidentifier\x18\x01 \x01(\x0c\x12\x17\n\nvote_count\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x15\n\x08\x64ocument\x18\x03 \x01(\x0cH\x01\x88\x01\x01\x42\r\n\x0b_vote_countB\x0b\n\t_documentB\x08\n\x06resultB\t\n\x07version\"\xd5\x05\n,GetContestedResourceVotersForIdentityRequest\x12\x84\x01\n\x02v0\x18\x01 \x01(\x0b\x32v.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityRequest.GetContestedResourceVotersForIdentityRequestV0H\x00\x1a\x92\x04\n.GetContestedResourceVotersForIdentityRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\x12\n\nindex_name\x18\x03 \x01(\t\x12\x14\n\x0cindex_values\x18\x04 \x03(\x0c\x12\x15\n\rcontestant_id\x18\x05 \x01(\x0c\x12\xb4\x01\n\x18start_at_identifier_info\x18\x06 \x01(\x0b\x32\x8c\x01.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityRequest.GetContestedResourceVotersForIdentityRequestV0.StartAtIdentifierInfoH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x07 \x01(\rH\x01\x88\x01\x01\x12\x17\n\x0forder_ascending\x18\x08 \x01(\x08\x12\r\n\x05prove\x18\t \x01(\x08\x1aT\n\x15StartAtIdentifierInfo\x12\x18\n\x10start_identifier\x18\x01 \x01(\x0c\x12!\n\x19start_identifier_included\x18\x02 \x01(\x08\x42\x1b\n\x19_start_at_identifier_infoB\x08\n\x06_countB\t\n\x07version\"\xf1\x04\n-GetContestedResourceVotersForIdentityResponse\x12\x86\x01\n\x02v0\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityResponse.GetContestedResourceVotersForIdentityResponseV0H\x00\x1a\xab\x03\n/GetContestedResourceVotersForIdentityResponseV0\x12\xb6\x01\n\x19\x63ontested_resource_voters\x18\x01 \x01(\x0b\x32\x90\x01.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityResponse.GetContestedResourceVotersForIdentityResponseV0.ContestedResourceVotersH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x43\n\x17\x43ontestedResourceVoters\x12\x0e\n\x06voters\x18\x01 \x03(\x0c\x12\x18\n\x10\x66inished_results\x18\x02 \x01(\x08\x42\x08\n\x06resultB\t\n\x07version\"\xad\x05\n(GetContestedResourceIdentityVotesRequest\x12|\n\x02v0\x18\x01 \x01(\x0b\x32n.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesRequest.GetContestedResourceIdentityVotesRequestV0H\x00\x1a\xf7\x03\n*GetContestedResourceIdentityVotesRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12+\n\x05limit\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12,\n\x06offset\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\x17\n\x0forder_ascending\x18\x04 \x01(\x08\x12\xae\x01\n\x1astart_at_vote_poll_id_info\x18\x05 \x01(\x0b\x32\x84\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesRequest.GetContestedResourceIdentityVotesRequestV0.StartAtVotePollIdInfoH\x00\x88\x01\x01\x12\r\n\x05prove\x18\x06 \x01(\x08\x1a\x61\n\x15StartAtVotePollIdInfo\x12 \n\x18start_at_poll_identifier\x18\x01 \x01(\x0c\x12&\n\x1estart_poll_identifier_included\x18\x02 \x01(\x08\x42\x1d\n\x1b_start_at_vote_poll_id_infoB\t\n\x07version\"\xc8\n\n)GetContestedResourceIdentityVotesResponse\x12~\n\x02v0\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0H\x00\x1a\x8f\t\n+GetContestedResourceIdentityVotesResponseV0\x12\xa1\x01\n\x05votes\x18\x01 \x01(\x0b\x32\x8f\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ContestedResourceIdentityVotesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xf7\x01\n\x1e\x43ontestedResourceIdentityVotes\x12\xba\x01\n!contested_resource_identity_votes\x18\x01 \x03(\x0b\x32\x8e\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ContestedResourceIdentityVote\x12\x18\n\x10\x66inished_results\x18\x02 \x01(\x08\x1a\xad\x02\n\x12ResourceVoteChoice\x12\xad\x01\n\x10vote_choice_type\x18\x01 \x01(\x0e\x32\x92\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ResourceVoteChoice.VoteChoiceType\x12\x18\n\x0bidentity_id\x18\x02 \x01(\x0cH\x00\x88\x01\x01\"=\n\x0eVoteChoiceType\x12\x14\n\x10TOWARDS_IDENTITY\x10\x00\x12\x0b\n\x07\x41\x42STAIN\x10\x01\x12\x08\n\x04LOCK\x10\x02\x42\x0e\n\x0c_identity_id\x1a\x95\x02\n\x1d\x43ontestedResourceIdentityVote\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\'\n\x1fserialized_index_storage_values\x18\x03 \x03(\x0c\x12\x99\x01\n\x0bvote_choice\x18\x04 \x01(\x0b\x32\x83\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ResourceVoteChoiceB\x08\n\x06resultB\t\n\x07version\"\xf0\x01\n%GetPrefundedSpecializedBalanceRequest\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceRequest.GetPrefundedSpecializedBalanceRequestV0H\x00\x1a\x44\n\'GetPrefundedSpecializedBalanceRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xed\x02\n&GetPrefundedSpecializedBalanceResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceResponse.GetPrefundedSpecializedBalanceResponseV0H\x00\x1a\xbd\x01\n(GetPrefundedSpecializedBalanceResponseV0\x12\x15\n\x07\x62\x61lance\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xd0\x01\n GetTotalCreditsInPlatformRequest\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformRequest.GetTotalCreditsInPlatformRequestV0H\x00\x1a\x33\n\"GetTotalCreditsInPlatformRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xd9\x02\n!GetTotalCreditsInPlatformResponse\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformResponse.GetTotalCreditsInPlatformResponseV0H\x00\x1a\xb8\x01\n#GetTotalCreditsInPlatformResponseV0\x12\x15\n\x07\x63redits\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc4\x01\n\x16GetPathElementsRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetPathElementsRequest.GetPathElementsRequestV0H\x00\x1a\x45\n\x18GetPathElementsRequestV0\x12\x0c\n\x04path\x18\x01 \x03(\x0c\x12\x0c\n\x04keys\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xa3\x03\n\x17GetPathElementsResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetPathElementsResponse.GetPathElementsResponseV0H\x00\x1a\xa0\x02\n\x19GetPathElementsResponseV0\x12i\n\x08\x65lements\x18\x01 \x01(\x0b\x32U.org.dash.platform.dapi.v0.GetPathElementsResponse.GetPathElementsResponseV0.ElementsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1c\n\x08\x45lements\x12\x10\n\x08\x65lements\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\x81\x01\n\x10GetStatusRequest\x12L\n\x02v0\x18\x01 \x01(\x0b\x32>.org.dash.platform.dapi.v0.GetStatusRequest.GetStatusRequestV0H\x00\x1a\x14\n\x12GetStatusRequestV0B\t\n\x07version\"\xe4\x10\n\x11GetStatusResponse\x12N\n\x02v0\x18\x01 \x01(\x0b\x32@.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0H\x00\x1a\xf3\x0f\n\x13GetStatusResponseV0\x12Y\n\x07version\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version\x12S\n\x04node\x18\x02 \x01(\x0b\x32\x45.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Node\x12U\n\x05\x63hain\x18\x03 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Chain\x12Y\n\x07network\x18\x04 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Network\x12^\n\nstate_sync\x18\x05 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.StateSync\x12S\n\x04time\x18\x06 \x01(\x0b\x32\x45.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Time\x1a\x82\x05\n\x07Version\x12\x63\n\x08software\x18\x01 \x01(\x0b\x32Q.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Software\x12\x63\n\x08protocol\x18\x02 \x01(\x0b\x32Q.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Protocol\x1a^\n\x08Software\x12\x0c\n\x04\x64\x61pi\x18\x01 \x01(\t\x12\x12\n\x05\x64rive\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x17\n\ntenderdash\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_driveB\r\n\x0b_tenderdash\x1a\xcc\x02\n\x08Protocol\x12p\n\ntenderdash\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Protocol.Tenderdash\x12\x66\n\x05\x64rive\x18\x02 \x01(\x0b\x32W.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Protocol.Drive\x1a(\n\nTenderdash\x12\x0b\n\x03p2p\x18\x01 \x01(\r\x12\r\n\x05\x62lock\x18\x02 \x01(\r\x1a<\n\x05\x44rive\x12\x0e\n\x06latest\x18\x03 \x01(\r\x12\x0f\n\x07\x63urrent\x18\x04 \x01(\r\x12\x12\n\nnext_epoch\x18\x05 \x01(\r\x1a\x7f\n\x04Time\x12\x11\n\x05local\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x16\n\x05\x62lock\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x88\x01\x01\x12\x18\n\x07genesis\x18\x03 \x01(\x04\x42\x02\x30\x01H\x01\x88\x01\x01\x12\x12\n\x05\x65poch\x18\x04 \x01(\rH\x02\x88\x01\x01\x42\x08\n\x06_blockB\n\n\x08_genesisB\x08\n\x06_epoch\x1a<\n\x04Node\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x18\n\x0bpro_tx_hash\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x42\x0e\n\x0c_pro_tx_hash\x1a\xb3\x02\n\x05\x43hain\x12\x13\n\x0b\x63\x61tching_up\x18\x01 \x01(\x08\x12\x19\n\x11latest_block_hash\x18\x02 \x01(\x0c\x12\x17\n\x0flatest_app_hash\x18\x03 \x01(\x0c\x12\x1f\n\x13latest_block_height\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x1b\n\x13\x65\x61rliest_block_hash\x18\x05 \x01(\x0c\x12\x19\n\x11\x65\x61rliest_app_hash\x18\x06 \x01(\x0c\x12!\n\x15\x65\x61rliest_block_height\x18\x07 \x01(\x04\x42\x02\x30\x01\x12!\n\x15max_peer_block_height\x18\t \x01(\x04\x42\x02\x30\x01\x12%\n\x18\x63ore_chain_locked_height\x18\n \x01(\rH\x00\x88\x01\x01\x42\x1b\n\x19_core_chain_locked_height\x1a\x43\n\x07Network\x12\x10\n\x08\x63hain_id\x18\x01 \x01(\t\x12\x13\n\x0bpeers_count\x18\x02 \x01(\r\x12\x11\n\tlistening\x18\x03 \x01(\x08\x1a\x85\x02\n\tStateSync\x12\x1d\n\x11total_synced_time\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1a\n\x0eremaining_time\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x17\n\x0ftotal_snapshots\x18\x03 \x01(\r\x12\"\n\x16\x63hunk_process_avg_time\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x1b\n\x0fsnapshot_height\x18\x05 \x01(\x04\x42\x02\x30\x01\x12!\n\x15snapshot_chunks_count\x18\x06 \x01(\x04\x42\x02\x30\x01\x12\x1d\n\x11\x62\x61\x63kfilled_blocks\x18\x07 \x01(\x04\x42\x02\x30\x01\x12!\n\x15\x62\x61\x63kfill_blocks_total\x18\x08 \x01(\x04\x42\x02\x30\x01\x42\t\n\x07version\"\xb1\x01\n\x1cGetCurrentQuorumsInfoRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoRequest.GetCurrentQuorumsInfoRequestV0H\x00\x1a \n\x1eGetCurrentQuorumsInfoRequestV0B\t\n\x07version\"\xa1\x05\n\x1dGetCurrentQuorumsInfoResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse.GetCurrentQuorumsInfoResponseV0H\x00\x1a\x46\n\x0bValidatorV0\x12\x13\n\x0bpro_tx_hash\x18\x01 \x01(\x0c\x12\x0f\n\x07node_ip\x18\x02 \x01(\t\x12\x11\n\tis_banned\x18\x03 \x01(\x08\x1a\xaf\x01\n\x0eValidatorSetV0\x12\x13\n\x0bquorum_hash\x18\x01 \x01(\x0c\x12\x13\n\x0b\x63ore_height\x18\x02 \x01(\r\x12U\n\x07members\x18\x03 \x03(\x0b\x32\x44.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse.ValidatorV0\x12\x1c\n\x14threshold_public_key\x18\x04 \x01(\x0c\x1a\x92\x02\n\x1fGetCurrentQuorumsInfoResponseV0\x12\x15\n\rquorum_hashes\x18\x01 \x03(\x0c\x12\x1b\n\x13\x63urrent_quorum_hash\x18\x02 \x01(\x0c\x12_\n\x0evalidator_sets\x18\x03 \x03(\x0b\x32G.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse.ValidatorSetV0\x12\x1b\n\x13last_block_proposer\x18\x04 \x01(\x0c\x12=\n\x08metadata\x18\x05 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\t\n\x07version\"\xf4\x01\n\x1fGetIdentityTokenBalancesRequest\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetIdentityTokenBalancesRequest.GetIdentityTokenBalancesRequestV0H\x00\x1aZ\n!GetIdentityTokenBalancesRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x11\n\ttoken_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xad\x05\n GetIdentityTokenBalancesResponse\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse.GetIdentityTokenBalancesResponseV0H\x00\x1a\x8f\x04\n\"GetIdentityTokenBalancesResponseV0\x12\x86\x01\n\x0etoken_balances\x18\x01 \x01(\x0b\x32l.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse.GetIdentityTokenBalancesResponseV0.TokenBalancesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aG\n\x11TokenBalanceEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x14\n\x07\x62\x61lance\x18\x02 \x01(\x04H\x00\x88\x01\x01\x42\n\n\x08_balance\x1a\x9a\x01\n\rTokenBalances\x12\x88\x01\n\x0etoken_balances\x18\x01 \x03(\x0b\x32p.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse.GetIdentityTokenBalancesResponseV0.TokenBalanceEntryB\x08\n\x06resultB\t\n\x07version\"\xfc\x01\n!GetIdentitiesTokenBalancesRequest\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesRequest.GetIdentitiesTokenBalancesRequestV0H\x00\x1a\\\n#GetIdentitiesTokenBalancesRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x14\n\x0cidentity_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xf2\x05\n\"GetIdentitiesTokenBalancesResponse\x12p\n\x02v0\x18\x01 \x01(\x0b\x32\x62.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse.GetIdentitiesTokenBalancesResponseV0H\x00\x1a\xce\x04\n$GetIdentitiesTokenBalancesResponseV0\x12\x9b\x01\n\x17identity_token_balances\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse.GetIdentitiesTokenBalancesResponseV0.IdentityTokenBalancesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aR\n\x19IdentityTokenBalanceEntry\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x14\n\x07\x62\x61lance\x18\x02 \x01(\x04H\x00\x88\x01\x01\x42\n\n\x08_balance\x1a\xb7\x01\n\x15IdentityTokenBalances\x12\x9d\x01\n\x17identity_token_balances\x18\x01 \x03(\x0b\x32|.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse.GetIdentitiesTokenBalancesResponseV0.IdentityTokenBalanceEntryB\x08\n\x06resultB\t\n\x07version\"\xe8\x01\n\x1cGetIdentityTokenInfosRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetIdentityTokenInfosRequest.GetIdentityTokenInfosRequestV0H\x00\x1aW\n\x1eGetIdentityTokenInfosRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x11\n\ttoken_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\x98\x06\n\x1dGetIdentityTokenInfosResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0H\x00\x1a\x83\x05\n\x1fGetIdentityTokenInfosResponseV0\x12z\n\x0btoken_infos\x18\x01 \x01(\x0b\x32\x63.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a(\n\x16TokenIdentityInfoEntry\x12\x0e\n\x06\x66rozen\x18\x01 \x01(\x08\x1a\xb0\x01\n\x0eTokenInfoEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x82\x01\n\x04info\x18\x02 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenIdentityInfoEntryH\x00\x88\x01\x01\x42\x07\n\x05_info\x1a\x8a\x01\n\nTokenInfos\x12|\n\x0btoken_infos\x18\x01 \x03(\x0b\x32g.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenInfoEntryB\x08\n\x06resultB\t\n\x07version\"\xf0\x01\n\x1eGetIdentitiesTokenInfosRequest\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosRequest.GetIdentitiesTokenInfosRequestV0H\x00\x1aY\n GetIdentitiesTokenInfosRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x14\n\x0cidentity_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xca\x06\n\x1fGetIdentitiesTokenInfosResponse\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0H\x00\x1a\xaf\x05\n!GetIdentitiesTokenInfosResponseV0\x12\x8f\x01\n\x14identity_token_infos\x18\x01 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0.IdentityTokenInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a(\n\x16TokenIdentityInfoEntry\x12\x0e\n\x06\x66rozen\x18\x01 \x01(\x08\x1a\xb7\x01\n\x0eTokenInfoEntry\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x86\x01\n\x04info\x18\x02 \x01(\x0b\x32s.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0.TokenIdentityInfoEntryH\x00\x88\x01\x01\x42\x07\n\x05_info\x1a\x97\x01\n\x12IdentityTokenInfos\x12\x80\x01\n\x0btoken_infos\x18\x01 \x03(\x0b\x32k.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0.TokenInfoEntryB\x08\n\x06resultB\t\n\x07version\"\xbf\x01\n\x17GetTokenStatusesRequest\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetTokenStatusesRequest.GetTokenStatusesRequestV0H\x00\x1a=\n\x19GetTokenStatusesRequestV0\x12\x11\n\ttoken_ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xe7\x04\n\x18GetTokenStatusesResponse\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetTokenStatusesResponse.GetTokenStatusesResponseV0H\x00\x1a\xe1\x03\n\x1aGetTokenStatusesResponseV0\x12v\n\x0etoken_statuses\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetTokenStatusesResponse.GetTokenStatusesResponseV0.TokenStatusesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x44\n\x10TokenStatusEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x13\n\x06paused\x18\x02 \x01(\x08H\x00\x88\x01\x01\x42\t\n\x07_paused\x1a\x88\x01\n\rTokenStatuses\x12w\n\x0etoken_statuses\x18\x01 \x03(\x0b\x32_.org.dash.platform.dapi.v0.GetTokenStatusesResponse.GetTokenStatusesResponseV0.TokenStatusEntryB\x08\n\x06resultB\t\n\x07version\"\xef\x01\n#GetTokenDirectPurchasePricesRequest\x12r\n\x02v0\x18\x01 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesRequest.GetTokenDirectPurchasePricesRequestV0H\x00\x1aI\n%GetTokenDirectPurchasePricesRequestV0\x12\x11\n\ttoken_ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x8b\t\n$GetTokenDirectPurchasePricesResponse\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0H\x00\x1a\xe1\x07\n&GetTokenDirectPurchasePricesResponseV0\x12\xa9\x01\n\x1ctoken_direct_purchase_prices\x18\x01 \x01(\x0b\x32\x80\x01.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.TokenDirectPurchasePricesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x33\n\x10PriceForQuantity\x12\x10\n\x08quantity\x18\x01 \x01(\x04\x12\r\n\x05price\x18\x02 \x01(\x04\x1a\xa7\x01\n\x0fPricingSchedule\x12\x93\x01\n\x12price_for_quantity\x18\x01 \x03(\x0b\x32w.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.PriceForQuantity\x1a\xe4\x01\n\x1dTokenDirectPurchasePriceEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x15\n\x0b\x66ixed_price\x18\x02 \x01(\x04H\x00\x12\x90\x01\n\x0evariable_price\x18\x03 \x01(\x0b\x32v.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.PricingScheduleH\x00\x42\x07\n\x05price\x1a\xc8\x01\n\x19TokenDirectPurchasePrices\x12\xaa\x01\n\x1btoken_direct_purchase_price\x18\x01 \x03(\x0b\x32\x84\x01.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.TokenDirectPurchasePriceEntryB\x08\n\x06resultB\t\n\x07version\"\xce\x01\n\x1bGetTokenContractInfoRequest\x12\x62\n\x02v0\x18\x01 \x01(\x0b\x32T.org.dash.platform.dapi.v0.GetTokenContractInfoRequest.GetTokenContractInfoRequestV0H\x00\x1a@\n\x1dGetTokenContractInfoRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xfb\x03\n\x1cGetTokenContractInfoResponse\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetTokenContractInfoResponse.GetTokenContractInfoResponseV0H\x00\x1a\xe9\x02\n\x1eGetTokenContractInfoResponseV0\x12|\n\x04\x64\x61ta\x18\x01 \x01(\x0b\x32l.org.dash.platform.dapi.v0.GetTokenContractInfoResponse.GetTokenContractInfoResponseV0.TokenContractInfoDataH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aM\n\x15TokenContractInfoData\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17token_contract_position\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xef\x04\n)GetTokenPreProgrammedDistributionsRequest\x12~\n\x02v0\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsRequest.GetTokenPreProgrammedDistributionsRequestV0H\x00\x1a\xb6\x03\n+GetTokenPreProgrammedDistributionsRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x98\x01\n\rstart_at_info\x18\x02 \x01(\x0b\x32|.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsRequest.GetTokenPreProgrammedDistributionsRequestV0.StartAtInfoH\x00\x88\x01\x01\x12\x12\n\x05limit\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\x04 \x01(\x08\x1a\x9a\x01\n\x0bStartAtInfo\x12\x15\n\rstart_time_ms\x18\x01 \x01(\x04\x12\x1c\n\x0fstart_recipient\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12%\n\x18start_recipient_included\x18\x03 \x01(\x08H\x01\x88\x01\x01\x42\x12\n\x10_start_recipientB\x1b\n\x19_start_recipient_includedB\x10\n\x0e_start_at_infoB\x08\n\x06_limitB\t\n\x07version\"\xec\x07\n*GetTokenPreProgrammedDistributionsResponse\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0H\x00\x1a\xaf\x06\n,GetTokenPreProgrammedDistributionsResponseV0\x12\xa5\x01\n\x13token_distributions\x18\x01 \x01(\x0b\x32\x85\x01.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0.TokenDistributionsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a>\n\x16TokenDistributionEntry\x12\x14\n\x0crecipient_id\x18\x01 \x01(\x0c\x12\x0e\n\x06\x61mount\x18\x02 \x01(\x04\x1a\xd4\x01\n\x1bTokenTimedDistributionEntry\x12\x11\n\ttimestamp\x18\x01 \x01(\x04\x12\xa1\x01\n\rdistributions\x18\x02 \x03(\x0b\x32\x89\x01.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0.TokenDistributionEntry\x1a\xc3\x01\n\x12TokenDistributions\x12\xac\x01\n\x13token_distributions\x18\x01 \x03(\x0b\x32\x8e\x01.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0.TokenTimedDistributionEntryB\x08\n\x06resultB\t\n\x07version\"\x82\x04\n-GetTokenPerpetualDistributionLastClaimRequest\x12\x86\x01\n\x02v0\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimRequest.GetTokenPerpetualDistributionLastClaimRequestV0H\x00\x1aI\n\x11\x43ontractTokenInfo\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17token_contract_position\x18\x02 \x01(\r\x1a\xf1\x01\n/GetTokenPerpetualDistributionLastClaimRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12v\n\rcontract_info\x18\x02 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimRequest.ContractTokenInfoH\x00\x88\x01\x01\x12\x13\n\x0bidentity_id\x18\x04 \x01(\x0c\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\x10\n\x0e_contract_infoB\t\n\x07version\"\x93\x05\n.GetTokenPerpetualDistributionLastClaimResponse\x12\x88\x01\n\x02v0\x18\x01 \x01(\x0b\x32z.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimResponse.GetTokenPerpetualDistributionLastClaimResponseV0H\x00\x1a\xca\x03\n0GetTokenPerpetualDistributionLastClaimResponseV0\x12\x9f\x01\n\nlast_claim\x18\x01 \x01(\x0b\x32\x88\x01.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimResponse.GetTokenPerpetualDistributionLastClaimResponseV0.LastClaimInfoH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1ax\n\rLastClaimInfo\x12\x1a\n\x0ctimestamp_ms\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x1a\n\x0c\x62lock_height\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x12\x0f\n\x05\x65poch\x18\x03 \x01(\rH\x00\x12\x13\n\traw_bytes\x18\x04 \x01(\x0cH\x00\x42\t\n\x07paid_atB\x08\n\x06resultB\t\n\x07version\"\xca\x01\n\x1aGetTokenTotalSupplyRequest\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetTokenTotalSupplyRequest.GetTokenTotalSupplyRequestV0H\x00\x1a?\n\x1cGetTokenTotalSupplyRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xaf\x04\n\x1bGetTokenTotalSupplyResponse\x12\x62\n\x02v0\x18\x01 \x01(\x0b\x32T.org.dash.platform.dapi.v0.GetTokenTotalSupplyResponse.GetTokenTotalSupplyResponseV0H\x00\x1a\xa0\x03\n\x1dGetTokenTotalSupplyResponseV0\x12\x88\x01\n\x12token_total_supply\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetTokenTotalSupplyResponse.GetTokenTotalSupplyResponseV0.TokenTotalSupplyEntryH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1ax\n\x15TokenTotalSupplyEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x30\n(total_aggregated_amount_in_user_accounts\x18\x02 \x01(\x04\x12\x1b\n\x13total_system_amount\x18\x03 \x01(\x04\x42\x08\n\x06resultB\t\n\x07version\"\xd2\x01\n\x13GetGroupInfoRequest\x12R\n\x02v0\x18\x01 \x01(\x0b\x32\x44.org.dash.platform.dapi.v0.GetGroupInfoRequest.GetGroupInfoRequestV0H\x00\x1a\\\n\x15GetGroupInfoRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17group_contract_position\x18\x02 \x01(\r\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xd4\x05\n\x14GetGroupInfoResponse\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0H\x00\x1a\xda\x04\n\x16GetGroupInfoResponseV0\x12\x66\n\ngroup_info\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0.GroupInfoH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x04 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x34\n\x10GroupMemberEntry\x12\x11\n\tmember_id\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x02 \x01(\r\x1a\x98\x01\n\x0eGroupInfoEntry\x12h\n\x07members\x18\x01 \x03(\x0b\x32W.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0.GroupMemberEntry\x12\x1c\n\x14group_required_power\x18\x02 \x01(\r\x1a\x8a\x01\n\tGroupInfo\x12n\n\ngroup_info\x18\x01 \x01(\x0b\x32U.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0.GroupInfoEntryH\x00\x88\x01\x01\x42\r\n\x0b_group_infoB\x08\n\x06resultB\t\n\x07version\"\xed\x03\n\x14GetGroupInfosRequest\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetGroupInfosRequest.GetGroupInfosRequestV0H\x00\x1au\n\x1cStartAtGroupContractPosition\x12%\n\x1dstart_group_contract_position\x18\x01 \x01(\r\x12.\n&start_group_contract_position_included\x18\x02 \x01(\x08\x1a\xfc\x01\n\x16GetGroupInfosRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12{\n start_at_group_contract_position\x18\x02 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetGroupInfosRequest.StartAtGroupContractPositionH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\x04 \x01(\x08\x42#\n!_start_at_group_contract_positionB\x08\n\x06_countB\t\n\x07version\"\xff\x05\n\x15GetGroupInfosResponse\x12V\n\x02v0\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0H\x00\x1a\x82\x05\n\x17GetGroupInfosResponseV0\x12j\n\x0bgroup_infos\x18\x01 \x01(\x0b\x32S.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0.GroupInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x04 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x34\n\x10GroupMemberEntry\x12\x11\n\tmember_id\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x02 \x01(\r\x1a\xc3\x01\n\x16GroupPositionInfoEntry\x12\x1f\n\x17group_contract_position\x18\x01 \x01(\r\x12j\n\x07members\x18\x02 \x03(\x0b\x32Y.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0.GroupMemberEntry\x12\x1c\n\x14group_required_power\x18\x03 \x01(\r\x1a\x82\x01\n\nGroupInfos\x12t\n\x0bgroup_infos\x18\x01 \x03(\x0b\x32_.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0.GroupPositionInfoEntryB\x08\n\x06resultB\t\n\x07version\"\xbe\x04\n\x16GetGroupActionsRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetGroupActionsRequest.GetGroupActionsRequestV0H\x00\x1aL\n\x0fStartAtActionId\x12\x17\n\x0fstart_action_id\x18\x01 \x01(\x0c\x12 \n\x18start_action_id_included\x18\x02 \x01(\x08\x1a\xc8\x02\n\x18GetGroupActionsRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17group_contract_position\x18\x02 \x01(\r\x12N\n\x06status\x18\x03 \x01(\x0e\x32>.org.dash.platform.dapi.v0.GetGroupActionsRequest.ActionStatus\x12\x62\n\x12start_at_action_id\x18\x04 \x01(\x0b\x32\x41.org.dash.platform.dapi.v0.GetGroupActionsRequest.StartAtActionIdH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x05 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\x06 \x01(\x08\x42\x15\n\x13_start_at_action_idB\x08\n\x06_count\"&\n\x0c\x41\x63tionStatus\x12\n\n\x06\x41\x43TIVE\x10\x00\x12\n\n\x06\x43LOSED\x10\x01\x42\t\n\x07version\"\xd6\x1e\n\x17GetGroupActionsResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0H\x00\x1a\xd3\x1d\n\x19GetGroupActionsResponseV0\x12r\n\rgroup_actions\x18\x01 \x01(\x0b\x32Y.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.GroupActionsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a[\n\tMintEvent\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x04\x12\x14\n\x0crecipient_id\x18\x02 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a[\n\tBurnEvent\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x04\x12\x14\n\x0c\x62urn_from_id\x18\x02 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1aJ\n\x0b\x46reezeEvent\x12\x11\n\tfrozen_id\x18\x01 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1aL\n\rUnfreezeEvent\x12\x11\n\tfrozen_id\x18\x01 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a\x66\n\x17\x44\x65stroyFrozenFundsEvent\x12\x11\n\tfrozen_id\x18\x01 \x01(\x0c\x12\x0e\n\x06\x61mount\x18\x02 \x01(\x04\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a\x64\n\x13SharedEncryptedNote\x12\x18\n\x10sender_key_index\x18\x01 \x01(\r\x12\x1b\n\x13recipient_key_index\x18\x02 \x01(\r\x12\x16\n\x0e\x65ncrypted_data\x18\x03 \x01(\x0c\x1a{\n\x15PersonalEncryptedNote\x12!\n\x19root_encryption_key_index\x18\x01 \x01(\r\x12\'\n\x1f\x64\x65rivation_encryption_key_index\x18\x02 \x01(\r\x12\x16\n\x0e\x65ncrypted_data\x18\x03 \x01(\x0c\x1a\xe9\x01\n\x14\x45mergencyActionEvent\x12\x81\x01\n\x0b\x61\x63tion_type\x18\x01 \x01(\x0e\x32l.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.EmergencyActionEvent.ActionType\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\"#\n\nActionType\x12\t\n\x05PAUSE\x10\x00\x12\n\n\x06RESUME\x10\x01\x42\x0e\n\x0c_public_note\x1a\x64\n\x16TokenConfigUpdateEvent\x12 \n\x18token_config_update_item\x18\x01 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a\xe6\x03\n\x1eUpdateDirectPurchasePriceEvent\x12\x15\n\x0b\x66ixed_price\x18\x01 \x01(\x04H\x00\x12\x95\x01\n\x0evariable_price\x18\x02 \x01(\x0b\x32{.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UpdateDirectPurchasePriceEvent.PricingScheduleH\x00\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x01\x88\x01\x01\x1a\x33\n\x10PriceForQuantity\x12\x10\n\x08quantity\x18\x01 \x01(\x04\x12\r\n\x05price\x18\x02 \x01(\x04\x1a\xac\x01\n\x0fPricingSchedule\x12\x98\x01\n\x12price_for_quantity\x18\x01 \x03(\x0b\x32|.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UpdateDirectPurchasePriceEvent.PriceForQuantityB\x07\n\x05priceB\x0e\n\x0c_public_note\x1a\xfc\x02\n\x10GroupActionEvent\x12n\n\x0btoken_event\x18\x01 \x01(\x0b\x32W.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.TokenEventH\x00\x12t\n\x0e\x64ocument_event\x18\x02 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.DocumentEventH\x00\x12t\n\x0e\x63ontract_event\x18\x03 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.ContractEventH\x00\x42\x0c\n\nevent_type\x1a\x8b\x01\n\rDocumentEvent\x12r\n\x06\x63reate\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.DocumentCreateEventH\x00\x42\x06\n\x04type\x1a/\n\x13\x44ocumentCreateEvent\x12\x18\n\x10\x63reated_document\x18\x01 \x01(\x0c\x1a/\n\x13\x43ontractUpdateEvent\x12\x18\n\x10updated_contract\x18\x01 \x01(\x0c\x1a\x8b\x01\n\rContractEvent\x12r\n\x06update\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.ContractUpdateEventH\x00\x42\x06\n\x04type\x1a\xd1\x07\n\nTokenEvent\x12\x66\n\x04mint\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.MintEventH\x00\x12\x66\n\x04\x62urn\x18\x02 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.BurnEventH\x00\x12j\n\x06\x66reeze\x18\x03 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.FreezeEventH\x00\x12n\n\x08unfreeze\x18\x04 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UnfreezeEventH\x00\x12\x84\x01\n\x14\x64\x65stroy_frozen_funds\x18\x05 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.DestroyFrozenFundsEventH\x00\x12}\n\x10\x65mergency_action\x18\x06 \x01(\x0b\x32\x61.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.EmergencyActionEventH\x00\x12\x82\x01\n\x13token_config_update\x18\x07 \x01(\x0b\x32\x63.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.TokenConfigUpdateEventH\x00\x12\x83\x01\n\x0cupdate_price\x18\x08 \x01(\x0b\x32k.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UpdateDirectPurchasePriceEventH\x00\x42\x06\n\x04type\x1a\x93\x01\n\x10GroupActionEntry\x12\x11\n\taction_id\x18\x01 \x01(\x0c\x12l\n\x05\x65vent\x18\x02 \x01(\x0b\x32].org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.GroupActionEvent\x1a\x84\x01\n\x0cGroupActions\x12t\n\rgroup_actions\x18\x01 \x03(\x0b\x32].org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.GroupActionEntryB\x08\n\x06resultB\t\n\x07version\"\x88\x03\n\x1cGetGroupActionSignersRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetGroupActionSignersRequest.GetGroupActionSignersRequestV0H\x00\x1a\xce\x01\n\x1eGetGroupActionSignersRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17group_contract_position\x18\x02 \x01(\r\x12T\n\x06status\x18\x03 \x01(\x0e\x32\x44.org.dash.platform.dapi.v0.GetGroupActionSignersRequest.ActionStatus\x12\x11\n\taction_id\x18\x04 \x01(\x0c\x12\r\n\x05prove\x18\x05 \x01(\x08\"&\n\x0c\x41\x63tionStatus\x12\n\n\x06\x41\x43TIVE\x10\x00\x12\n\n\x06\x43LOSED\x10\x01\x42\t\n\x07version\"\x8b\x05\n\x1dGetGroupActionSignersResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetGroupActionSignersResponse.GetGroupActionSignersResponseV0H\x00\x1a\xf6\x03\n\x1fGetGroupActionSignersResponseV0\x12\x8b\x01\n\x14group_action_signers\x18\x01 \x01(\x0b\x32k.org.dash.platform.dapi.v0.GetGroupActionSignersResponse.GetGroupActionSignersResponseV0.GroupActionSignersH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x35\n\x11GroupActionSigner\x12\x11\n\tsigner_id\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x02 \x01(\r\x1a\x91\x01\n\x12GroupActionSigners\x12{\n\x07signers\x18\x01 \x03(\x0b\x32j.org.dash.platform.dapi.v0.GetGroupActionSignersResponse.GetGroupActionSignersResponseV0.GroupActionSignerB\x08\n\x06resultB\t\n\x07version\"\xb5\x01\n\x15GetAddressInfoRequest\x12V\n\x02v0\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetAddressInfoRequest.GetAddressInfoRequestV0H\x00\x1a\x39\n\x17GetAddressInfoRequestV0\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x85\x01\n\x10\x41\x64\x64ressInfoEntry\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12J\n\x11\x62\x61lance_and_nonce\x18\x02 \x01(\x0b\x32*.org.dash.platform.dapi.v0.BalanceAndNonceH\x00\x88\x01\x01\x42\x14\n\x12_balance_and_nonce\"1\n\x0f\x42\x61lanceAndNonce\x12\x0f\n\x07\x62\x61lance\x18\x01 \x01(\x04\x12\r\n\x05nonce\x18\x02 \x01(\r\"_\n\x12\x41\x64\x64ressInfoEntries\x12I\n\x14\x61\x64\x64ress_info_entries\x18\x01 \x03(\x0b\x32+.org.dash.platform.dapi.v0.AddressInfoEntry\"m\n\x14\x41\x64\x64ressBalanceChange\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x19\n\x0bset_balance\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x12\x1c\n\x0e\x61\x64\x64_to_balance\x18\x03 \x01(\x04\x42\x02\x30\x01H\x00\x42\x0b\n\toperation\"x\n\x1a\x42lockAddressBalanceChanges\x12\x18\n\x0c\x62lock_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12@\n\x07\x63hanges\x18\x02 \x03(\x0b\x32/.org.dash.platform.dapi.v0.AddressBalanceChange\"k\n\x1b\x41\x64\x64ressBalanceUpdateEntries\x12L\n\rblock_changes\x18\x01 \x03(\x0b\x32\x35.org.dash.platform.dapi.v0.BlockAddressBalanceChanges\"\xe1\x02\n\x16GetAddressInfoResponse\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetAddressInfoResponse.GetAddressInfoResponseV0H\x00\x1a\xe1\x01\n\x18GetAddressInfoResponseV0\x12I\n\x12\x61\x64\x64ress_info_entry\x18\x01 \x01(\x0b\x32+.org.dash.platform.dapi.v0.AddressInfoEntryH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc3\x01\n\x18GetAddressesInfosRequest\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetAddressesInfosRequest.GetAddressesInfosRequestV0H\x00\x1a>\n\x1aGetAddressesInfosRequestV0\x12\x11\n\taddresses\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xf1\x02\n\x19GetAddressesInfosResponse\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetAddressesInfosResponse.GetAddressesInfosResponseV0H\x00\x1a\xe8\x01\n\x1bGetAddressesInfosResponseV0\x12M\n\x14\x61\x64\x64ress_info_entries\x18\x01 \x01(\x0b\x32-.org.dash.platform.dapi.v0.AddressInfoEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xb5\x01\n\x1dGetAddressesTrunkStateRequest\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetAddressesTrunkStateRequest.GetAddressesTrunkStateRequestV0H\x00\x1a!\n\x1fGetAddressesTrunkStateRequestV0B\t\n\x07version\"\xaa\x02\n\x1eGetAddressesTrunkStateResponse\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetAddressesTrunkStateResponse.GetAddressesTrunkStateResponseV0H\x00\x1a\x92\x01\n GetAddressesTrunkStateResponseV0\x12/\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.Proof\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\t\n\x07version\"\xf0\x01\n\x1eGetAddressesBranchStateRequest\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetAddressesBranchStateRequest.GetAddressesBranchStateRequestV0H\x00\x1aY\n GetAddressesBranchStateRequestV0\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\r\n\x05\x64\x65pth\x18\x02 \x01(\r\x12\x19\n\x11\x63heckpoint_height\x18\x03 \x01(\x04\x42\t\n\x07version\"\xd1\x01\n\x1fGetAddressesBranchStateResponse\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetAddressesBranchStateResponse.GetAddressesBranchStateResponseV0H\x00\x1a\x37\n!GetAddressesBranchStateResponseV0\x12\x12\n\nmerk_proof\x18\x02 \x01(\x0c\x42\t\n\x07version\"\xfe\x01\n%GetRecentAddressBalanceChangesRequest\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesRequest.GetRecentAddressBalanceChangesRequestV0H\x00\x1aR\n\'GetRecentAddressBalanceChangesRequestV0\x12\x18\n\x0cstart_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xb8\x03\n&GetRecentAddressBalanceChangesResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesResponse.GetRecentAddressBalanceChangesResponseV0H\x00\x1a\x88\x02\n(GetRecentAddressBalanceChangesResponseV0\x12`\n\x1e\x61\x64\x64ress_balance_update_entries\x18\x01 \x01(\x0b\x32\x36.org.dash.platform.dapi.v0.AddressBalanceUpdateEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"G\n\x16\x42lockHeightCreditEntry\x12\x18\n\x0c\x62lock_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x13\n\x07\x63redits\x18\x02 \x01(\x04\x42\x02\x30\x01\"\xb0\x01\n\x1d\x43ompactedAddressBalanceChange\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x19\n\x0bset_credits\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x12V\n\x19\x61\x64\x64_to_credits_operations\x18\x03 \x01(\x0b\x32\x31.org.dash.platform.dapi.v0.AddToCreditsOperationsH\x00\x42\x0b\n\toperation\"\\\n\x16\x41\x64\x64ToCreditsOperations\x12\x42\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x31.org.dash.platform.dapi.v0.BlockHeightCreditEntry\"\xae\x01\n#CompactedBlockAddressBalanceChanges\x12\x1e\n\x12start_block_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1c\n\x10\x65nd_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12I\n\x07\x63hanges\x18\x03 \x03(\x0b\x32\x38.org.dash.platform.dapi.v0.CompactedAddressBalanceChange\"\x87\x01\n$CompactedAddressBalanceUpdateEntries\x12_\n\x17\x63ompacted_block_changes\x18\x01 \x03(\x0b\x32>.org.dash.platform.dapi.v0.CompactedBlockAddressBalanceChanges\"\xa9\x02\n.GetRecentCompactedAddressBalanceChangesRequest\x12\x88\x01\n\x02v0\x18\x01 \x01(\x0b\x32z.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesRequest.GetRecentCompactedAddressBalanceChangesRequestV0H\x00\x1a\x61\n0GetRecentCompactedAddressBalanceChangesRequestV0\x12\x1e\n\x12start_block_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xf0\x03\n/GetRecentCompactedAddressBalanceChangesResponse\x12\x8a\x01\n\x02v0\x18\x01 \x01(\x0b\x32|.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0H\x00\x1a\xa4\x02\n1GetRecentCompactedAddressBalanceChangesResponseV0\x12s\n(compacted_address_balance_update_entries\x18\x01 \x01(\x0b\x32?.org.dash.platform.dapi.v0.CompactedAddressBalanceUpdateEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xf4\x01\n GetShieldedEncryptedNotesRequest\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0H\x00\x1aW\n\"GetShieldedEncryptedNotesRequestV0\x12\x13\n\x0bstart_index\x18\x01 \x01(\x04\x12\r\n\x05\x63ount\x18\x02 \x01(\r\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xac\x05\n!GetShieldedEncryptedNotesResponse\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0H\x00\x1a\x8b\x04\n#GetShieldedEncryptedNotesResponseV0\x12\x8a\x01\n\x0f\x65ncrypted_notes\x18\x01 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aG\n\rEncryptedNote\x12\x11\n\tnullifier\x18\x01 \x01(\x0c\x12\x0b\n\x03\x63mx\x18\x02 \x01(\x0c\x12\x16\n\x0e\x65ncrypted_note\x18\x03 \x01(\x0c\x1a\x91\x01\n\x0e\x45ncryptedNotes\x12\x7f\n\x07\x65ntries\x18\x01 \x03(\x0b\x32n.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNoteB\x08\n\x06resultB\t\n\x07version\"\xb4\x01\n\x19GetShieldedAnchorsRequest\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0H\x00\x1a,\n\x1bGetShieldedAnchorsRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xb1\x03\n\x1aGetShieldedAnchorsResponse\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0H\x00\x1a\xa5\x02\n\x1cGetShieldedAnchorsResponseV0\x12m\n\x07\x61nchors\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.AnchorsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1a\n\x07\x41nchors\x12\x0f\n\x07\x61nchors\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xbc\x01\n\x1bGetShieldedPoolStateRequest\x12\x62\n\x02v0\x18\x01 \x01(\x0b\x32T.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0H\x00\x1a.\n\x1dGetShieldedPoolStateRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xcb\x02\n\x1cGetShieldedPoolStateResponse\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0H\x00\x1a\xb9\x01\n\x1eGetShieldedPoolStateResponseV0\x12\x1b\n\rtotal_balance\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xd4\x01\n\x1cGetShieldedNullifiersRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0H\x00\x1a\x43\n\x1eGetShieldedNullifiersRequestV0\x12\x12\n\nnullifiers\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x86\x05\n\x1dGetShieldedNullifiersResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0H\x00\x1a\xf1\x03\n\x1fGetShieldedNullifiersResponseV0\x12\x88\x01\n\x12nullifier_statuses\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatusesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x36\n\x0fNullifierStatus\x12\x11\n\tnullifier\x18\x01 \x01(\x0c\x12\x10\n\x08is_spent\x18\x02 \x01(\x08\x1a\x8e\x01\n\x11NullifierStatuses\x12y\n\x07\x65ntries\x18\x01 \x03(\x0b\x32h.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatusB\x08\n\x06resultB\t\n\x07version*Z\n\nKeyPurpose\x12\x12\n\x0e\x41UTHENTICATION\x10\x00\x12\x0e\n\nENCRYPTION\x10\x01\x12\x0e\n\nDECRYPTION\x10\x02\x12\x0c\n\x08TRANSFER\x10\x03\x12\n\n\x06VOTING\x10\x05\x32\x9e\x41\n\x08Platform\x12\x93\x01\n\x18\x62roadcastStateTransition\x12:.org.dash.platform.dapi.v0.BroadcastStateTransitionRequest\x1a;.org.dash.platform.dapi.v0.BroadcastStateTransitionResponse\x12l\n\x0bgetIdentity\x12-.org.dash.platform.dapi.v0.GetIdentityRequest\x1a..org.dash.platform.dapi.v0.GetIdentityResponse\x12x\n\x0fgetIdentityKeys\x12\x31.org.dash.platform.dapi.v0.GetIdentityKeysRequest\x1a\x32.org.dash.platform.dapi.v0.GetIdentityKeysResponse\x12\x96\x01\n\x19getIdentitiesContractKeys\x12;.org.dash.platform.dapi.v0.GetIdentitiesContractKeysRequest\x1a<.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse\x12{\n\x10getIdentityNonce\x12\x32.org.dash.platform.dapi.v0.GetIdentityNonceRequest\x1a\x33.org.dash.platform.dapi.v0.GetIdentityNonceResponse\x12\x93\x01\n\x18getIdentityContractNonce\x12:.org.dash.platform.dapi.v0.GetIdentityContractNonceRequest\x1a;.org.dash.platform.dapi.v0.GetIdentityContractNonceResponse\x12\x81\x01\n\x12getIdentityBalance\x12\x34.org.dash.platform.dapi.v0.GetIdentityBalanceRequest\x1a\x35.org.dash.platform.dapi.v0.GetIdentityBalanceResponse\x12\x8a\x01\n\x15getIdentitiesBalances\x12\x37.org.dash.platform.dapi.v0.GetIdentitiesBalancesRequest\x1a\x38.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse\x12\xa2\x01\n\x1dgetIdentityBalanceAndRevision\x12?.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionRequest\x1a@.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionResponse\x12\xaf\x01\n#getEvonodesProposedEpochBlocksByIds\x12\x45.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByIdsRequest\x1a\x41.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse\x12\xb3\x01\n%getEvonodesProposedEpochBlocksByRange\x12G.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByRangeRequest\x1a\x41.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse\x12x\n\x0fgetDataContract\x12\x31.org.dash.platform.dapi.v0.GetDataContractRequest\x1a\x32.org.dash.platform.dapi.v0.GetDataContractResponse\x12\x8d\x01\n\x16getDataContractHistory\x12\x38.org.dash.platform.dapi.v0.GetDataContractHistoryRequest\x1a\x39.org.dash.platform.dapi.v0.GetDataContractHistoryResponse\x12{\n\x10getDataContracts\x12\x32.org.dash.platform.dapi.v0.GetDataContractsRequest\x1a\x33.org.dash.platform.dapi.v0.GetDataContractsResponse\x12o\n\x0cgetDocuments\x12..org.dash.platform.dapi.v0.GetDocumentsRequest\x1a/.org.dash.platform.dapi.v0.GetDocumentsResponse\x12\x99\x01\n\x1agetIdentityByPublicKeyHash\x12<.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashRequest\x1a=.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashResponse\x12\xb4\x01\n#getIdentityByNonUniquePublicKeyHash\x12\x45.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashRequest\x1a\x46.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse\x12\x9f\x01\n\x1cwaitForStateTransitionResult\x12>.org.dash.platform.dapi.v0.WaitForStateTransitionResultRequest\x1a?.org.dash.platform.dapi.v0.WaitForStateTransitionResultResponse\x12\x81\x01\n\x12getConsensusParams\x12\x34.org.dash.platform.dapi.v0.GetConsensusParamsRequest\x1a\x35.org.dash.platform.dapi.v0.GetConsensusParamsResponse\x12\xa5\x01\n\x1egetProtocolVersionUpgradeState\x12@.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateRequest\x1a\x41.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse\x12\xb4\x01\n#getProtocolVersionUpgradeVoteStatus\x12\x45.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusRequest\x1a\x46.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse\x12r\n\rgetEpochsInfo\x12/.org.dash.platform.dapi.v0.GetEpochsInfoRequest\x1a\x30.org.dash.platform.dapi.v0.GetEpochsInfoResponse\x12\x8d\x01\n\x16getFinalizedEpochInfos\x12\x38.org.dash.platform.dapi.v0.GetFinalizedEpochInfosRequest\x1a\x39.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse\x12\x8a\x01\n\x15getContestedResources\x12\x37.org.dash.platform.dapi.v0.GetContestedResourcesRequest\x1a\x38.org.dash.platform.dapi.v0.GetContestedResourcesResponse\x12\xa2\x01\n\x1dgetContestedResourceVoteState\x12?.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest\x1a@.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse\x12\xba\x01\n%getContestedResourceVotersForIdentity\x12G.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityRequest\x1aH.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityResponse\x12\xae\x01\n!getContestedResourceIdentityVotes\x12\x43.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesRequest\x1a\x44.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse\x12\x8a\x01\n\x15getVotePollsByEndDate\x12\x37.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest\x1a\x38.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse\x12\xa5\x01\n\x1egetPrefundedSpecializedBalance\x12@.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceRequest\x1a\x41.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceResponse\x12\x96\x01\n\x19getTotalCreditsInPlatform\x12;.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformRequest\x1a<.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformResponse\x12x\n\x0fgetPathElements\x12\x31.org.dash.platform.dapi.v0.GetPathElementsRequest\x1a\x32.org.dash.platform.dapi.v0.GetPathElementsResponse\x12\x66\n\tgetStatus\x12+.org.dash.platform.dapi.v0.GetStatusRequest\x1a,.org.dash.platform.dapi.v0.GetStatusResponse\x12\x8a\x01\n\x15getCurrentQuorumsInfo\x12\x37.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoRequest\x1a\x38.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse\x12\x93\x01\n\x18getIdentityTokenBalances\x12:.org.dash.platform.dapi.v0.GetIdentityTokenBalancesRequest\x1a;.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse\x12\x99\x01\n\x1agetIdentitiesTokenBalances\x12<.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesRequest\x1a=.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse\x12\x8a\x01\n\x15getIdentityTokenInfos\x12\x37.org.dash.platform.dapi.v0.GetIdentityTokenInfosRequest\x1a\x38.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse\x12\x90\x01\n\x17getIdentitiesTokenInfos\x12\x39.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosRequest\x1a:.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse\x12{\n\x10getTokenStatuses\x12\x32.org.dash.platform.dapi.v0.GetTokenStatusesRequest\x1a\x33.org.dash.platform.dapi.v0.GetTokenStatusesResponse\x12\x9f\x01\n\x1cgetTokenDirectPurchasePrices\x12>.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesRequest\x1a?.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse\x12\x87\x01\n\x14getTokenContractInfo\x12\x36.org.dash.platform.dapi.v0.GetTokenContractInfoRequest\x1a\x37.org.dash.platform.dapi.v0.GetTokenContractInfoResponse\x12\xb1\x01\n\"getTokenPreProgrammedDistributions\x12\x44.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsRequest\x1a\x45.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse\x12\xbd\x01\n&getTokenPerpetualDistributionLastClaim\x12H.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimRequest\x1aI.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimResponse\x12\x84\x01\n\x13getTokenTotalSupply\x12\x35.org.dash.platform.dapi.v0.GetTokenTotalSupplyRequest\x1a\x36.org.dash.platform.dapi.v0.GetTokenTotalSupplyResponse\x12o\n\x0cgetGroupInfo\x12..org.dash.platform.dapi.v0.GetGroupInfoRequest\x1a/.org.dash.platform.dapi.v0.GetGroupInfoResponse\x12r\n\rgetGroupInfos\x12/.org.dash.platform.dapi.v0.GetGroupInfosRequest\x1a\x30.org.dash.platform.dapi.v0.GetGroupInfosResponse\x12x\n\x0fgetGroupActions\x12\x31.org.dash.platform.dapi.v0.GetGroupActionsRequest\x1a\x32.org.dash.platform.dapi.v0.GetGroupActionsResponse\x12\x8a\x01\n\x15getGroupActionSigners\x12\x37.org.dash.platform.dapi.v0.GetGroupActionSignersRequest\x1a\x38.org.dash.platform.dapi.v0.GetGroupActionSignersResponse\x12u\n\x0egetAddressInfo\x12\x30.org.dash.platform.dapi.v0.GetAddressInfoRequest\x1a\x31.org.dash.platform.dapi.v0.GetAddressInfoResponse\x12~\n\x11getAddressesInfos\x12\x33.org.dash.platform.dapi.v0.GetAddressesInfosRequest\x1a\x34.org.dash.platform.dapi.v0.GetAddressesInfosResponse\x12\x8d\x01\n\x16getAddressesTrunkState\x12\x38.org.dash.platform.dapi.v0.GetAddressesTrunkStateRequest\x1a\x39.org.dash.platform.dapi.v0.GetAddressesTrunkStateResponse\x12\x90\x01\n\x17getAddressesBranchState\x12\x39.org.dash.platform.dapi.v0.GetAddressesBranchStateRequest\x1a:.org.dash.platform.dapi.v0.GetAddressesBranchStateResponse\x12\xa5\x01\n\x1egetRecentAddressBalanceChanges\x12@.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesRequest\x1a\x41.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesResponse\x12\xc0\x01\n\'getRecentCompactedAddressBalanceChanges\x12I.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesRequest\x1aJ.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse\x12\x96\x01\n\x19getShieldedEncryptedNotes\x12;.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest\x1a<.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse\x12\x81\x01\n\x12getShieldedAnchors\x12\x34.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest\x1a\x35.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse\x12\x87\x01\n\x14getShieldedPoolState\x12\x36.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest\x1a\x37.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse\x12\x8a\x01\n\x15getShieldedNullifiers\x12\x37.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest\x1a\x38.org.dash.platform.dapi.v0.GetShieldedNullifiersResponseb\x06proto3' , dependencies=[google_dot_protobuf_dot_wrappers__pb2.DESCRIPTOR,google_dot_protobuf_dot_struct__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,]) @@ -62,8 +62,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=58735, - serialized_end=58825, + serialized_start=58754, + serialized_end=58844, ) _sym_db.RegisterEnumDescriptor(_KEYPURPOSE) @@ -14817,19 +14817,26 @@ create_key=_descriptor._internal_create_key, fields=[ _descriptor.FieldDescriptor( - name='cmx', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.cmx', index=0, + name='nullifier', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.nullifier', index=0, number=1, type=12, cpp_type=9, label=1, has_default_value=False, default_value=b"", message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( - name='encrypted_note', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.encrypted_note', index=1, + name='cmx', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.cmx', index=1, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=b"", message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='encrypted_note', full_name='org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.encrypted_note', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -14843,7 +14850,7 @@ oneofs=[ ], serialized_start=56504, - serialized_end=56556, + serialized_end=56575, ) _GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0_ENCRYPTEDNOTES = _descriptor.Descriptor( @@ -14873,8 +14880,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=56559, - serialized_end=56704, + serialized_start=56578, + serialized_end=56723, ) _GETSHIELDEDENCRYPTEDNOTESRESPONSE_GETSHIELDEDENCRYPTEDNOTESRESPONSEV0 = _descriptor.Descriptor( @@ -14924,7 +14931,7 @@ fields=[]), ], serialized_start=56210, - serialized_end=56714, + serialized_end=56733, ) _GETSHIELDEDENCRYPTEDNOTESRESPONSE = _descriptor.Descriptor( @@ -14960,7 +14967,7 @@ fields=[]), ], serialized_start=56060, - serialized_end=56725, + serialized_end=56744, ) @@ -14991,8 +14998,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=56853, - serialized_end=56897, + serialized_start=56872, + serialized_end=56916, ) _GETSHIELDEDANCHORSREQUEST = _descriptor.Descriptor( @@ -15027,8 +15034,8 @@ create_key=_descriptor._internal_create_key, fields=[]), ], - serialized_start=56728, - serialized_end=56908, + serialized_start=56747, + serialized_end=56927, ) @@ -15059,8 +15066,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=57297, - serialized_end=57323, + serialized_start=57316, + serialized_end=57342, ) _GETSHIELDEDANCHORSRESPONSE_GETSHIELDEDANCHORSRESPONSEV0 = _descriptor.Descriptor( @@ -15109,8 +15116,8 @@ create_key=_descriptor._internal_create_key, fields=[]), ], - serialized_start=57040, - serialized_end=57333, + serialized_start=57059, + serialized_end=57352, ) _GETSHIELDEDANCHORSRESPONSE = _descriptor.Descriptor( @@ -15145,8 +15152,8 @@ create_key=_descriptor._internal_create_key, fields=[]), ], - serialized_start=56911, - serialized_end=57344, + serialized_start=56930, + serialized_end=57363, ) @@ -15177,8 +15184,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=57478, - serialized_end=57524, + serialized_start=57497, + serialized_end=57543, ) _GETSHIELDEDPOOLSTATEREQUEST = _descriptor.Descriptor( @@ -15213,8 +15220,8 @@ create_key=_descriptor._internal_create_key, fields=[]), ], - serialized_start=57347, - serialized_end=57535, + serialized_start=57366, + serialized_end=57554, ) @@ -15264,8 +15271,8 @@ create_key=_descriptor._internal_create_key, fields=[]), ], - serialized_start=57673, - serialized_end=57858, + serialized_start=57692, + serialized_end=57877, ) _GETSHIELDEDPOOLSTATERESPONSE = _descriptor.Descriptor( @@ -15300,8 +15307,8 @@ create_key=_descriptor._internal_create_key, fields=[]), ], - serialized_start=57538, - serialized_end=57869, + serialized_start=57557, + serialized_end=57888, ) @@ -15339,8 +15346,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=58006, - serialized_end=58073, + serialized_start=58025, + serialized_end=58092, ) _GETSHIELDEDNULLIFIERSREQUEST = _descriptor.Descriptor( @@ -15375,8 +15382,8 @@ create_key=_descriptor._internal_create_key, fields=[]), ], - serialized_start=57872, - serialized_end=58084, + serialized_start=57891, + serialized_end=58103, ) @@ -15414,8 +15421,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=58513, - serialized_end=58567, + serialized_start=58532, + serialized_end=58586, ) _GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0_NULLIFIERSTATUSES = _descriptor.Descriptor( @@ -15445,8 +15452,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=58570, - serialized_end=58712, + serialized_start=58589, + serialized_end=58731, ) _GETSHIELDEDNULLIFIERSRESPONSE_GETSHIELDEDNULLIFIERSRESPONSEV0 = _descriptor.Descriptor( @@ -15495,8 +15502,8 @@ create_key=_descriptor._internal_create_key, fields=[]), ], - serialized_start=58225, - serialized_end=58722, + serialized_start=58244, + serialized_end=58741, ) _GETSHIELDEDNULLIFIERSRESPONSE = _descriptor.Descriptor( @@ -15531,8 +15538,8 @@ create_key=_descriptor._internal_create_key, fields=[]), ], - serialized_start=58087, - serialized_end=58733, + serialized_start=58106, + serialized_end=58752, ) _GETIDENTITYREQUEST_GETIDENTITYREQUESTV0.containing_type = _GETIDENTITYREQUEST @@ -19981,8 +19988,8 @@ index=0, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=58828, - serialized_end=67178, + serialized_start=58847, + serialized_end=67197, methods=[ _descriptor.MethodDescriptor( name='broadcastStateTransition', diff --git a/packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts b/packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts index e6c480d626d..39802f2f414 100644 --- a/packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts +++ b/packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts @@ -10615,6 +10615,11 @@ export namespace GetShieldedEncryptedNotesResponse { } export class EncryptedNote extends jspb.Message { + getNullifier(): Uint8Array | string; + getNullifier_asU8(): Uint8Array; + getNullifier_asB64(): string; + setNullifier(value: Uint8Array | string): void; + getCmx(): Uint8Array | string; getCmx_asU8(): Uint8Array; getCmx_asB64(): string; @@ -10637,6 +10642,7 @@ export namespace GetShieldedEncryptedNotesResponse { export namespace EncryptedNote { export type AsObject = { + nullifier: Uint8Array | string, cmx: Uint8Array | string, encryptedNote: Uint8Array | string, } diff --git a/packages/dapi-grpc/clients/platform/v0/web/platform_pb.js b/packages/dapi-grpc/clients/platform/v0/web/platform_pb.js index f38425b23af..b3961b34a2e 100644 --- a/packages/dapi-grpc/clients/platform/v0/web/platform_pb.js +++ b/packages/dapi-grpc/clients/platform/v0/web/platform_pb.js @@ -80852,6 +80852,7 @@ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEnc */ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.toObject = function(includeInstance, msg) { var f, obj = { + nullifier: msg.getNullifier_asB64(), cmx: msg.getCmx_asB64(), encryptedNote: msg.getEncryptedNote_asB64() }; @@ -80892,9 +80893,13 @@ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEnc switch (field) { case 1: var value = /** @type {!Uint8Array} */ (reader.readBytes()); - msg.setCmx(value); + msg.setNullifier(value); break; case 2: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setCmx(value); + break; + case 3: var value = /** @type {!Uint8Array} */ (reader.readBytes()); msg.setEncryptedNote(value); break; @@ -80927,34 +80932,83 @@ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEnc */ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.serializeBinaryToWriter = function(message, writer) { var f = undefined; - f = message.getCmx_asU8(); + f = message.getNullifier_asU8(); if (f.length > 0) { writer.writeBytes( 1, f ); } - f = message.getEncryptedNote_asU8(); + f = message.getCmx_asU8(); if (f.length > 0) { writer.writeBytes( 2, f ); } + f = message.getEncryptedNote_asU8(); + if (f.length > 0) { + writer.writeBytes( + 3, + f + ); + } }; /** - * optional bytes cmx = 1; + * optional bytes nullifier = 1; * @return {string} */ -proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getCmx = function() { +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getNullifier = function() { return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "")); }; /** - * optional bytes cmx = 1; + * optional bytes nullifier = 1; + * This is a type-conversion wrapper around `getNullifier()` + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getNullifier_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getNullifier())); +}; + + +/** + * optional bytes nullifier = 1; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getNullifier()` + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getNullifier_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getNullifier())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} returns this + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.setNullifier = function(value) { + return jspb.Message.setProto3BytesField(this, 1, value); +}; + + +/** + * optional bytes cmx = 2; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getCmx = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * optional bytes cmx = 2; * This is a type-conversion wrapper around `getCmx()` * @return {string} */ @@ -80965,7 +81019,7 @@ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEnc /** - * optional bytes cmx = 1; + * optional bytes cmx = 2; * Note that Uint8Array is not supported on all browsers. * @see http://caniuse.com/Uint8Array * This is a type-conversion wrapper around `getCmx()` @@ -80982,21 +81036,21 @@ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEnc * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} returns this */ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.setCmx = function(value) { - return jspb.Message.setProto3BytesField(this, 1, value); + return jspb.Message.setProto3BytesField(this, 2, value); }; /** - * optional bytes encrypted_note = 2; + * optional bytes encrypted_note = 3; * @return {string} */ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.getEncryptedNote = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); }; /** - * optional bytes encrypted_note = 2; + * optional bytes encrypted_note = 3; * This is a type-conversion wrapper around `getEncryptedNote()` * @return {string} */ @@ -81007,7 +81061,7 @@ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEnc /** - * optional bytes encrypted_note = 2; + * optional bytes encrypted_note = 3; * Note that Uint8Array is not supported on all browsers. * @see http://caniuse.com/Uint8Array * This is a type-conversion wrapper around `getEncryptedNote()` @@ -81024,7 +81078,7 @@ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEnc * @return {!proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote} returns this */ proto.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNote.prototype.setEncryptedNote = function(value) { - return jspb.Message.setProto3BytesField(this, 2, value); + return jspb.Message.setProto3BytesField(this, 3, value); }; diff --git a/packages/dapi-grpc/protos/platform/v0/platform.proto b/packages/dapi-grpc/protos/platform/v0/platform.proto index 7f993724d51..46718eb03b3 100644 --- a/packages/dapi-grpc/protos/platform/v0/platform.proto +++ b/packages/dapi-grpc/protos/platform/v0/platform.proto @@ -2148,8 +2148,9 @@ message GetShieldedEncryptedNotesRequest { message GetShieldedEncryptedNotesResponse { message GetShieldedEncryptedNotesResponseV0 { message EncryptedNote { - bytes cmx = 1; - bytes encrypted_note = 2; + bytes nullifier = 1; // 32-byte nullifier (needed for Rho derivation in trial decryption) + bytes cmx = 2; // 32-byte extracted note commitment + bytes encrypted_note = 3; // encrypted note payload (epk + enc_ciphertext + out_ciphertext) } message EncryptedNotes { repeated EncryptedNote entries = 1; diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs index 790ac30b2ec..b5f3f178dbb 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs @@ -41,7 +41,10 @@ impl ShieldStateTransitionTransformIntoActionValidationV0 for ShieldTransition { execution_context: &mut StateTransitionExecutionContext, platform_version: &PlatformVersion, ) -> Result, Error> { - // Extract note commitments and encrypted notes from serialized actions + // Extract nullifiers, note commitments, and encrypted notes from serialized actions + let nullifiers: Vec<[u8; 32]> = match self { + ShieldTransition::V0(v0) => v0.actions.iter().map(|a| a.nullifier).collect(), + }; let note_commitments: Vec<[u8; 32]> = match self { ShieldTransition::V0(v0) => v0.actions.iter().map(|a| a.cmx).collect(), }; @@ -99,6 +102,7 @@ impl ShieldStateTransitionTransformIntoActionValidationV0 for ShieldTransition { self, inputs_with_remaining_balance, shield_amount, + nullifiers, note_commitments, encrypted_notes, current_total_balance, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs index c6be736535b..47b0f0fd94f 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs @@ -65,7 +65,12 @@ impl ShieldFromAssetLockStateTransitionTransformIntoActionValidationV0 ) -> Result, Error> { let platform_version = platform.state.current_platform_version()?; - // Extract note commitments and encrypted notes from serialized actions + // Extract nullifiers, note commitments, and encrypted notes from serialized actions + let nullifiers: Vec<[u8; 32]> = match self { + ShieldFromAssetLockTransition::V0(v0) => { + v0.actions.iter().map(|a| a.nullifier).collect() + } + }; let note_commitments: Vec<[u8; 32]> = match self { ShieldFromAssetLockTransition::V0(v0) => v0.actions.iter().map(|a| a.cmx).collect(), }; @@ -349,6 +354,7 @@ impl ShieldFromAssetLockStateTransitionTransformIntoActionValidationV0 asset_lock_value_credits, signable_bytes_hash, shield_amount, + nullifiers, note_commitments, encrypted_notes, current_total_balance, diff --git a/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs index 193292b3ac8..cf73f4228a9 100644 --- a/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs @@ -103,10 +103,12 @@ impl Platform { .map_err(|e| Error::Drive(drive::error::Error::GroveDB(Box::new(e))))?; match maybe_value { - Some(value) if value.len() > 32 => { + // Stored value = cmx (32) || nullifier (32) || encrypted_note (rest) + Some(value) if value.len() > 64 => { entries.push(EncryptedNote { cmx: value[..32].to_vec(), - encrypted_note: value[32..].to_vec(), + nullifier: value[32..64].to_vec(), + encrypted_note: value[64..].to_vec(), }); } _ => break, // past end of tree @@ -119,9 +121,7 @@ impl Platform { EncryptedNotes { entries }, ), ), - metadata: Some( - self.response_metadata_v0(platform_state, CheckpointUsed::Current), - ), + metadata: Some(self.response_metadata_v0(platform_state, CheckpointUsed::Current)), } }; diff --git a/packages/rs-drive/src/fees/op.rs b/packages/rs-drive/src/fees/op.rs index 0f70a0397cf..0b3d4115be8 100644 --- a/packages/rs-drive/src/fees/op.rs +++ b/packages/rs-drive/src/fees/op.rs @@ -579,7 +579,9 @@ impl LowLevelDriveOperationTreeTypeConverter for TreeType { TreeType::ProvableCountSumTree => { Element::empty_provable_count_sum_tree_with_flags(element_flags) } - TreeType::CommitmentTree => Element::empty_commitment_tree_with_flags(2048, element_flags), + TreeType::CommitmentTree => { + Element::empty_commitment_tree_with_flags(2048, element_flags) + } TreeType::MmrTree => Element::empty_mmr_tree_with_flags(element_flags), TreeType::BulkAppendTree => { Element::empty_bulk_append_tree_with_flags(4, element_flags) diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs index 06ddcb76633..87e6cf66191 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs @@ -18,15 +18,24 @@ pub(super) fn insert_nullifiers<'a>(ops: &mut Vec>, nullifier } } -/// Insert notes into the CommitmentTree (appends cmx to frontier + stores cmx||encrypted_note). +/// Insert notes into the CommitmentTree (appends cmx to frontier + stores nullifier||cmx||encrypted_note). +/// +/// Each action's nullifier is stored alongside the note so light clients can derive +/// Rho for trial decryption. pub(super) fn insert_notes<'a>( ops: &mut Vec>, + nullifiers: &[[u8; 32]], note_commitments: &[[u8; 32]], encrypted_notes: &[Vec], ) { - for (cmx, encrypted_note) in note_commitments.iter().zip(encrypted_notes.iter()) { + for ((nullifier, cmx), encrypted_note) in nullifiers + .iter() + .zip(note_commitments.iter()) + .zip(encrypted_notes.iter()) + { ops.push(DriveOperation::ShieldedPoolOperation( ShieldedPoolOperationType::InsertNote { + nullifier: *nullifier, cmx: *cmx, encrypted_note: encrypted_note.clone(), }, diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_from_asset_lock_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_from_asset_lock_transition.rs index 6859b0c1431..eea69690e59 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_from_asset_lock_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_from_asset_lock_transition.rs @@ -50,7 +50,12 @@ impl DriveHighLevelOperationConverter for ShieldFromAssetLockTransitionAction { )); // 3. Insert notes into CommitmentTree - insert_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); + insert_notes( + &mut ops, + &v0.nullifiers, + &v0.note_commitments, + &v0.encrypted_notes, + ); // 4. Update total balance let new_total_balance = diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_transition.rs index 38ca067b8eb..530b4e08a05 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_transition.rs @@ -37,7 +37,12 @@ impl DriveHighLevelOperationConverter for ShieldTransitionAction { } // 2. Insert notes into CommitmentTree - insert_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); + insert_notes( + &mut ops, + &v0.nullifiers, + &v0.note_commitments, + &v0.encrypted_notes, + ); // 3. Update total balance let new_total_balance = v0 diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs index 497af111301..fe2a2a8bac2 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs @@ -28,7 +28,12 @@ impl DriveHighLevelOperationConverter for ShieldedTransferTransitionAction { insert_nullifiers(&mut ops, &v0.nullifiers); // 2. Insert notes into CommitmentTree - insert_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); + insert_notes( + &mut ops, + &v0.nullifiers, + &v0.note_commitments, + &v0.encrypted_notes, + ); // 3. Update total balance (pool decreases by fee_amount) let new_total_balance = v0 diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs index 564c1c04936..e08057ee85b 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs @@ -30,7 +30,12 @@ impl DriveHighLevelOperationConverter for ShieldedWithdrawalTransitionAction { insert_nullifiers(&mut ops, &v0.nullifiers); // 2. Insert change notes into CommitmentTree - insert_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); + insert_notes( + &mut ops, + &v0.nullifiers, + &v0.note_commitments, + &v0.encrypted_notes, + ); // 3. Update total balance: subtract withdrawal amount + fee (both leave the pool) let total_deduction = diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs index 17a12dd35da..d550f5d045d 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs @@ -37,7 +37,12 @@ impl DriveHighLevelOperationConverter for UnshieldTransitionAction { )); // 3. Insert notes into CommitmentTree (change outputs) - insert_notes(&mut ops, &v0.note_commitments, &v0.encrypted_notes); + insert_notes( + &mut ops, + &v0.nullifiers, + &v0.note_commitments, + &v0.encrypted_notes, + ); // 4. Update total balance // Pool decreases by amount (to output address) + fee_amount (to proposers) diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs index 65ca2c5c246..92ea7a81698 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs @@ -12,6 +12,7 @@ impl ShieldTransitionAction { value: &ShieldTransition, inputs_with_remaining_balance: BTreeMap, shield_amount: Credits, + nullifiers: Vec<[u8; 32]>, note_commitments: Vec<[u8; 32]>, encrypted_notes: Vec>, current_total_balance: Credits, @@ -22,6 +23,7 @@ impl ShieldTransitionAction { v0, inputs_with_remaining_balance, shield_amount, + nullifiers, note_commitments, encrypted_notes, current_total_balance, diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs index fee8a77ed44..922bfa6f480 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs @@ -12,6 +12,8 @@ pub struct ShieldTransitionActionV0 { pub inputs_with_remaining_balance: BTreeMap, /// The amount being shielded (sent into the shielded pool) pub shield_amount: Credits, + /// Nullifiers from the orchard bundle actions (needed for Rho derivation in trial decryption) + pub nullifiers: Vec<[u8; 32]>, /// Note commitments from the orchard bundle (cmx values) pub note_commitments: Vec<[u8; 32]>, /// Encrypted notes from the orchard bundle diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs index 95858478302..826a9eddd8c 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs @@ -11,6 +11,7 @@ impl ShieldTransitionActionV0 { value: &ShieldTransitionV0, inputs_with_remaining_balance: BTreeMap, shield_amount: Credits, + nullifiers: Vec<[u8; 32]>, note_commitments: Vec<[u8; 32]>, encrypted_notes: Vec>, current_total_balance: Credits, @@ -18,6 +19,7 @@ impl ShieldTransitionActionV0 { ConsensusValidationResult::new_with_data(ShieldTransitionActionV0 { inputs_with_remaining_balance, shield_amount, + nullifiers, note_commitments, encrypted_notes, fee_strategy: value.fee_strategy.clone(), diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/transformer.rs index 8c61167af79..749254c2218 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/transformer.rs @@ -12,6 +12,7 @@ impl ShieldFromAssetLockTransitionAction { asset_lock_value_to_be_consumed: Credits, signable_bytes_hasher: [u8; 32], shield_amount: Credits, + nullifiers: Vec<[u8; 32]>, note_commitments: Vec<[u8; 32]>, encrypted_notes: Vec>, current_total_balance: Credits, @@ -24,6 +25,7 @@ impl ShieldFromAssetLockTransitionAction { asset_lock_value_to_be_consumed, signable_bytes_hasher, shield_amount, + nullifiers, note_commitments, encrypted_notes, current_total_balance, diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/mod.rs index cb11bc5c7a4..cfcb230d0e6 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/mod.rs @@ -14,6 +14,8 @@ pub struct ShieldFromAssetLockTransitionActionV0 { pub signable_bytes_hasher: [u8; 32], /// Amount going into shielded pool (|value_balance|) pub shield_amount: Credits, + /// Nullifiers from the orchard bundle actions (needed for Rho derivation in trial decryption) + pub nullifiers: Vec<[u8; 32]>, /// Note commitments from the orchard bundle (cmx values) pub note_commitments: Vec<[u8; 32]>, /// Encrypted notes from the orchard bundle diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/transformer.rs index c4f4b68a75d..4e28e84cb32 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/transformer.rs @@ -11,6 +11,7 @@ impl ShieldFromAssetLockTransitionActionV0 { asset_lock_value_to_be_consumed: Credits, signable_bytes_hasher: [u8; 32], shield_amount: Credits, + nullifiers: Vec<[u8; 32]>, note_commitments: Vec<[u8; 32]>, encrypted_notes: Vec>, current_total_balance: Credits, @@ -20,6 +21,7 @@ impl ShieldFromAssetLockTransitionActionV0 { asset_lock_value_to_be_consumed, signable_bytes_hasher, shield_amount, + nullifiers, note_commitments, encrypted_notes, user_fee_increase: value.user_fee_increase, diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs b/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs index d9e9ec1d1c6..2ddd8e38555 100644 --- a/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs +++ b/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs @@ -17,8 +17,10 @@ use std::collections::HashMap; /// Operations on the Shielded Pool #[derive(Clone, Debug)] pub enum ShieldedPoolOperationType { - /// Insert a note into the CommitmentTree (appends cmx to frontier + stores cmx||payload as item) + /// Insert a note into the CommitmentTree (appends cmx to frontier + stores nullifier||cmx||payload as item) InsertNote { + /// The 32-byte nullifier of the spent note in this action (needed for Rho derivation in trial decryption) + nullifier: [u8; 32], /// The 32-byte note commitment (cmx) cmx: [u8; 32], /// The encrypted note payload @@ -53,16 +55,23 @@ impl DriveLowLevelOperationConverter for ShieldedPoolOperationType { match self { ShieldedPoolOperationType::InsertNote { + nullifier, cmx, encrypted_note, } => { let pool_path = shielded_credit_pool_path_vec(); + // Payload = nullifier || encrypted_note + // Retrieved value = cmx || nullifier || encrypted_note + // The nullifier is needed by light clients to derive Rho for trial decryption + let mut payload = Vec::with_capacity(32 + encrypted_note.len()); + payload.extend_from_slice(&nullifier); + payload.extend_from_slice(&encrypted_note); Ok(vec![GroveOperation( QualifiedGroveDbOp::commitment_tree_insert_op( pool_path, vec![SHIELDED_NOTES_KEY], cmx, - encrypted_note, + payload, ), )]) } diff --git a/packages/rs-drive/src/util/grove_operations/grove_commitment_tree_count/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_commitment_tree_count/v0/mod.rs index 237cafa239e..bef6d837192 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_commitment_tree_count/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_commitment_tree_count/v0/mod.rs @@ -18,12 +18,9 @@ impl Drive { drive_operations: &mut Vec, drive_version: &DriveVersion, ) -> Result { - let CostContext { value, cost } = self.grove.commitment_tree_count( - path, - key, - transaction, - &drive_version.grove_version, - ); + let CostContext { value, cost } = + self.grove + .commitment_tree_count(path, key, transaction, &drive_version.grove_version); drive_operations.push(CalculatedCostOperation(cost)); value.map_err(Error::from) } diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_v1/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_v1/mod.rs index b151f16af4b..6679f518813 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_v1/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_v1/mod.rs @@ -33,11 +33,9 @@ impl Drive { .basic .grove_get_proved_path_query_v1 { - 0 => self.grove_get_proved_path_query_v1_v0( - path_query, - drive_operations, - drive_version, - ), + 0 => { + self.grove_get_proved_path_query_v1_v0(path_query, drive_operations, drive_version) + } version => Err(Error::Drive(DriveError::UnknownVersionMismatch { method: "grove_get_proved_path_query_v1".to_string(), known_versions: vec![0], diff --git a/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_v1/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_v1/v0/mod.rs index eb8c8e3f2cf..d7f8a9d0f85 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_v1/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_get_proved_path_query_v1/v0/mod.rs @@ -16,11 +16,9 @@ impl Drive { drive_operations: &mut Vec, drive_version: &DriveVersion, ) -> Result, Error> { - let CostContext { value, cost } = self.grove.prove_query_v1( - path_query, - None, - &drive_version.grove_version, - ); + let CostContext { value, cost } = + self.grove + .prove_query_v1(path_query, None, &drive_version.grove_version); drive_operations.push(CalculatedCostOperation(cost)); value.map_err(Error::from) } diff --git a/packages/rs-sdk/src/lib.rs b/packages/rs-sdk/src/lib.rs index ee5fe952180..0b17ba0cb5c 100644 --- a/packages/rs-sdk/src/lib.rs +++ b/packages/rs-sdk/src/lib.rs @@ -79,10 +79,10 @@ pub use dpp::dash_spv; #[cfg(feature = "core_rpc_client")] pub use dpp::dashcore_rpc; pub use drive; -#[cfg(feature = "shielded")] -pub use grovedb_commitment_tree; pub use drive_proof_verifier::types as query_types; pub use drive_proof_verifier::Error as ProofVerifierError; +#[cfg(feature = "shielded")] +pub use grovedb_commitment_tree; #[cfg(feature = "platform-wallet")] pub use platform_wallet; pub use rs_dapi_client as dapi_client; From 66c8230959dd70e7f6455bb58989087a17a37737 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 18 Feb 2026 05:00:21 +0700 Subject: [PATCH 20/40] more work --- Cargo.lock | 17 ++++- .../clients/core/v0/nodejs/core_protoc.js | 76 +++++++++---------- .../dapi-grpc/clients/core/v0/web/core_pb.js | 76 +++++++++---------- .../clients/drive/v0/nodejs/drive_protoc.js | 8 +- .../clients/drive/v0/web/drive_pb.js | 8 +- packages/rs-dpp/Cargo.toml | 2 +- packages/rs-drive-abci/Cargo.toml | 4 +- packages/rs-drive/Cargo.toml | 12 +-- packages/rs-platform-version/Cargo.toml | 2 +- packages/rs-sdk/Cargo.toml | 2 +- .../src/state_transitions/proof_result.rs | 32 +++++++- 11 files changed, 142 insertions(+), 97 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b8c07174dec..2e151d0636a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2596,6 +2596,7 @@ dependencies = [ [[package]] name = "grovedb" version = "4.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" dependencies = [ "axum 0.8.8", "bincode", @@ -2633,6 +2634,7 @@ dependencies = [ [[package]] name = "grovedb-bulk-append-tree" version = "4.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" dependencies = [ "bincode", "blake3", @@ -2645,17 +2647,18 @@ dependencies = [ [[package]] name = "grovedb-commitment-tree" version = "4.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" dependencies = [ "incrementalmerkletree", "orchard", "shardtree", "thiserror 2.0.17", - "zcash_note_encryption", ] [[package]] name = "grovedb-costs" version = "4.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" dependencies = [ "integer-encoding", "intmap", @@ -2665,6 +2668,7 @@ dependencies = [ [[package]] name = "grovedb-dense-fixed-sized-merkle-tree" version = "4.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" dependencies = [ "bincode", "blake3", @@ -2674,6 +2678,7 @@ dependencies = [ [[package]] name = "grovedb-element" version = "4.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" dependencies = [ "bincode", "bincode_derive", @@ -2688,6 +2693,7 @@ dependencies = [ [[package]] name = "grovedb-epoch-based-storage-flags" version = "4.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" dependencies = [ "grovedb-costs", "hex", @@ -2699,6 +2705,7 @@ dependencies = [ [[package]] name = "grovedb-merk" version = "4.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" dependencies = [ "bincode", "bincode_derive", @@ -2723,6 +2730,7 @@ dependencies = [ [[package]] name = "grovedb-mmr" version = "4.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" dependencies = [ "bincode", "blake3", @@ -2733,6 +2741,7 @@ dependencies = [ [[package]] name = "grovedb-path" version = "4.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" dependencies = [ "hex", ] @@ -2740,6 +2749,7 @@ dependencies = [ [[package]] name = "grovedb-storage" version = "4.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" dependencies = [ "blake3", "grovedb-costs", @@ -2758,6 +2768,7 @@ dependencies = [ [[package]] name = "grovedb-version" version = "4.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" dependencies = [ "thiserror 2.0.17", "versioned-feature-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2766,6 +2777,7 @@ dependencies = [ [[package]] name = "grovedb-visualize" version = "4.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" dependencies = [ "hex", "itertools 0.14.0", @@ -2774,6 +2786,7 @@ dependencies = [ [[package]] name = "grovedbg-types" version = "4.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" dependencies = [ "serde", "serde_with 3.16.1", @@ -4372,6 +4385,7 @@ dependencies = [ [[package]] name = "orchard" version = "0.12.0" +source = "git+https://github.com/dashpay/orchard.git?rev=41c8f7169f2683c99cf0e0c63e8d25ec12c47a79#41c8f7169f2683c99cf0e0c63e8d25ec12c47a79" dependencies = [ "aes", "bitvec", @@ -8293,6 +8307,7 @@ dependencies = [ [[package]] name = "zcash_note_encryption" version = "0.4.1" +source = "git+https://github.com/dashpay/zcash_note_encryption?rev=9f7e93d#9f7e93d42cef839d02b9d75918117941d453f8cb" dependencies = [ "chacha20", "chacha20poly1305", diff --git a/packages/dapi-grpc/clients/core/v0/nodejs/core_protoc.js b/packages/dapi-grpc/clients/core/v0/nodejs/core_protoc.js index 5d91bb2c010..5bf2a3edaeb 100644 --- a/packages/dapi-grpc/clients/core/v0/nodejs/core_protoc.js +++ b/packages/dapi-grpc/clients/core/v0/nodejs/core_protoc.js @@ -13,44 +13,44 @@ var jspb = require('google-protobuf'); var goog = jspb; -var global = Function('return this')(); - -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeaders', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksRequest.FromBlockCase', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksResponse.ResponsesCase', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BloomFilter', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastTransactionRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastTransactionResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBestBlockHeightRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBestBlockHeightResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockRequest.BlockCase', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Chain', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Network', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.NetworkFee', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Status', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Time', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Version', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetEstimatedTransactionFeeRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetEstimatedTransactionFeeResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusResponse.Status', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetTransactionRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetTransactionResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.InstantSendLockMessages', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.MasternodeListRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.MasternodeListResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.RawTransactions', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsRequest.FromBlockCase', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsResponse.ResponsesCase', null, global); +const proto = {}; + +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeaders', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksRequest.FromBlockCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksResponse.ResponsesCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BloomFilter', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastTransactionRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastTransactionResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBestBlockHeightRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBestBlockHeightResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockRequest.BlockCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Chain', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Network', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.NetworkFee', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Status', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Time', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Version', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetEstimatedTransactionFeeRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetEstimatedTransactionFeeResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusResponse.Status', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetTransactionRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetTransactionResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.InstantSendLockMessages', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.MasternodeListRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.MasternodeListResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.RawTransactions', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsRequest.FromBlockCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsResponse.ResponsesCase', null, { proto }); /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a diff --git a/packages/dapi-grpc/clients/core/v0/web/core_pb.js b/packages/dapi-grpc/clients/core/v0/web/core_pb.js index 5d91bb2c010..5bf2a3edaeb 100644 --- a/packages/dapi-grpc/clients/core/v0/web/core_pb.js +++ b/packages/dapi-grpc/clients/core/v0/web/core_pb.js @@ -13,44 +13,44 @@ var jspb = require('google-protobuf'); var goog = jspb; -var global = Function('return this')(); - -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeaders', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksRequest.FromBlockCase', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksResponse.ResponsesCase', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BloomFilter', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastTransactionRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastTransactionResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBestBlockHeightRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBestBlockHeightResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockRequest.BlockCase', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Chain', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Network', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.NetworkFee', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Status', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Time', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Version', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetEstimatedTransactionFeeRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetEstimatedTransactionFeeResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusResponse.Status', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetTransactionRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetTransactionResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.InstantSendLockMessages', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.MasternodeListRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.MasternodeListResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.RawTransactions', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsRequest.FromBlockCase', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsResponse', null, global); -goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsResponse.ResponsesCase', null, global); +const proto = {}; + +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeaders', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksRequest.FromBlockCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeadersWithChainLocksResponse.ResponsesCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BloomFilter', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastTransactionRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastTransactionResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBestBlockHeightRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBestBlockHeightResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockRequest.BlockCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Chain', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Network', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.NetworkFee', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Status', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Time', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetBlockchainStatusResponse.Version', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetEstimatedTransactionFeeRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetEstimatedTransactionFeeResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetMasternodeStatusResponse.Status', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetTransactionRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetTransactionResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.InstantSendLockMessages', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.MasternodeListRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.MasternodeListResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.RawTransactions', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsRequest.FromBlockCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.TransactionsWithProofsResponse.ResponsesCase', null, { proto }); /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a diff --git a/packages/dapi-grpc/clients/drive/v0/nodejs/drive_protoc.js b/packages/dapi-grpc/clients/drive/v0/nodejs/drive_protoc.js index 1373c867d42..d43136990a8 100644 --- a/packages/dapi-grpc/clients/drive/v0/nodejs/drive_protoc.js +++ b/packages/dapi-grpc/clients/drive/v0/nodejs/drive_protoc.js @@ -13,12 +13,12 @@ var jspb = require('google-protobuf'); var goog = jspb; -var global = Function('return this')(); +const proto = {}; -var platform_v0_platform_pb = require('./platform/v0/platform_pb.js'); +var platform_v0_platform_pb = require('../../../platform/v0/web/platform_pb.js'); goog.object.extend(proto, platform_v0_platform_pb); -goog.exportSymbol('proto.org.dash.platform.drive.v0.GetProofsRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.drive.v0.GetProofsResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.drive.v0.GetProofsRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.drive.v0.GetProofsResponse', null, { proto }); /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a diff --git a/packages/dapi-grpc/clients/drive/v0/web/drive_pb.js b/packages/dapi-grpc/clients/drive/v0/web/drive_pb.js index 1373c867d42..d43136990a8 100644 --- a/packages/dapi-grpc/clients/drive/v0/web/drive_pb.js +++ b/packages/dapi-grpc/clients/drive/v0/web/drive_pb.js @@ -13,12 +13,12 @@ var jspb = require('google-protobuf'); var goog = jspb; -var global = Function('return this')(); +const proto = {}; -var platform_v0_platform_pb = require('./platform/v0/platform_pb.js'); +var platform_v0_platform_pb = require('../../../platform/v0/web/platform_pb.js'); goog.object.extend(proto, platform_v0_platform_pb); -goog.exportSymbol('proto.org.dash.platform.drive.v0.GetProofsRequest', null, global); -goog.exportSymbol('proto.org.dash.platform.drive.v0.GetProofsResponse', null, global); +goog.exportSymbol('proto.org.dash.platform.drive.v0.GetProofsRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.drive.v0.GetProofsResponse', null, { proto }); /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index e10a6610845..24bad8c19e7 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -71,7 +71,7 @@ strum = { version = "0.26", features = ["derive"] } json-schema-compatibility-validator = { path = '../rs-json-schema-compatibility-validator', optional = true } once_cell = "1.19.0" tracing = { version = "0.1.41" } -grovedb-commitment-tree = { path = "../../../grovedb/grovedb-commitment-tree", optional = true } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db", optional = true } [dev-dependencies] tokio = { version = "1.40", features = ["full"] } diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index 125894cbc8a..63e9e73651c 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -82,7 +82,7 @@ derive_more = { version = "1.0", features = ["from", "deref", "deref_mut"] } async-trait = "0.1.77" console-subscriber = { version = "0.4", optional = true } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f", optional = true } -grovedb-commitment-tree = { path = "../../../grovedb/grovedb-commitment-tree" } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db" } sha2 = "0.10" nonempty = "0.11" @@ -105,7 +105,7 @@ dpp = { path = "../rs-dpp", default-features = false, features = [ drive = { path = "../rs-drive", features = ["fixtures-and-mocks"] } drive-proof-verifier = { path = "../rs-drive-proof-verifier" } strategy-tests = { path = "../strategy-tests" } -grovedb-commitment-tree = { path = "../../../grovedb/grovedb-commitment-tree", features = ["client"] } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db", features = ["client"] } assert_matches = "1.5.0" drive-abci = { path = ".", features = ["testing-config", "mocks"] } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f" } diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index ad41153e4e2..d4cb0b97543 100644 --- a/packages/rs-drive/Cargo.toml +++ b/packages/rs-drive/Cargo.toml @@ -52,12 +52,12 @@ enum-map = { version = "2.0.3", optional = true } intmap = { version = "3.0.1", features = ["serde"], optional = true } chrono = { version = "0.4.35", optional = true } itertools = { version = "0.13", optional = true } -grovedb = { path = "../../../grovedb/grovedb", optional = true, default-features = false } -grovedb-costs = { path = "../../../grovedb/costs", optional = true } -grovedb-path = { path = "../../../grovedb/path" } -grovedb-storage = { path = "../../../grovedb/storage", optional = true } -grovedb-version = { path = "../../../grovedb/grovedb-version" } -grovedb-epoch-based-storage-flags = { path = "../../../grovedb/grovedb-epoch-based-storage-flags" } +grovedb = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db", optional = true, default-features = false } +grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db", optional = true } +grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db" } +grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db", optional = true } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db" } +grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db" } [dev-dependencies] criterion = "0.5" diff --git a/packages/rs-platform-version/Cargo.toml b/packages/rs-platform-version/Cargo.toml index 01cae57e095..08bbd48b36d 100644 --- a/packages/rs-platform-version/Cargo.toml +++ b/packages/rs-platform-version/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT" thiserror = { version = "2.0.12" } bincode = { version = "=2.0.1" } versioned-feature-core = { git = "https://github.com/dashpay/versioned-feature-core", version = "1.0.0" } -grovedb-version = { path = "../../../grovedb/grovedb-version" } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db" } [features] mock-versions = [] diff --git a/packages/rs-sdk/Cargo.toml b/packages/rs-sdk/Cargo.toml index 7a95a87dbf6..d67e9504ca4 100644 --- a/packages/rs-sdk/Cargo.toml +++ b/packages/rs-sdk/Cargo.toml @@ -18,7 +18,7 @@ drive = { path = "../rs-drive", default-features = false, features = [ platform-wallet = { path = "../rs-platform-wallet", optional = true } drive-proof-verifier = { path = "../rs-drive-proof-verifier", default-features = false } -grovedb-commitment-tree = { path = "../../../grovedb/grovedb-commitment-tree", features = ["client"], optional = true } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db", features = ["client"], optional = true } dash-context-provider = { path = "../rs-context-provider", default-features = false } dash-platform-macros = { path = "../rs-dash-platform-macros" } http = { version = "1.1" } diff --git a/packages/wasm-dpp2/src/state_transitions/proof_result.rs b/packages/wasm-dpp2/src/state_transitions/proof_result.rs index 619328fbd8b..766f266b4df 100644 --- a/packages/wasm-dpp2/src/state_transitions/proof_result.rs +++ b/packages/wasm-dpp2/src/state_transitions/proof_result.rs @@ -57,7 +57,8 @@ export type StateTransitionProofResultType = | VerifiedNextDistribution | VerifiedAddressInfos | VerifiedIdentityFullWithAddressInfos - | VerifiedIdentityWithAddressInfos; + | VerifiedIdentityWithAddressInfos + | VerifiedShieldedPoolState; "#; #[wasm_bindgen] @@ -734,6 +735,28 @@ fn action_status_to_string(status: dpp::group::group_action_status::GroupActionS } } +// --- VerifiedShieldedPoolState --- + +#[wasm_bindgen(js_name = "VerifiedShieldedPoolState")] +#[derive(Clone, Serialize, Deserialize)] +pub struct VerifiedShieldedPoolStateWasm { + pool_balance: Option, +} + +impl_wasm_type_info!(VerifiedShieldedPoolStateWasm, VerifiedShieldedPoolState); +impl_wasm_conversions!(VerifiedShieldedPoolStateWasm, VerifiedShieldedPoolState); + +#[wasm_bindgen(js_class = VerifiedShieldedPoolState)] +impl VerifiedShieldedPoolStateWasm { + #[wasm_bindgen(getter, js_name = "poolBalance")] + pub fn pool_balance(&self) -> JsValue { + match self.pool_balance { + Some(b) => BigInt::from(b).into(), + None => JsValue::undefined(), + } + } +} + /// Convert a Rust `StateTransitionProofResult` into the corresponding typed /// WASM wrapper, ready to be returned to JavaScript. pub fn convert_proof_result( @@ -894,6 +917,13 @@ pub fn convert_proof_result( } .into() } + + StateTransitionProofResult::VerifiedShieldedPoolState(maybe_balance) => { + VerifiedShieldedPoolStateWasm { + pool_balance: maybe_balance, + } + .into() + } }; Ok(js_value.into()) From 58f9a7daa37b3962ca571e22cd50800f6e8a9afd Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 18 Feb 2026 09:02:46 +0700 Subject: [PATCH 21/40] fix encrypted notes --- packages/rs-dpp/src/shielded/builder.rs | 6 +++ packages/rs-drive-proof-verifier/src/proof.rs | 3 +- packages/rs-drive-proof-verifier/src/types.rs | 2 + .../verify_shielded_encrypted_notes/mod.rs | 2 +- .../verify_shielded_encrypted_notes/v0/mod.rs | 49 ++++++++++++------- 5 files changed, 43 insertions(+), 19 deletions(-) diff --git a/packages/rs-dpp/src/shielded/builder.rs b/packages/rs-dpp/src/shielded/builder.rs index 57c5821c8d6..c533b12f06a 100644 --- a/packages/rs-dpp/src/shielded/builder.rs +++ b/packages/rs-dpp/src/shielded/builder.rs @@ -240,6 +240,12 @@ pub fn build_shield_transition>( memo: [u8; 36], platform_version: &PlatformVersion, ) -> Result { + if fee_strategy.is_empty() { + return Err(ProtocolError::Generic( + "fee_strategy must have at least one step".to_string(), + )); + } + let bundle = build_output_only_bundle(recipient, shield_amount, memo, proving_key)?; let (actions, flags, value_balance, anchor, proof, binding_sig) = serialize_authorized_bundle(&bundle); diff --git a/packages/rs-drive-proof-verifier/src/proof.rs b/packages/rs-drive-proof-verifier/src/proof.rs index 48829762e51..fbdaf6aca65 100644 --- a/packages/rs-drive-proof-verifier/src/proof.rs +++ b/packages/rs-drive-proof-verifier/src/proof.rs @@ -2392,8 +2392,9 @@ impl FromProof for ShieldedEncrypted Some(ShieldedEncryptedNotes( notes .into_iter() - .map(|(cmx, encrypted_note)| ShieldedEncryptedNote { + .map(|(cmx, nullifier, encrypted_note)| ShieldedEncryptedNote { cmx, + nullifier, encrypted_note, }) .collect(), diff --git a/packages/rs-drive-proof-verifier/src/types.rs b/packages/rs-drive-proof-verifier/src/types.rs index 98f31d31e3a..929b905e209 100644 --- a/packages/rs-drive-proof-verifier/src/types.rs +++ b/packages/rs-drive-proof-verifier/src/types.rs @@ -779,6 +779,8 @@ pub struct ShieldedPoolState(pub u64); pub struct ShieldedEncryptedNote { /// The note commitment (cmx), 32 bytes pub cmx: Vec, + /// The nullifier (32 bytes), needed for Rho derivation in trial decryption + pub nullifier: Vec, /// The encrypted note data pub encrypted_note: Vec, } diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/mod.rs index 9cb4beca969..969f319b450 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/mod.rs @@ -15,7 +15,7 @@ impl Drive { max_elements: u32, verify_subset_of_proof: bool, platform_version: &PlatformVersion, - ) -> Result<(RootHash, Vec<(Vec, Vec)>), Error> { + ) -> Result<(RootHash, Vec<(Vec, Vec, Vec)>), Error> { match platform_version .drive .methods diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs index 611fb430590..0f799cc13e0 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs @@ -1,9 +1,9 @@ -use crate::drive::shielded::paths::shielded_credit_pool_notes_path_vec; +use crate::drive::shielded::paths::{shielded_credit_pool_path_vec, SHIELDED_NOTES_KEY}; use crate::drive::Drive; use crate::error::drive::DriveError; use crate::error::Error; use crate::verify::RootHash; -use grovedb::{Element, GroveDb, PathQuery, Query, SizedQuery}; +use grovedb::{Element, GroveDb, PathQuery, Query, QueryItem, SizedQuery, SubqueryBranch}; use platform_version::version::PlatformVersion; impl Drive { @@ -14,7 +14,7 @@ impl Drive { max_elements: u32, verify_subset_of_proof: bool, platform_version: &PlatformVersion, - ) -> Result<(RootHash, Vec<(Vec, Vec)>), Error> { + ) -> Result<(RootHash, Vec<(Vec, Vec, Vec)>), Error> { let effective = if count == 0 || count > max_elements { max_elements } else { @@ -22,19 +22,29 @@ impl Drive { }; let limit = effective.min(u16::MAX as u32) as u16; - let query = if start_index == 0 { - Query::new_range_full() - } else { - let mut q = Query::new(); - q.insert_range_from(start_index.to_be_bytes().to_vec()..); - q - }; + // PathQuery must match the server-side proof generation exactly: + // path = [AddressBalances, "s"], key = [SHIELDED_NOTES_KEY], + // subquery = range_inclusive(start..=end) + let end_index = start_index + limit as u64 - 1; + let mut inner_query = Query::new(); + inner_query.insert_range_inclusive( + start_index.to_be_bytes().to_vec()..=end_index.to_be_bytes().to_vec(), + ); let path_query = PathQuery { - path: shielded_credit_pool_notes_path_vec(), + path: shielded_credit_pool_path_vec(), query: SizedQuery { - query, - limit: Some(limit), + query: Query { + items: vec![QueryItem::Key(vec![SHIELDED_NOTES_KEY])], + default_subquery_branch: SubqueryBranch { + subquery_path: None, + subquery: Some(inner_query.into()), + }, + left_to_right: true, + conditional_subquery_branches: None, + add_parent_tree_on_subquery: false, + }, + limit: None, offset: None, }, }; @@ -49,13 +59,18 @@ impl Drive { for (_, _key, maybe_element) in proved_key_values { match maybe_element { Some(Element::Item(value, _)) => { - // Value format: cmx (32 bytes) || encrypted_note (remaining bytes) - if value.len() <= 32 { + // Value format: cmx (32) || nullifier (32) || encrypted_note (rest) + if value.len() <= 64 { return Err(Error::Drive(DriveError::CorruptedElementType( - "encrypted note value too short: expected more than 32 bytes", + "encrypted note value too short: expected more than 64 bytes (cmx + nullifier + encrypted_note)", ))); } - notes.push((value[..32].to_vec(), value[32..].to_vec())); + // Return (cmx, nullifier, encrypted_note) + notes.push(( + value[..32].to_vec(), + value[32..64].to_vec(), + value[64..].to_vec(), + )); } Some(_) => { return Err(Error::Drive(DriveError::CorruptedElementType( From c817f704ea9bac0d7819da062b6a13d33c8870c8 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 18 Feb 2026 12:31:38 +0700 Subject: [PATCH 22/40] more work --- Cargo.lock | 28 +++++++++---------- packages/rs-dpp/Cargo.toml | 2 +- packages/rs-drive-abci/Cargo.toml | 4 +-- .../v0/mod.rs | 2 +- packages/rs-drive/Cargo.toml | 12 ++++---- .../src/drive/initialization/v3/mod.rs | 2 +- packages/rs-drive/src/fees/op.rs | 2 +- .../grove_insert_empty_tree/v0/mod.rs | 2 +- packages/rs-platform-version/Cargo.toml | 2 +- .../src/system/queries/path_elements.rs | 12 ++++---- packages/rs-sdk/Cargo.toml | 2 +- 11 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e151d0636a..77bf684a789 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2596,7 +2596,7 @@ dependencies = [ [[package]] name = "grovedb" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" +source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" dependencies = [ "axum 0.8.8", "bincode", @@ -2634,7 +2634,7 @@ dependencies = [ [[package]] name = "grovedb-bulk-append-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" +source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" dependencies = [ "bincode", "blake3", @@ -2647,7 +2647,7 @@ dependencies = [ [[package]] name = "grovedb-commitment-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" +source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" dependencies = [ "incrementalmerkletree", "orchard", @@ -2658,7 +2658,7 @@ dependencies = [ [[package]] name = "grovedb-costs" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" +source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" dependencies = [ "integer-encoding", "intmap", @@ -2668,7 +2668,7 @@ dependencies = [ [[package]] name = "grovedb-dense-fixed-sized-merkle-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" +source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" dependencies = [ "bincode", "blake3", @@ -2678,7 +2678,7 @@ dependencies = [ [[package]] name = "grovedb-element" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" +source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" dependencies = [ "bincode", "bincode_derive", @@ -2693,7 +2693,7 @@ dependencies = [ [[package]] name = "grovedb-epoch-based-storage-flags" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" +source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" dependencies = [ "grovedb-costs", "hex", @@ -2705,7 +2705,7 @@ dependencies = [ [[package]] name = "grovedb-merk" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" +source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" dependencies = [ "bincode", "bincode_derive", @@ -2730,7 +2730,7 @@ dependencies = [ [[package]] name = "grovedb-mmr" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" +source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" dependencies = [ "bincode", "blake3", @@ -2741,7 +2741,7 @@ dependencies = [ [[package]] name = "grovedb-path" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" +source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" dependencies = [ "hex", ] @@ -2749,7 +2749,7 @@ dependencies = [ [[package]] name = "grovedb-storage" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" +source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" dependencies = [ "blake3", "grovedb-costs", @@ -2768,7 +2768,7 @@ dependencies = [ [[package]] name = "grovedb-version" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" +source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" dependencies = [ "thiserror 2.0.17", "versioned-feature-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2777,7 +2777,7 @@ dependencies = [ [[package]] name = "grovedb-visualize" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" +source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" dependencies = [ "hex", "itertools 0.14.0", @@ -2786,7 +2786,7 @@ dependencies = [ [[package]] name = "grovedbg-types" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=8a8852060a7bb2a92b9016622ce67cb68a86e8db#8a8852060a7bb2a92b9016622ce67cb68a86e8db" +source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" dependencies = [ "serde", "serde_with 3.16.1", diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index 24bad8c19e7..103bbb48d7c 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -71,7 +71,7 @@ strum = { version = "0.26", features = ["derive"] } json-schema-compatibility-validator = { path = '../rs-json-schema-compatibility-validator', optional = true } once_cell = "1.19.0" tracing = { version = "0.1.41" } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db", optional = true } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1", optional = true } [dev-dependencies] tokio = { version = "1.40", features = ["full"] } diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index 63e9e73651c..98c03d97d4d 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -82,7 +82,7 @@ derive_more = { version = "1.0", features = ["from", "deref", "deref_mut"] } async-trait = "0.1.77" console-subscriber = { version = "0.4", optional = true } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f", optional = true } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db" } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1" } sha2 = "0.10" nonempty = "0.11" @@ -105,7 +105,7 @@ dpp = { path = "../rs-dpp", default-features = false, features = [ drive = { path = "../rs-drive", features = ["fixtures-and-mocks"] } drive-proof-verifier = { path = "../rs-drive-proof-verifier" } strategy-tests = { path = "../strategy-tests" } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db", features = ["client"] } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1", features = ["client"] } assert_matches = "1.5.0" drive-abci = { path = ".", features = ["testing-config", "mocks"] } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f" } 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 28337d5fdf1..7fe26966ae5 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 @@ -631,7 +631,7 @@ impl Platform { self.drive.grove_insert_if_not_exists( (&shielded_pool_path).into(), &[SHIELDED_NOTES_KEY], - Element::empty_commitment_tree(2048), + Element::empty_commitment_tree(11), Some(transaction), None, &platform_version.drive, diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index d4cb0b97543..bc6d06fbbb8 100644 --- a/packages/rs-drive/Cargo.toml +++ b/packages/rs-drive/Cargo.toml @@ -52,12 +52,12 @@ enum-map = { version = "2.0.3", optional = true } intmap = { version = "3.0.1", features = ["serde"], optional = true } chrono = { version = "0.4.35", optional = true } itertools = { version = "0.13", optional = true } -grovedb = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db", optional = true, default-features = false } -grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db", optional = true } -grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db" } -grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db", optional = true } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db" } -grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db" } +grovedb = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1", optional = true, default-features = false } +grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1", optional = true } +grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1" } +grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1", optional = true } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1" } +grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1" } [dev-dependencies] criterion = "0.5" diff --git a/packages/rs-drive/src/drive/initialization/v3/mod.rs b/packages/rs-drive/src/drive/initialization/v3/mod.rs index b2b97b9c371..b406520197b 100644 --- a/packages/rs-drive/src/drive/initialization/v3/mod.rs +++ b/packages/rs-drive/src/drive/initialization/v3/mod.rs @@ -82,7 +82,7 @@ impl Drive { batch.add_insert( shielded_credit_pool_path_vec(), vec![SHIELDED_NOTES_KEY], - Element::empty_commitment_tree(2048), + Element::empty_commitment_tree(11), ); // 3. Nullifiers tree (NormalTree) diff --git a/packages/rs-drive/src/fees/op.rs b/packages/rs-drive/src/fees/op.rs index 0b3d4115be8..22f03821bf4 100644 --- a/packages/rs-drive/src/fees/op.rs +++ b/packages/rs-drive/src/fees/op.rs @@ -580,7 +580,7 @@ impl LowLevelDriveOperationTreeTypeConverter for TreeType { Element::empty_provable_count_sum_tree_with_flags(element_flags) } TreeType::CommitmentTree => { - Element::empty_commitment_tree_with_flags(2048, element_flags) + Element::empty_commitment_tree_with_flags(11, element_flags) } TreeType::MmrTree => Element::empty_mmr_tree_with_flags(element_flags), TreeType::BulkAppendTree => { diff --git a/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs index 3c4ee655b0b..db95af541c8 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs @@ -28,7 +28,7 @@ impl Drive { TreeType::CountSumTree => Element::empty_count_sum_tree(), TreeType::ProvableCountTree => Element::empty_provable_count_tree(), TreeType::ProvableCountSumTree => Element::empty_provable_count_sum_tree(), - TreeType::CommitmentTree => Element::empty_commitment_tree(2048), + TreeType::CommitmentTree => Element::empty_commitment_tree(11), TreeType::MmrTree => Element::empty_mmr_tree(), TreeType::BulkAppendTree => Element::empty_bulk_append_tree(4), TreeType::DenseAppendOnlyFixedSizeTree => Element::empty_dense_tree(8), diff --git a/packages/rs-platform-version/Cargo.toml b/packages/rs-platform-version/Cargo.toml index 08bbd48b36d..837000ca662 100644 --- a/packages/rs-platform-version/Cargo.toml +++ b/packages/rs-platform-version/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT" thiserror = { version = "2.0.12" } bincode = { version = "=2.0.1" } versioned-feature-core = { git = "https://github.com/dashpay/versioned-feature-core", version = "1.0.0" } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db" } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1" } [features] mock-versions = [] diff --git a/packages/rs-sdk-ffi/src/system/queries/path_elements.rs b/packages/rs-sdk-ffi/src/system/queries/path_elements.rs index cb9f8f87ce9..3e0678f8168 100644 --- a/packages/rs-sdk-ffi/src/system/queries/path_elements.rs +++ b/packages/rs-sdk-ffi/src/system/queries/path_elements.rs @@ -159,11 +159,11 @@ fn get_path_elements( Element::CommitmentTree(_, _, _, _) => { "commitment_tree".to_string() } - Element::MmrTree(_, _, _, _) => "mmr_tree".to_string(), - Element::BulkAppendTree(_, _, _, _, _) => { + Element::MmrTree(_, _, _) => "mmr_tree".to_string(), + Element::BulkAppendTree(_, _, _, _) => { "bulk_append_tree".to_string() } - Element::DenseAppendOnlyFixedSizeTree(_, _, _, _, _) => { + Element::DenseAppendOnlyFixedSizeTree(_, _, _, _) => { "dense_tree".to_string() } }; @@ -187,9 +187,9 @@ fn get_path_elements( "provable_count_sum_tree" } Element::CommitmentTree(_, _, _, _) => "commitment_tree", - Element::MmrTree(_, _, _, _) => "mmr_tree", - Element::BulkAppendTree(_, _, _, _, _) => "bulk_append_tree", - Element::DenseAppendOnlyFixedSizeTree(_, _, _, _, _) => + Element::MmrTree(_, _, _) => "mmr_tree", + Element::BulkAppendTree(_, _, _, _) => "bulk_append_tree", + Element::DenseAppendOnlyFixedSizeTree(_, _, _, _) => "dense_tree", } ) diff --git a/packages/rs-sdk/Cargo.toml b/packages/rs-sdk/Cargo.toml index d67e9504ca4..35e52438b08 100644 --- a/packages/rs-sdk/Cargo.toml +++ b/packages/rs-sdk/Cargo.toml @@ -18,7 +18,7 @@ drive = { path = "../rs-drive", default-features = false, features = [ platform-wallet = { path = "../rs-platform-wallet", optional = true } drive-proof-verifier = { path = "../rs-drive-proof-verifier", default-features = false } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "8a8852060a7bb2a92b9016622ce67cb68a86e8db", features = ["client"], optional = true } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1", features = ["client"], optional = true } dash-context-provider = { path = "../rs-context-provider", default-features = false } dash-platform-macros = { path = "../rs-dash-platform-macros" } http = { version = "1.1" } From 24df2306c3c72b5bebcf19050ec44ca4b79365ce Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 18 Feb 2026 21:24:21 +0700 Subject: [PATCH 23/40] more work --- .../src/verify/shielded/verify_shielded_nullifiers/v0/mod.rs | 2 +- packages/rs-sdk/src/lib.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/v0/mod.rs index 289a14606fc..4725b9ba841 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/v0/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_nullifiers/v0/mod.rs @@ -19,7 +19,7 @@ impl Drive { path: shielded_credit_pool_nullifiers_path_vec(), query: SizedQuery { query, - limit: None, + limit: Some(nullifiers.len() as u16), offset: None, }, }; diff --git a/packages/rs-sdk/src/lib.rs b/packages/rs-sdk/src/lib.rs index 0b17ba0cb5c..9034582b60b 100644 --- a/packages/rs-sdk/src/lib.rs +++ b/packages/rs-sdk/src/lib.rs @@ -82,6 +82,8 @@ pub use drive; pub use drive_proof_verifier::types as query_types; pub use drive_proof_verifier::Error as ProofVerifierError; #[cfg(feature = "shielded")] +pub mod shielded; +#[cfg(feature = "shielded")] pub use grovedb_commitment_tree; #[cfg(feature = "platform-wallet")] pub use platform_wallet; From aa9af759cea28da9b3d07f3a5ffc93a46440fce4 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Thu, 19 Feb 2026 05:48:06 +0700 Subject: [PATCH 24/40] more work --- Cargo.lock | 185 ++++++++++++------ Dockerfile | 2 +- packages/rs-dpp/Cargo.toml | 2 +- packages/rs-drive-abci/Cargo.toml | 4 +- .../shielded_transfer/tests.rs | 12 +- .../shielded_withdrawal/tests.rs | 18 +- .../state_transitions/unshield/tests.rs | 12 +- .../tests/strategy_tests/strategy.rs | 12 +- packages/rs-drive/Cargo.toml | 12 +- packages/rs-platform-version/Cargo.toml | 2 +- packages/rs-sdk/Cargo.toml | 2 +- packages/rs-sdk/src/shielded.rs | 67 +++++++ packages/wasm-dpp/Cargo.toml | 4 +- packages/wasm-dpp2/Cargo.toml | 4 +- packages/wasm-drive-verify/Cargo.toml | 2 +- packages/wasm-sdk/Cargo.toml | 4 +- scripts/setup-ai-agent-environment.sh | 2 +- 17 files changed, 239 insertions(+), 107 deletions(-) create mode 100644 packages/rs-sdk/src/shielded.rs diff --git a/Cargo.lock b/Cargo.lock index 77bf684a789..e0bb175667b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2237,6 +2237,18 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + [[package]] name = "fancy-regex" version = "0.13.0" @@ -2596,7 +2608,7 @@ dependencies = [ [[package]] name = "grovedb" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" +source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" dependencies = [ "axum 0.8.8", "bincode", @@ -2634,7 +2646,7 @@ dependencies = [ [[package]] name = "grovedb-bulk-append-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" +source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" dependencies = [ "bincode", "blake3", @@ -2647,10 +2659,11 @@ dependencies = [ [[package]] name = "grovedb-commitment-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" +source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" dependencies = [ "incrementalmerkletree", "orchard", + "rusqlite", "shardtree", "thiserror 2.0.17", ] @@ -2658,7 +2671,7 @@ dependencies = [ [[package]] name = "grovedb-costs" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" +source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" dependencies = [ "integer-encoding", "intmap", @@ -2668,7 +2681,7 @@ dependencies = [ [[package]] name = "grovedb-dense-fixed-sized-merkle-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" +source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" dependencies = [ "bincode", "blake3", @@ -2678,7 +2691,7 @@ dependencies = [ [[package]] name = "grovedb-element" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" +source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" dependencies = [ "bincode", "bincode_derive", @@ -2693,7 +2706,7 @@ dependencies = [ [[package]] name = "grovedb-epoch-based-storage-flags" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" +source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" dependencies = [ "grovedb-costs", "hex", @@ -2705,7 +2718,7 @@ dependencies = [ [[package]] name = "grovedb-merk" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" +source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" dependencies = [ "bincode", "bincode_derive", @@ -2730,7 +2743,7 @@ dependencies = [ [[package]] name = "grovedb-mmr" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" +source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" dependencies = [ "bincode", "blake3", @@ -2741,7 +2754,7 @@ dependencies = [ [[package]] name = "grovedb-path" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" +source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" dependencies = [ "hex", ] @@ -2749,7 +2762,7 @@ dependencies = [ [[package]] name = "grovedb-storage" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" +source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" dependencies = [ "blake3", "grovedb-costs", @@ -2768,7 +2781,7 @@ dependencies = [ [[package]] name = "grovedb-version" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" +source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" dependencies = [ "thiserror 2.0.17", "versioned-feature-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2777,7 +2790,7 @@ dependencies = [ [[package]] name = "grovedb-visualize" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" +source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" dependencies = [ "hex", "itertools 0.14.0", @@ -2786,7 +2799,7 @@ dependencies = [ [[package]] name = "grovedbg-types" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=d5bec5bfc288c6384cea00a544e6abb970f8d3c1#d5bec5bfc288c6384cea00a544e6abb970f8d3c1" +source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" dependencies = [ "serde", "serde_with 3.16.1", @@ -2915,6 +2928,15 @@ dependencies = [ "foldhash 0.2.0", ] +[[package]] +name = "hashlink" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea0b22561a9c04a7cb1a302c013e0259cd3b4bb619f145b32f72b8b4bcbed230" +dependencies = [ + "hashbrown 0.16.1", +] + [[package]] name = "hdrhistogram" version = "7.5.4" @@ -3549,9 +3571,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.80" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" dependencies = [ "once_cell", "wasm-bindgen", @@ -3769,6 +3791,17 @@ dependencies = [ "zstd-sys", ] +[[package]] +name = "libsqlite3-sys" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b4103cffefa72eb8428cb6b47d6627161e51c2739fc5e3b734584157bc642a" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "libz-rs-sys" version = "0.5.5" @@ -4249,6 +4282,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -5625,6 +5659,16 @@ dependencies = [ "libc", ] +[[package]] +name = "rsqlite-vfs" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a1f2315036ef6b1fbacd1972e8ee7688030b0a2121edfc2a6550febd41574d" +dependencies = [ + "hashbrown 0.16.1", + "thiserror 2.0.17", +] + [[package]] name = "rtoolbox" version = "0.0.3" @@ -5635,6 +5679,21 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rusqlite" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1c93dd1c9683b438c392c492109cb702b8090b2bfc8fed6f6e4eb4523f17af3" +dependencies = [ + "bitflags 2.10.0", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", + "sqlite-wasm-rs", +] + [[package]] name = "rust_decimal" version = "1.39.0" @@ -5956,17 +6015,7 @@ dependencies = [ [[package]] name = "serde-wasm-bindgen" version = "0.5.0" -source = "git+https://github.com/QuantumExplorer/serde-wasm-bindgen?branch=feat%2Fnot_human_readable#121d1f7fbf62cb97f74b91626a1b23851098cc82" -dependencies = [ - "js-sys", - "serde", - "wasm-bindgen", -] - -[[package]] -name = "serde-wasm-bindgen" -version = "0.5.0" -source = "git+https://github.com/dashpay/serde-wasm-bindgen?branch=fix%2Fuint8array-to-bytes#c909c5759c9ca997abe96283edd8e23cb64b4ce0" +source = "git+https://github.com/dashpay/serde-wasm-bindgen?rev=0d3e1a8ff058b400bab3a8ececd2fb9581e8c287#0d3e1a8ff058b400bab3a8ececd2fb9581e8c287" dependencies = [ "js-sys", "serde", @@ -6361,6 +6410,18 @@ dependencies = [ "der", ] +[[package]] +name = "sqlite-wasm-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4206ed3a67690b9c29b77d728f6acc3ce78f16bf846d83c94f76400320181b" +dependencies = [ + "cc", + "js-sys", + "rsqlite-vfs", + "wasm-bindgen", +] + [[package]] name = "sqlparser" version = "0.38.0" @@ -7611,9 +7672,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.103" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" dependencies = [ "cfg-if", "once_cell", @@ -7624,27 +7685,14 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.111", - "wasm-bindgen-shared", -] - [[package]] name = "wasm-bindgen-futures" -version = "0.4.53" +version = "0.4.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0b221ff421256839509adbb55998214a70d829d3a28c69b4a6672e9d2a42f67" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" dependencies = [ "cfg-if", + "futures-util", "js-sys", "once_cell", "wasm-bindgen", @@ -7653,9 +7701,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.103" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -7663,50 +7711,65 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.103" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn 2.0.111", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.103" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" dependencies = [ "unicode-ident", ] [[package]] name = "wasm-bindgen-test" -version = "0.3.53" +version = "0.3.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aee0a0f5343de9221a0d233b04520ed8dc2e6728dce180b1dcd9288ec9d9fa3c" +checksum = "45649196a53b0b7a15101d845d44d2dda7374fc1b5b5e2bbf58b7577ff4b346d" dependencies = [ + "async-trait", + "cast", "js-sys", + "libm", "minicov", + "nu-ansi-term", + "num-traits", + "oorandom", + "serde", + "serde_json", "wasm-bindgen", "wasm-bindgen-futures", "wasm-bindgen-test-macro", + "wasm-bindgen-test-shared", ] [[package]] name = "wasm-bindgen-test-macro" -version = "0.3.53" +version = "0.3.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a369369e4360c2884c3168d22bded735c43cccae97bbc147586d4b480edd138d" +checksum = "f579cdd0123ac74b94e1a4a72bd963cf30ebac343f2df347da0b8df24cdebed2" dependencies = [ "proc-macro2", "quote", "syn 2.0.111", ] +[[package]] +name = "wasm-bindgen-test-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8145dd1593bf0fb137dbfa85b8be79ec560a447298955877804640e40c2d6ea" + [[package]] name = "wasm-dpp" version = "3.0.1" @@ -7722,7 +7785,7 @@ dependencies = [ "num_enum 0.7.5", "paste", "serde", - "serde-wasm-bindgen 0.5.0 (git+https://github.com/QuantumExplorer/serde-wasm-bindgen?branch=feat%2Fnot_human_readable)", + "serde-wasm-bindgen 0.5.0", "serde_json", "thiserror 2.0.17", "wasm-bindgen", @@ -7741,7 +7804,7 @@ dependencies = [ "hex", "js-sys", "serde", - "serde-wasm-bindgen 0.5.0 (git+https://github.com/dashpay/serde-wasm-bindgen?branch=fix%2Fuint8array-to-bytes)", + "serde-wasm-bindgen 0.5.0", "serde_json", "sha2", "thiserror 1.0.69", @@ -7802,7 +7865,7 @@ dependencies = [ "rs-dapi-client", "rs-sdk-trusted-context-provider", "serde", - "serde-wasm-bindgen 0.5.0 (git+https://github.com/dashpay/serde-wasm-bindgen?branch=fix%2Fuint8array-to-bytes)", + "serde-wasm-bindgen 0.5.0", "serde_json", "sha2", "thiserror 2.0.17", @@ -7830,9 +7893,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.80" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbe734895e869dc429d78c4b433f8d17d95f8d05317440b4fad5ab2d33e596dc" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/Dockerfile b/Dockerfile index 4691e520b39..971dd07c627 100644 --- a/Dockerfile +++ b/Dockerfile @@ -347,7 +347,7 @@ RUN --mount=type=secret,id=AWS \ RUN --mount=type=secret,id=AWS \ source /root/env; \ - cargo binstall wasm-bindgen-cli@0.2.103 cargo-chef@0.1.72 \ + cargo binstall wasm-bindgen-cli@0.2.108 cargo-chef@0.1.72 \ --locked \ --no-discover-github-token \ --disable-telemetry \ diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index 103bbb48d7c..7b776e19698 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -71,7 +71,7 @@ strum = { version = "0.26", features = ["derive"] } json-schema-compatibility-validator = { path = '../rs-json-schema-compatibility-validator', optional = true } once_cell = "1.19.0" tracing = { version = "0.1.41" } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1", optional = true } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8", optional = true } [dev-dependencies] tokio = { version = "1.40", features = ["full"] } diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index 98c03d97d4d..aef0dc90623 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -82,7 +82,7 @@ derive_more = { version = "1.0", features = ["from", "deref", "deref_mut"] } async-trait = "0.1.77" console-subscriber = { version = "0.4", optional = true } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f", optional = true } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1" } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8" } sha2 = "0.10" nonempty = "0.11" @@ -105,7 +105,7 @@ dpp = { path = "../rs-dpp", default-features = false, features = [ drive = { path = "../rs-drive", features = ["fixtures-and-mocks"] } drive-proof-verifier = { path = "../rs-drive-proof-verifier" } strategy-tests = { path = "../strategy-tests" } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1", features = ["client"] } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8", features = ["client"] } assert_matches = "1.5.0" drive-abci = { path = ".", features = ["testing-config", "mocks"] } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f" } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs index 94912509794..017f706507b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs @@ -231,8 +231,8 @@ mod tests { use super::*; use grovedb_commitment_tree::{ Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - ClientCommitmentTree, DashMemo, ExtractedNoteCommitment, FullViewingKey, MerklePath, - Note, NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, + ClientMemoryCommitmentTree, DashMemo, ExtractedNoteCommitment, FullViewingKey, + MerklePath, Note, NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, }; use rand::rngs::OsRng; @@ -324,7 +324,7 @@ mod tests { // --- Build commitment tree and get anchor + merkle path --- let cmx = ExtractedNoteCommitment::from(note.commitment()); - let mut tree = ClientCommitmentTree::new(100); + let mut tree = ClientMemoryCommitmentTree::new(100); tree.append(cmx.to_bytes(), Retention::Marked).unwrap(); tree.checkpoint(0u32).unwrap(); let anchor = tree.anchor().unwrap(); @@ -418,8 +418,8 @@ mod tests { use super::*; use grovedb_commitment_tree::{ Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - ClientCommitmentTree, DashMemo, ExtractedNoteCommitment, FullViewingKey, MerklePath, - Note, NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, + ClientMemoryCommitmentTree, DashMemo, ExtractedNoteCommitment, FullViewingKey, + MerklePath, Note, NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, }; use rand::rngs::OsRng; @@ -483,7 +483,7 @@ mod tests { Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); let cmx = ExtractedNoteCommitment::from(note.commitment()); - let mut tree = ClientCommitmentTree::new(100); + let mut tree = ClientMemoryCommitmentTree::new(100); tree.append(cmx.to_bytes(), Retention::Marked).unwrap(); tree.checkpoint(0u32).unwrap(); let anchor = tree.anchor().unwrap(); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs index 1ae966236f4..2a3591f7747 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs @@ -385,9 +385,10 @@ mod tests { mod proof_verification { use super::*; use grovedb_commitment_tree::{ - Authorized as OrchardAuthorized, Builder, Bundle, BundleType, ClientCommitmentTree, - DashMemo, ExtractedNoteCommitment, FullViewingKey, Note, NoteValue, Position, - ProvingKey, RandomSeed, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, + Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + ClientMemoryCommitmentTree, DashMemo, ExtractedNoteCommitment, FullViewingKey, Note, + NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, + SpendAuthorizingKey, SpendingKey, }; use rand::rngs::OsRng; use std::sync::OnceLock; @@ -483,7 +484,7 @@ mod tests { // --- Build commitment tree and get anchor + merkle path --- let cmx = ExtractedNoteCommitment::from(note.commitment()); - let mut tree = ClientCommitmentTree::new(100); + let mut tree = ClientMemoryCommitmentTree::new(100); tree.append(cmx.to_bytes(), Retention::Marked).unwrap(); tree.checkpoint(0u32).unwrap(); let anchor = tree.anchor().unwrap(); @@ -599,9 +600,10 @@ mod tests { mod security_audit { use super::*; use grovedb_commitment_tree::{ - Authorized as OrchardAuthorized, Builder, Bundle, BundleType, ClientCommitmentTree, - DashMemo, ExtractedNoteCommitment, FullViewingKey, Note, NoteValue, Position, - ProvingKey, RandomSeed, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, + Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + ClientMemoryCommitmentTree, DashMemo, ExtractedNoteCommitment, FullViewingKey, Note, + NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, + SpendAuthorizingKey, SpendingKey, }; use rand::rngs::OsRng; use std::sync::OnceLock; @@ -668,7 +670,7 @@ mod tests { Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); let cmx = ExtractedNoteCommitment::from(note.commitment()); - let mut tree = ClientCommitmentTree::new(100); + let mut tree = ClientMemoryCommitmentTree::new(100); tree.append(cmx.to_bytes(), Retention::Marked).unwrap(); tree.checkpoint(0u32).unwrap(); let anchor = tree.anchor().unwrap(); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs index 265576a66a0..a65d0ebbb49 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs @@ -355,8 +355,8 @@ mod tests { use super::*; use grovedb_commitment_tree::{ Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - ClientCommitmentTree, DashMemo, ExtractedNoteCommitment, FullViewingKey, MerklePath, - Note, NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, + ClientMemoryCommitmentTree, DashMemo, ExtractedNoteCommitment, FullViewingKey, + MerklePath, Note, NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, }; use rand::rngs::OsRng; @@ -450,7 +450,7 @@ mod tests { // --- Build commitment tree and get anchor + merkle path --- let cmx = ExtractedNoteCommitment::from(note.commitment()); - let mut tree = ClientCommitmentTree::new(100); + let mut tree = ClientMemoryCommitmentTree::new(100); tree.append(cmx.to_bytes(), Retention::Marked).unwrap(); tree.checkpoint(0u32).unwrap(); let anchor = tree.anchor().unwrap(); @@ -556,8 +556,8 @@ mod tests { use super::*; use grovedb_commitment_tree::{ Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, - ClientCommitmentTree, DashMemo, ExtractedNoteCommitment, FullViewingKey, MerklePath, - Note, NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, + ClientMemoryCommitmentTree, DashMemo, ExtractedNoteCommitment, FullViewingKey, + MerklePath, Note, NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, SpendAuthorizingKey, SpendingKey, }; use rand::rngs::OsRng; @@ -625,7 +625,7 @@ mod tests { Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); let cmx = ExtractedNoteCommitment::from(note.commitment()); - let mut tree = ClientCommitmentTree::new(100); + let mut tree = ClientMemoryCommitmentTree::new(100); tree.append(cmx.to_bytes(), Retention::Marked).unwrap(); tree.checkpoint(0u32).unwrap(); let anchor = tree.anchor().unwrap(); diff --git a/packages/rs-drive-abci/tests/strategy_tests/strategy.rs b/packages/rs-drive-abci/tests/strategy_tests/strategy.rs index fbae6c67d5f..d4d507aef7c 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/strategy.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/strategy.rs @@ -17,10 +17,10 @@ use dpp::state_transition::unshield_transition::methods::UnshieldTransitionMetho use dpp::state_transition::unshield_transition::UnshieldTransition; use dpp::ProtocolError; use grovedb_commitment_tree::{ - Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, ClientCommitmentTree, - DashMemo, ExtractedNoteCommitment, Flags as OrchardFlags, FullViewingKey, MerklePath, Note, - NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, SpendAuthorizingKey, - SpendingKey, + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + ClientMemoryCommitmentTree, DashMemo, ExtractedNoteCommitment, Flags as OrchardFlags, + FullViewingKey, MerklePath, Note, NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, + Scope, SpendAuthorizingKey, SpendingKey, }; use dpp::dashcore::secp256k1::SecretKey; @@ -155,7 +155,7 @@ const TEST_SK_BYTES: [u8; 32] = [0u8; 32]; /// with valid Merkle witnesses. pub struct ShieldedState { /// Local commitment tree mirroring the on-chain tree. - pub tree: ClientCommitmentTree, + pub tree: ClientMemoryCommitmentTree, /// Spendable notes: (Note, Position in commitment tree). /// Notes are removed once spent. pub spendable_notes: Vec<(Note, Position)>, @@ -178,7 +178,7 @@ impl ShieldedState { let fvk = FullViewingKey::from(&sk); let ask = SpendAuthorizingKey::from(&sk); Self { - tree: ClientCommitmentTree::new(1000), + tree: ClientMemoryCommitmentTree::new(1000), spendable_notes: Vec::new(), checkpoint_counter: 0, sk, diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index bc6d06fbbb8..76bb43bf626 100644 --- a/packages/rs-drive/Cargo.toml +++ b/packages/rs-drive/Cargo.toml @@ -52,12 +52,12 @@ enum-map = { version = "2.0.3", optional = true } intmap = { version = "3.0.1", features = ["serde"], optional = true } chrono = { version = "0.4.35", optional = true } itertools = { version = "0.13", optional = true } -grovedb = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1", optional = true, default-features = false } -grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1", optional = true } -grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1" } -grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1", optional = true } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1" } -grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1" } +grovedb = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8", optional = true, default-features = false } +grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8", optional = true } +grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8" } +grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8", optional = true } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8" } +grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8" } [dev-dependencies] criterion = "0.5" diff --git a/packages/rs-platform-version/Cargo.toml b/packages/rs-platform-version/Cargo.toml index 837000ca662..55839797ad2 100644 --- a/packages/rs-platform-version/Cargo.toml +++ b/packages/rs-platform-version/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT" thiserror = { version = "2.0.12" } bincode = { version = "=2.0.1" } versioned-feature-core = { git = "https://github.com/dashpay/versioned-feature-core", version = "1.0.0" } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1" } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8" } [features] mock-versions = [] diff --git a/packages/rs-sdk/Cargo.toml b/packages/rs-sdk/Cargo.toml index 35e52438b08..158aa59ae54 100644 --- a/packages/rs-sdk/Cargo.toml +++ b/packages/rs-sdk/Cargo.toml @@ -18,7 +18,7 @@ drive = { path = "../rs-drive", default-features = false, features = [ platform-wallet = { path = "../rs-platform-wallet", optional = true } drive-proof-verifier = { path = "../rs-drive-proof-verifier", default-features = false } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "d5bec5bfc288c6384cea00a544e6abb970f8d3c1", features = ["client"], optional = true } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8", features = ["client", "sqlite"], optional = true } dash-context-provider = { path = "../rs-context-provider", default-features = false } dash-platform-macros = { path = "../rs-dash-platform-macros" } http = { version = "1.1" } diff --git a/packages/rs-sdk/src/shielded.rs b/packages/rs-sdk/src/shielded.rs new file mode 100644 index 00000000000..4683cfa5253 --- /dev/null +++ b/packages/rs-sdk/src/shielded.rs @@ -0,0 +1,67 @@ +//! Shielded note trial decryption utilities. +//! +//! This module provides helpers for performing compact trial decryption on +//! [`ShieldedEncryptedNote`] structs returned by the platform query layer. +//! +//! The [`try_decrypt_note`] function is the primary entry point. It takes a +//! prepared incoming viewing key and a proof-verified encrypted note, and +//! returns the decrypted [`Note`] and recipient [`PaymentAddress`] if the +//! note belongs to the viewer. + +use drive_proof_verifier::types::ShieldedEncryptedNote; +use grovedb_commitment_tree::{ + try_compact_note_decryption, CompactAction, DashMemo, EphemeralKeyBytes, + ExtractedNoteCommitment, Note, Nullifier, OrchardDomain, PaymentAddress, + PreparedIncomingViewingKey, COMPACT_NOTE_SIZE, +}; + +/// Minimum length of the `encrypted_note` field for compact trial decryption. +/// +/// The `encrypted_note` field layout is: +/// `epk(32) || enc_ciphertext(104) || out_ciphertext(80)` = 216 bytes +/// +/// For compact decryption we need at least `epk(32) + COMPACT_NOTE_SIZE` bytes +/// of the enc_ciphertext. +const MIN_ENCRYPTED_NOTE_LEN: usize = 32 + COMPACT_NOTE_SIZE; + +/// Attempt compact trial decryption on a [`ShieldedEncryptedNote`]. +/// +/// The [`ShieldedEncryptedNote`] struct (from proof verification) has three +/// separate fields: +/// - `cmx`: note commitment (32 bytes) +/// - `nullifier`: nullifier (32 bytes) — used for Rho derivation +/// - `encrypted_note`: `epk(32) || enc_ciphertext(104) || out_ciphertext(80)` +/// +/// Returns `Some((note, address))` if the note decrypts successfully under the +/// given incoming viewing key, or `None` if it does not belong to the viewer +/// (including dummy/padding notes). +pub fn try_decrypt_note( + ivk: &PreparedIncomingViewingKey, + encrypted_note: &ShieldedEncryptedNote, +) -> Option<(Note, PaymentAddress)> { + let data = &encrypted_note.encrypted_note; + if data.len() < MIN_ENCRYPTED_NOTE_LEN { + return None; + } + + // Parse nullifier from the dedicated field (32 bytes) + let nf_bytes: [u8; 32] = encrypted_note.nullifier.as_slice().try_into().ok()?; + let nf = Nullifier::from_bytes(&nf_bytes).into_option()?; + + // Parse cmx from the dedicated field (32 bytes) + let cmx_bytes: [u8; 32] = encrypted_note.cmx.as_slice().try_into().ok()?; + let cmx = ExtractedNoteCommitment::from_bytes(&cmx_bytes).into_option()?; + + // Parse ephemeral public key (first 32 bytes of encrypted_note) + let epk_bytes: [u8; 32] = data[0..32].try_into().ok()?; + + // Parse compact ciphertext (first COMPACT_NOTE_SIZE bytes of enc_ciphertext, + // starting at byte 32) + let enc_compact: [u8; COMPACT_NOTE_SIZE] = data[32..32 + COMPACT_NOTE_SIZE].try_into().ok()?; + + // Build CompactAction and OrchardDomain for trial decryption + let compact = CompactAction::from_parts(nf, cmx, EphemeralKeyBytes(epk_bytes), enc_compact); + let domain = OrchardDomain::::for_compact_action(&compact); + + try_compact_note_decryption(&domain, ivk, &compact) +} diff --git a/packages/wasm-dpp/Cargo.toml b/packages/wasm-dpp/Cargo.toml index 10015e76d90..6b2d6129701 100644 --- a/packages/wasm-dpp/Cargo.toml +++ b/packages/wasm-dpp/Cargo.toml @@ -18,11 +18,11 @@ 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.103" } +wasm-bindgen = { version = "=0.2.108" } js-sys = "0.3.64" web-sys = { version = "0.3.64", features = ["console"] } thiserror = { version = "2.0.17" } -serde-wasm-bindgen = { git = "https://github.com/QuantumExplorer/serde-wasm-bindgen", branch = "feat/not_human_readable" } +serde-wasm-bindgen = { git = "https://github.com/dashpay/serde-wasm-bindgen", rev = "0d3e1a8ff058b400bab3a8ececd2fb9581e8c287" } dpp = { path = "../rs-dpp", default-features = false, features = [ "state-transition-serde-conversion", "state-transition-value-conversion", diff --git a/packages/wasm-dpp2/Cargo.toml b/packages/wasm-dpp2/Cargo.toml index 0481f70263f..a849f929dbc 100644 --- a/packages/wasm-dpp2/Cargo.toml +++ b/packages/wasm-dpp2/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["cdylib", "lib"] # TODO: Consider to use talc allocator #talc = { version = "=4.4.2", default-features = false, features = ["lock_api"] } bincode = "=2.0.1" -wasm-bindgen = { version = "=0.2.103", default-features = false, features = [ +wasm-bindgen = { version = "=0.2.108", default-features = false, features = [ "serde-serialize", ] } dpp = { path = "../rs-dpp", default-features = false, features = [ @@ -28,7 +28,7 @@ dpp = { path = "../rs-dpp", default-features = false, features = [ "state-transition-serde-conversion", "vote-serde-conversion", ] } -serde-wasm-bindgen = { git = "https://github.com/dashpay/serde-wasm-bindgen", branch = "fix/uint8array-to-bytes" } +serde-wasm-bindgen = { git = "https://github.com/dashpay/serde-wasm-bindgen", rev = "0d3e1a8ff058b400bab3a8ececd2fb9581e8c287" } serde = { version = "1.0.197", features = ["derive"] } serde_json = { version = "1.0", features = ["preserve_order"] } js-sys = "0.3.77" diff --git a/packages/wasm-drive-verify/Cargo.toml b/packages/wasm-drive-verify/Cargo.toml index 7ec72ab367f..8bb8044e8bb 100644 --- a/packages/wasm-drive-verify/Cargo.toml +++ b/packages/wasm-drive-verify/Cargo.toml @@ -27,7 +27,7 @@ dpp = { path = "../rs-dpp", default-features = false, features = [ ] } bincode = { version = "=2.0.1" } -wasm-bindgen = { version = "=0.2.103" } +wasm-bindgen = { version = "=0.2.108" } serde = { version = "1.0.193", default-features = false, features = [ "alloc", "derive", diff --git a/packages/wasm-sdk/Cargo.toml b/packages/wasm-sdk/Cargo.toml index 11b6b9cc45d..e455682d136 100644 --- a/packages/wasm-sdk/Cargo.toml +++ b/packages/wasm-sdk/Cargo.toml @@ -64,7 +64,7 @@ drive = { path = "../rs-drive", default-features = false, features = [ ] } console_error_panic_hook = { version = "0.1.6" } thiserror = { version = "2.0.17" } -wasm-bindgen = { version = "=0.2.103" } +wasm-bindgen = { version = "=0.2.108" } wasm-bindgen-futures = { version = "0.4.49" } drive-proof-verifier = { path = "../rs-drive-proof-verifier", default-features = false } # TODO: I think it's not needed (LKl) tracing = { version = "0.1.41" } @@ -75,7 +75,7 @@ tracing-subscriber = { version = "0.3.22", default-features = false, features = tracing-wasm = { version = "0.2.1" } platform-value = { path = "../rs-platform-value", features = ["json"] } serde = { version = "1.0", features = ["derive"] } -serde-wasm-bindgen = { git = "https://github.com/dashpay/serde-wasm-bindgen", branch = "fix/uint8array-to-bytes" } +serde-wasm-bindgen = { git = "https://github.com/dashpay/serde-wasm-bindgen", rev = "0d3e1a8ff058b400bab3a8ececd2fb9581e8c287" } serde_json = "1.0" hex = "0.4" base64 = "0.22" diff --git a/scripts/setup-ai-agent-environment.sh b/scripts/setup-ai-agent-environment.sh index 069cf901882..aa60764fe6c 100755 --- a/scripts/setup-ai-agent-environment.sh +++ b/scripts/setup-ai-agent-environment.sh @@ -199,7 +199,7 @@ install_protoc() { install_protoc install_cargo_tools() { - local wasm_bindgen_version="0.2.103" + local wasm_bindgen_version="0.2.108" if ! command -v wasm-bindgen >/dev/null 2>&1 || [[ "$(wasm-bindgen --version | awk '{print $2}')" != "${wasm_bindgen_version}" ]]; then log "Installing wasm-bindgen-cli ${wasm_bindgen_version}" From 220fb790a3585f729634e04722f733c9d6414543 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Thu, 19 Feb 2026 10:03:31 +0700 Subject: [PATCH 25/40] more work --- .../query/shielded/encrypted_notes/v0/mod.rs | 24 +- packages/rs-drive-proof-verifier/src/proof.rs | 6 +- .../verify_shielded_encrypted_notes/v0/mod.rs | 8 + .../drive_abci_query_versions/mod.rs | 3 + .../drive_abci_query_versions/v1.rs | 1 + .../src/version/mocks/v2_test.rs | 1 + packages/rs-sdk/src/shielded.rs | 266 +++++++++++++++++- 7 files changed, 296 insertions(+), 13 deletions(-) diff --git a/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs index cf73f4228a9..2f8da854bf6 100644 --- a/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/shielded/encrypted_notes/v0/mod.rs @@ -1,3 +1,4 @@ +use crate::error::query::QueryError; use crate::error::Error; use crate::platform_types::platform::Platform; use crate::platform_types::platform_state::PlatformState; @@ -31,9 +32,26 @@ impl Platform { platform_state: &PlatformState, platform_version: &PlatformVersion, ) -> Result, Error> { - let max_elements = platform_version.drive_abci.query.max_returned_elements as u32; - let effective = if count == 0 || count > max_elements { - max_elements + let max_notes = platform_version + .drive_abci + .query + .shielded_queries + .max_encrypted_notes_per_query as u32; + + // start_index must be chunk-aligned (multiple of max_notes) so each + // query touches exactly one MMR chunk or the buffer. + let chunk_size = max_notes as u64; + if start_index % chunk_size != 0 { + return Ok(QueryValidationResult::new_with_error( + QueryError::InvalidArgument(format!( + "start_index {} is not chunk-aligned; must be a multiple of {}", + start_index, chunk_size + )), + )); + } + + let effective = if count == 0 || count > max_notes { + max_notes } else { count }; diff --git a/packages/rs-drive-proof-verifier/src/proof.rs b/packages/rs-drive-proof-verifier/src/proof.rs index fbdaf6aca65..98d1f2052a0 100644 --- a/packages/rs-drive-proof-verifier/src/proof.rs +++ b/packages/rs-drive-proof-verifier/src/proof.rs @@ -2372,7 +2372,11 @@ impl FromProof for ShieldedEncrypted get_shielded_encrypted_notes_request::Version::V0(v0) => (v0.start_index, v0.count), }; - let max_elements = platform_version.drive_abci.query.max_returned_elements as u32; + let max_elements = platform_version + .drive_abci + .query + .shielded_queries + .max_encrypted_notes_per_query as u32; let (root_hash, notes) = Drive::verify_shielded_encrypted_notes( &proof.grovedb_proof, diff --git a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs index 0f799cc13e0..39cb6eded49 100644 --- a/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs +++ b/packages/rs-drive/src/verify/shielded/verify_shielded_encrypted_notes/v0/mod.rs @@ -15,6 +15,14 @@ impl Drive { verify_subset_of_proof: bool, platform_version: &PlatformVersion, ) -> Result<(RootHash, Vec<(Vec, Vec, Vec)>), Error> { + // start_index must be chunk-aligned (multiple of max_elements) + let chunk_size = max_elements as u64; + if chunk_size > 0 && start_index % chunk_size != 0 { + return Err(Error::Drive(DriveError::CorruptedElementType( + "start_index is not chunk-aligned; must be a multiple of max_elements", + ))); + } + let effective = if count == 0 || count > max_elements { max_elements } else { diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs index a9e147a8528..2cdeb9299c5 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs @@ -99,6 +99,9 @@ pub struct DriveAbciQueryShieldedVersions { pub anchors: FeatureVersionBounds, pub pool_state: FeatureVersionBounds, pub nullifiers: FeatureVersionBounds, + /// Maximum number of encrypted notes returned per query. + /// Should match the BulkAppendTree buffer capacity (2^chunk_power). + pub max_encrypted_notes_per_query: u16, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs index 61227ee6a9f..a31fb8c12e7 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs @@ -268,6 +268,7 @@ pub const DRIVE_ABCI_QUERY_VERSIONS_V1: DriveAbciQueryVersions = DriveAbciQueryV max_version: 0, default_current_version: 0, }, + max_encrypted_notes_per_query: 2048, }, address_funds_queries: DriveAbciQueryAddressFundsVersions { addresses_infos: FeatureVersionBounds { 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 748d2f20499..6141068900e 100644 --- a/packages/rs-platform-version/src/version/mocks/v2_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v2_test.rs @@ -412,6 +412,7 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { max_version: 0, default_current_version: 0, }, + max_encrypted_notes_per_query: 2048, }, address_funds_queries: DriveAbciQueryAddressFundsVersions { addresses_infos: FeatureVersionBounds { diff --git a/packages/rs-sdk/src/shielded.rs b/packages/rs-sdk/src/shielded.rs index 4683cfa5253..1a14f091c6c 100644 --- a/packages/rs-sdk/src/shielded.rs +++ b/packages/rs-sdk/src/shielded.rs @@ -1,19 +1,26 @@ -//! Shielded note trial decryption utilities. +//! Shielded note sync and trial decryption utilities. //! -//! This module provides helpers for performing compact trial decryption on -//! [`ShieldedEncryptedNote`] structs returned by the platform query layer. -//! -//! The [`try_decrypt_note`] function is the primary entry point. It takes a -//! prepared incoming viewing key and a proof-verified encrypted note, and -//! returns the decrypted [`Note`] and recipient [`PaymentAddress`] if the -//! note belongs to the viewer. +//! This module provides: +//! - [`try_decrypt_note`]: compact trial decryption on a single encrypted note +//! - [`sync_shielded_notes`]: end-to-end sync that fetches encrypted notes from +//! the network in parallel and performs trial decryption -use drive_proof_verifier::types::ShieldedEncryptedNote; +use crate::error::Error; +use crate::platform::Fetch; +use crate::Sdk; +use drive_proof_verifier::types::{ShieldedEncryptedNote, ShieldedEncryptedNotes}; +use drive_proof_verifier::types::ShieldedEncryptedNotesQuery; +use futures::stream::{FuturesUnordered, StreamExt}; +use std::pin::Pin; +use std::future::Future; use grovedb_commitment_tree::{ try_compact_note_decryption, CompactAction, DashMemo, EphemeralKeyBytes, ExtractedNoteCommitment, Note, Nullifier, OrchardDomain, PaymentAddress, PreparedIncomingViewingKey, COMPACT_NOTE_SIZE, }; +use rs_dapi_client::RequestSettings; +use std::collections::BTreeMap; +use tracing::debug; /// Minimum length of the `encrypted_note` field for compact trial decryption. /// @@ -24,6 +31,13 @@ use grovedb_commitment_tree::{ /// of the enc_ciphertext. const MIN_ENCRYPTED_NOTE_LEN: usize = 32 + COMPACT_NOTE_SIZE; +/// Default maximum number of chunk queries in flight at once. +const DEFAULT_MAX_CONCURRENT: usize = 4; + +// --------------------------------------------------------------------------- +// Trial decryption +// --------------------------------------------------------------------------- + /// Attempt compact trial decryption on a [`ShieldedEncryptedNote`]. /// /// The [`ShieldedEncryptedNote`] struct (from proof verification) has three @@ -65,3 +79,237 @@ pub fn try_decrypt_note( try_compact_note_decryption(&domain, ivk, &compact) } + +// --------------------------------------------------------------------------- +// Shielded note sync +// --------------------------------------------------------------------------- + +/// Configuration for [`sync_shielded_notes`]. +pub struct ShieldedSyncConfig { + /// Maximum number of chunk queries in flight at once (default: 4). + pub max_concurrent: usize, + /// Request settings forwarded to each individual fetch call. + pub request_settings: RequestSettings, +} + +impl Default for ShieldedSyncConfig { + fn default() -> Self { + Self { + max_concurrent: DEFAULT_MAX_CONCURRENT, + request_settings: RequestSettings::default(), + } + } +} + +/// A note that was successfully decrypted (belongs to the viewer). +pub struct DecryptedNote { + /// Global position of this note in the commitment tree. + pub position: u64, + /// The decrypted Orchard note (contains value, rseed, rho). + pub note: Note, + /// The recipient payment address. + pub address: PaymentAddress, + /// The nullifier (32 bytes). + pub nullifier: [u8; 32], + /// The note commitment (32 bytes). + pub cmx: [u8; 32], +} + +/// Result of [`sync_shielded_notes`]. +pub struct ShieldedSyncResult { + /// Notes that successfully decrypted (belong to the viewer). + pub decrypted_notes: Vec, + /// All raw encrypted notes fetched, in tree order. + /// Useful for updating a local commitment tree. + pub all_notes: Vec, + /// Next chunk-aligned index to resume syncing from. + pub next_start_index: u64, + /// Total number of notes scanned in this sync. + pub total_notes_scanned: u64, +} + +/// Fetch all shielded encrypted notes starting from `start_index`, query +/// multiple nodes in parallel, and perform trial decryption. +/// +/// This is the main entry point for wallet sync. It handles: +/// 1. Chunk-aligned pagination (each query covers one BulkAppendTree chunk) +/// 2. Parallel dispatch of chunk queries across network nodes +/// 3. Proof verification on every response +/// 4. Trial decryption with the provided incoming viewing key +/// +/// # Arguments +/// +/// - `sdk` — SDK instance connected to the network +/// - `ivk` — prepared incoming viewing key for trial decryption +/// - `start_index` — first note position to fetch (must be a multiple of +/// the chunk size, typically 2048) +/// - `config` — optional tuning; `None` uses sensible defaults +/// +/// # Returns +/// +/// [`ShieldedSyncResult`] containing decrypted notes that belong to the +/// viewer, all raw notes for commitment tree updates, and the next index +/// to resume from. +pub async fn sync_shielded_notes( + sdk: &Sdk, + ivk: &PreparedIncomingViewingKey, + start_index: u64, + config: Option, +) -> Result { + let config = config.unwrap_or_default(); + + let chunk_size = sdk + .version() + .drive_abci + .query + .shielded_queries + .max_encrypted_notes_per_query as u64; + + // Validate alignment + if chunk_size > 0 && start_index % chunk_size != 0 { + return Err(Error::Generic(format!( + "start_index {} is not chunk-aligned; must be a multiple of {}", + start_index, chunk_size + ))); + } + + let max_concurrent = config.max_concurrent.max(1); + let settings = config.request_settings; + + type ChunkFuture = Pin< + Box), Error>> + Send>, + >; + + // Sliding-window parallel fetch using FuturesUnordered. + // Each future fetches one chunk and returns (chunk_start_index, notes). + let mut futures: FuturesUnordered = FuturesUnordered::new(); + let mut next_chunk_index = start_index; + let mut reached_end = false; + + // Seed initial batch of chunk queries + for _ in 0..max_concurrent { + let chunk_idx = next_chunk_index; + next_chunk_index += chunk_size; + let sdk = sdk.clone(); + futures.push(Box::pin( + async move { fetch_chunk(&sdk, chunk_idx, chunk_size, settings).await }, + )); + } + + // Collect results keyed by chunk start_index for ordered reassembly + let mut chunk_results: BTreeMap> = BTreeMap::new(); + + while let Some(result) = futures.next().await { + let (chunk_idx, notes) = result?; + let is_partial = (notes.len() as u64) < chunk_size; + chunk_results.insert(chunk_idx, notes); + + if is_partial { + reached_end = true; + } + + // Queue the next chunk if we haven't reached the end + if !reached_end { + let chunk_idx = next_chunk_index; + next_chunk_index += chunk_size; + let sdk = sdk.clone(); + futures.push(Box::pin( + async move { fetch_chunk(&sdk, chunk_idx, chunk_size, settings).await }, + )); + } + } + + // Flatten in tree order and perform trial decryption + let mut all_notes = Vec::new(); + let mut decrypted_notes = Vec::new(); + + for (&chunk_start, notes) in &chunk_results { + for (i, note) in notes.iter().enumerate() { + let position = chunk_start + i as u64; + + if let Some((decrypted, address)) = try_decrypt_note(ivk, note) { + let nf: [u8; 32] = note + .nullifier + .as_slice() + .try_into() + .unwrap_or([0u8; 32]); + let cmx: [u8; 32] = note + .cmx + .as_slice() + .try_into() + .unwrap_or([0u8; 32]); + + decrypted_notes.push(DecryptedNote { + position, + note: decrypted, + address, + nullifier: nf, + cmx, + }); + } + } + } + + let total_notes_scanned: u64 = chunk_results.values().map(|v| v.len() as u64).sum(); + + // Move notes out of the BTreeMap in order + for (_, notes) in chunk_results { + all_notes.extend(notes); + } + + // Next start index: round up to next chunk boundary + let raw_next = start_index + total_notes_scanned; + let next_start_index = if chunk_size > 0 { + ((raw_next + chunk_size - 1) / chunk_size) * chunk_size + } else { + raw_next + }; + + debug!( + total_notes_scanned, + decrypted_count = decrypted_notes.len(), + next_start_index, + "shielded note sync complete" + ); + + Ok(ShieldedSyncResult { + decrypted_notes, + all_notes, + next_start_index, + total_notes_scanned, + }) +} + +/// Fetch a single chunk of encrypted notes from the network. +/// +/// Returns `(chunk_start_index, notes)`. An empty vec means no notes exist +/// at this position (past end of tree). +async fn fetch_chunk( + sdk: &Sdk, + chunk_start: u64, + chunk_size: u64, + settings: RequestSettings, +) -> Result<(u64, Vec), Error> { + let query = ShieldedEncryptedNotesQuery { + start_index: chunk_start, + count: chunk_size as u32, + }; + + debug!(chunk_start, chunk_size, "fetching shielded notes chunk"); + + let result = + ShieldedEncryptedNotes::fetch_with_settings(sdk, query, settings).await?; + + let notes = match result { + Some(ShieldedEncryptedNotes(notes)) => notes, + None => Vec::new(), + }; + + debug!( + chunk_start, + notes_returned = notes.len(), + "shielded notes chunk fetched" + ); + + Ok((chunk_start, notes)) +} From 737d6c25556c5203d2654d871355390e5316f9e3 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 24 Feb 2026 01:18:47 +0700 Subject: [PATCH 26/40] work on nullifiers --- Cargo.lock | 72 +++-- packages/dapi-grpc/build.rs | 28 +- .../protos/platform/v0/platform.proto | 103 +++++++ packages/rs-dpp/Cargo.toml | 2 +- packages/rs-drive-abci/Cargo.toml | 4 +- .../engine/run_block_proposal/v0/mod.rs | 11 + .../v0/mod.rs | 4 +- .../mod.rs | 41 +++ .../v0/mod.rs | 27 ++ .../execute_event/v0/mod.rs | 1 + .../state_transition_processing/mod.rs | 2 + .../process_raw_state_transitions/v0/mod.rs | 5 + .../mod.rs | 43 +++ .../v0/mod.rs | 30 ++ .../execution/types/execution_event/mod.rs | 22 +- .../mod.rs | 14 + packages/rs-drive-abci/src/query/service.rs | 74 ++++- .../rs-drive-abci/src/query/shielded/mod.rs | 4 + .../shielded/nullifiers_branch_state/mod.rs | 62 ++++ .../nullifiers_branch_state/v0/mod.rs | 41 +++ .../shielded/nullifiers_trunk_state/mod.rs | 62 ++++ .../shielded/nullifiers_trunk_state/v0/mod.rs | 44 +++ .../recent_compacted_nullifier_changes/mod.rs | 67 +++++ .../v0/mod.rs | 78 +++++ .../shielded/recent_nullifier_changes/mod.rs | 65 ++++ .../recent_nullifier_changes/v0/mod.rs | 71 +++++ packages/rs-drive-proof-verifier/src/proof.rs | 193 +++++++++++- packages/rs-drive-proof-verifier/src/types.rs | 90 ++++++ packages/rs-drive/Cargo.toml | 12 +- .../src/drive/initialization/v3/mod.rs | 33 ++- .../cleanup_expired_nullifiers/mod.rs | 49 ++++ .../cleanup_expired_nullifiers/v0/mod.rs | 95 ++++++ .../compact_nullifiers/mod.rs | 61 ++++ .../compact_nullifiers/v0/mod.rs | 194 ++++++++++++ .../fetch_compacted_nullifiers/mod.rs | 85 ++++++ .../fetch_compacted_nullifiers/v0/mod.rs | 277 ++++++++++++++++++ .../fetch_nullifiers/mod.rs | 85 ++++++ .../fetch_nullifiers/v0/mod.rs | 101 +++++++ .../src/drive/saved_block_transactions/mod.rs | 9 + .../drive/saved_block_transactions/queries.rs | 66 +++++ .../store_nullifiers/mod.rs | 55 ++++ .../store_nullifiers/v0/mod.rs | 154 ++++++++++ packages/rs-drive/src/drive/shielded/mod.rs | 4 + packages/rs-drive/src/drive/shielded/paths.rs | 25 ++ .../rs-drive/src/drive/shielded/prove/mod.rs | 5 + .../prove_nullifiers_branch_query/mod.rs | 93 ++++++ .../prove_nullifiers_branch_query/v0/mod.rs | 70 +++++ .../prove/prove_nullifiers_trunk_query/mod.rs | 74 +++++ .../prove_nullifiers_trunk_query/v0/mod.rs | 56 ++++ packages/rs-drive/src/verify/shielded/mod.rs | 8 + .../verify_compacted_nullifier_changes/mod.rs | 56 ++++ .../v0/mod.rs | 207 +++++++++++++ .../verify_nullifiers_branch_query/mod.rs | 58 ++++ .../verify_nullifiers_branch_query/v0/mod.rs | 48 +++ .../verify_nullifiers_trunk_query/mod.rs | 50 ++++ .../verify_nullifiers_trunk_query/v0/mod.rs | 36 +++ .../verify_recent_nullifier_changes/mod.rs | 57 ++++ .../verify_recent_nullifier_changes/v0/mod.rs | 83 ++++++ packages/rs-platform-version/Cargo.toml | 2 +- .../drive_abci_method_versions/mod.rs | 2 + .../drive_abci_method_versions/v1.rs | 2 + .../drive_abci_method_versions/v2.rs | 2 + .../drive_abci_method_versions/v3.rs | 2 + .../drive_abci_method_versions/v4.rs | 2 + .../drive_abci_method_versions/v5.rs | 2 + .../drive_abci_method_versions/v6.rs | 2 + .../drive_abci_method_versions/v7.rs | 2 + .../drive_abci_query_versions/mod.rs | 4 + .../drive_abci_query_versions/v1.rs | 20 ++ .../drive_group_method_versions/mod.rs | 8 + .../drive_verify_method_versions/mod.rs | 4 + .../drive_verify_method_versions/v1.rs | 4 + .../src/version/drive_versions/mod.rs | 13 +- .../src/version/drive_versions/v1.rs | 13 + .../src/version/drive_versions/v2.rs | 13 + .../src/version/drive_versions/v3.rs | 13 + .../src/version/drive_versions/v4.rs | 13 + .../src/version/drive_versions/v5.rs | 13 + .../src/version/drive_versions/v6.rs | 13 + .../src/version/drive_versions/v7.rs | 13 + .../src/version/mocks/v2_test.rs | 22 +- .../src/version/mocks/v3_test.rs | 2 + packages/rs-sdk/Cargo.toml | 2 +- packages/rs-sdk/src/shielded.rs | 38 +-- 84 files changed, 3598 insertions(+), 94 deletions(-) create mode 100644 packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/cleanup_recent_block_storage_nullifiers/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/cleanup_recent_block_storage_nullifiers/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/store_nullifiers_to_recent_block_storage/mod.rs create mode 100644 packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/store_nullifiers_to_recent_block_storage/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/query/shielded/nullifiers_branch_state/mod.rs create mode 100644 packages/rs-drive-abci/src/query/shielded/nullifiers_branch_state/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/query/shielded/nullifiers_trunk_state/mod.rs create mode 100644 packages/rs-drive-abci/src/query/shielded/nullifiers_trunk_state/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/query/shielded/recent_compacted_nullifier_changes/mod.rs create mode 100644 packages/rs-drive-abci/src/query/shielded/recent_compacted_nullifier_changes/v0/mod.rs create mode 100644 packages/rs-drive-abci/src/query/shielded/recent_nullifier_changes/mod.rs create mode 100644 packages/rs-drive-abci/src/query/shielded/recent_nullifier_changes/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/saved_block_transactions/cleanup_expired_nullifiers/mod.rs create mode 100644 packages/rs-drive/src/drive/saved_block_transactions/cleanup_expired_nullifiers/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/saved_block_transactions/compact_nullifiers/mod.rs create mode 100644 packages/rs-drive/src/drive/saved_block_transactions/compact_nullifiers/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_nullifiers/mod.rs create mode 100644 packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_nullifiers/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/saved_block_transactions/fetch_nullifiers/mod.rs create mode 100644 packages/rs-drive/src/drive/saved_block_transactions/fetch_nullifiers/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/saved_block_transactions/store_nullifiers/mod.rs create mode 100644 packages/rs-drive/src/drive/saved_block_transactions/store_nullifiers/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/shielded/prove/mod.rs create mode 100644 packages/rs-drive/src/drive/shielded/prove/prove_nullifiers_branch_query/mod.rs create mode 100644 packages/rs-drive/src/drive/shielded/prove/prove_nullifiers_branch_query/v0/mod.rs create mode 100644 packages/rs-drive/src/drive/shielded/prove/prove_nullifiers_trunk_query/mod.rs create mode 100644 packages/rs-drive/src/drive/shielded/prove/prove_nullifiers_trunk_query/v0/mod.rs create mode 100644 packages/rs-drive/src/verify/shielded/verify_compacted_nullifier_changes/mod.rs create mode 100644 packages/rs-drive/src/verify/shielded/verify_compacted_nullifier_changes/v0/mod.rs create mode 100644 packages/rs-drive/src/verify/shielded/verify_nullifiers_branch_query/mod.rs create mode 100644 packages/rs-drive/src/verify/shielded/verify_nullifiers_branch_query/v0/mod.rs create mode 100644 packages/rs-drive/src/verify/shielded/verify_nullifiers_trunk_query/mod.rs create mode 100644 packages/rs-drive/src/verify/shielded/verify_nullifiers_trunk_query/v0/mod.rs create mode 100644 packages/rs-drive/src/verify/shielded/verify_recent_nullifier_changes/mod.rs create mode 100644 packages/rs-drive/src/verify/shielded/verify_recent_nullifier_changes/v0/mod.rs diff --git a/Cargo.lock b/Cargo.lock index e0bb175667b..35959feb8bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -992,15 +992,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ckb-merkle-mountain-range" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327c468ff2702c0a2b7ad26728a180611da22244882959b8b2e85c79bf56bcea" -dependencies = [ - "cfg-if", -] - [[package]] name = "clang-sys" version = "1.8.1" @@ -2608,21 +2599,21 @@ dependencies = [ [[package]] name = "grovedb" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" +source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" dependencies = [ "axum 0.8.8", "bincode", "bincode_derive", "blake3", - "ckb-merkle-mountain-range", "grovedb-bulk-append-tree", "grovedb-commitment-tree", "grovedb-costs", "grovedb-dense-fixed-sized-merkle-tree", "grovedb-element", "grovedb-merk", - "grovedb-mmr", + "grovedb-merkle-mountain-range", "grovedb-path", + "grovedb-query", "grovedb-storage", "grovedb-version", "grovedb-visualize", @@ -2646,12 +2637,15 @@ dependencies = [ [[package]] name = "grovedb-bulk-append-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" +source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" dependencies = [ "bincode", "blake3", + "grovedb-costs", "grovedb-dense-fixed-sized-merkle-tree", - "grovedb-mmr", + "grovedb-merkle-mountain-range", + "grovedb-query", + "grovedb-storage", "hex", "thiserror 2.0.17", ] @@ -2659,7 +2653,7 @@ dependencies = [ [[package]] name = "grovedb-commitment-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" +source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" dependencies = [ "incrementalmerkletree", "orchard", @@ -2671,7 +2665,7 @@ dependencies = [ [[package]] name = "grovedb-costs" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" +source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" dependencies = [ "integer-encoding", "intmap", @@ -2681,17 +2675,20 @@ dependencies = [ [[package]] name = "grovedb-dense-fixed-sized-merkle-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" +source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" dependencies = [ "bincode", "blake3", + "grovedb-costs", + "grovedb-query", + "grovedb-storage", "thiserror 2.0.17", ] [[package]] name = "grovedb-element" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" +source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" dependencies = [ "bincode", "bincode_derive", @@ -2706,7 +2703,7 @@ dependencies = [ [[package]] name = "grovedb-epoch-based-storage-flags" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" +source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" dependencies = [ "grovedb-costs", "hex", @@ -2718,7 +2715,7 @@ dependencies = [ [[package]] name = "grovedb-merk" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" +source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" dependencies = [ "bincode", "bincode_derive", @@ -2729,6 +2726,7 @@ dependencies = [ "grovedb-costs", "grovedb-element", "grovedb-path", + "grovedb-query", "grovedb-storage", "grovedb-version", "grovedb-visualize", @@ -2741,28 +2739,44 @@ dependencies = [ ] [[package]] -name = "grovedb-mmr" +name = "grovedb-merkle-mountain-range" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" +source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" dependencies = [ "bincode", "blake3", - "ckb-merkle-mountain-range", - "thiserror 2.0.17", + "grovedb-costs", + "grovedb-storage", ] [[package]] name = "grovedb-path" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" +source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" dependencies = [ "hex", ] +[[package]] +name = "grovedb-query" +version = "4.0.0" +source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" +dependencies = [ + "bincode", + "byteorder", + "ed", + "grovedb-costs", + "grovedb-storage", + "hex", + "indexmap 2.12.1", + "integer-encoding", + "thiserror 2.0.17", +] + [[package]] name = "grovedb-storage" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" +source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" dependencies = [ "blake3", "grovedb-costs", @@ -2781,7 +2795,7 @@ dependencies = [ [[package]] name = "grovedb-version" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" +source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" dependencies = [ "thiserror 2.0.17", "versioned-feature-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2790,7 +2804,7 @@ dependencies = [ [[package]] name = "grovedb-visualize" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" +source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" dependencies = [ "hex", "itertools 0.14.0", @@ -2799,7 +2813,7 @@ dependencies = [ [[package]] name = "grovedbg-types" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=dc8c25023c5116374087b2c73008ae9167c567d8#dc8c25023c5116374087b2c73008ae9167c567d8" +source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" dependencies = [ "serde", "serde_with 3.16.1", diff --git a/packages/dapi-grpc/build.rs b/packages/dapi-grpc/build.rs index 77431d20c8c..ad9462df64e 100644 --- a/packages/dapi-grpc/build.rs +++ b/packages/dapi-grpc/build.rs @@ -84,7 +84,7 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig { // Derive features for versioned messages // // "GetConsensusParamsRequest" is excluded as this message does not support proofs - const VERSIONED_REQUESTS: [&str; 52] = [ + const VERSIONED_REQUESTS: [&str; 54] = [ "GetDataContractHistoryRequest", "GetDataContractRequest", "GetDataContractsRequest", @@ -137,11 +137,19 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig { "GetShieldedAnchorsRequest", "GetShieldedPoolStateRequest", "GetShieldedNullifiersRequest", + "GetRecentNullifierChangesRequest", + "GetRecentCompactedNullifierChangesRequest", ]; - const PROOF_ONLY_VERSIONED_REQUESTS: [&str; 1] = ["GetAddressesTrunkStateRequest"]; + const PROOF_ONLY_VERSIONED_REQUESTS: [&str; 2] = [ + "GetAddressesTrunkStateRequest", + "GetNullifiersTrunkStateRequest", + ]; - const MERK_PROOF_VERSIONED_REQUESTS: [&str; 1] = ["GetAddressesBranchStateRequest"]; + const MERK_PROOF_VERSIONED_REQUESTS: [&str; 2] = [ + "GetAddressesBranchStateRequest", + "GetNullifiersBranchStateRequest", + ]; // The following responses are excluded as they don't support proofs: // - "GetConsensusParamsResponse" @@ -151,7 +159,7 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig { // - "GetIdentityByNonUniquePublicKeyHashResponse" // // "GetEvonodesProposedEpochBlocksResponse" is used for 2 Requests - const VERSIONED_RESPONSES: [&str; 50] = [ + const VERSIONED_RESPONSES: [&str; 52] = [ "GetDataContractHistoryResponse", "GetDataContractResponse", "GetDataContractsResponse", @@ -202,11 +210,19 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig { "GetShieldedAnchorsResponse", "GetShieldedPoolStateResponse", "GetShieldedNullifiersResponse", + "GetRecentNullifierChangesResponse", + "GetRecentCompactedNullifierChangesResponse", ]; - const PROOF_ONLY_VERSIONED_RESPONSES: [&str; 1] = ["GetAddressesTrunkStateResponse"]; + const PROOF_ONLY_VERSIONED_RESPONSES: [&str; 2] = [ + "GetAddressesTrunkStateResponse", + "GetNullifiersTrunkStateResponse", + ]; - const MERK_PROOF_VERSIONED_RESPONSES: [&str; 1] = ["GetAddressesBranchStateResponse"]; + const MERK_PROOF_VERSIONED_RESPONSES: [&str; 2] = [ + "GetAddressesBranchStateResponse", + "GetNullifiersBranchStateResponse", + ]; check_unique(&VERSIONED_REQUESTS).expect("VERSIONED_REQUESTS"); check_unique(&VERSIONED_RESPONSES).expect("VERSIONED_RESPONSES"); diff --git a/packages/dapi-grpc/protos/platform/v0/platform.proto b/packages/dapi-grpc/protos/platform/v0/platform.proto index 46718eb03b3..84a1e91053b 100644 --- a/packages/dapi-grpc/protos/platform/v0/platform.proto +++ b/packages/dapi-grpc/protos/platform/v0/platform.proto @@ -124,6 +124,14 @@ service Platform { returns (GetShieldedPoolStateResponse); rpc getShieldedNullifiers(GetShieldedNullifiersRequest) returns (GetShieldedNullifiersResponse); + rpc getNullifiersTrunkState(GetNullifiersTrunkStateRequest) + returns (GetNullifiersTrunkStateResponse); + rpc getNullifiersBranchState(GetNullifiersBranchStateRequest) + returns (GetNullifiersBranchStateResponse); + rpc getRecentNullifierChanges(GetRecentNullifierChangesRequest) + returns (GetRecentNullifierChangesResponse); + rpc getRecentCompactedNullifierChanges(GetRecentCompactedNullifierChangesRequest) + returns (GetRecentCompactedNullifierChangesResponse); } // Proof message includes cryptographic proofs for validating responses @@ -2228,3 +2236,98 @@ message GetShieldedNullifiersResponse { } oneof version { GetShieldedNullifiersResponseV0 v0 = 1; } } + +message GetNullifiersTrunkStateRequest { + message GetNullifiersTrunkStateRequestV0 { + uint32 pool_type = 1; // ShieldedPoolType enum value (0=credit, 1=main token, 2=individual token) + bytes pool_identifier = 2; // 32-byte Identifier, required for pool_type=2 + } + oneof version { GetNullifiersTrunkStateRequestV0 v0 = 1; } +} + +message GetNullifiersTrunkStateResponse { + message GetNullifiersTrunkStateResponseV0 { + Proof proof = 2; + ResponseMetadata metadata = 3; + } + oneof version { GetNullifiersTrunkStateResponseV0 v0 = 1; } +} + +message GetNullifiersBranchStateRequest { + message GetNullifiersBranchStateRequestV0 { + uint32 pool_type = 1; + bytes pool_identifier = 2; + bytes key = 3; + uint32 depth = 4; + uint64 checkpoint_height = 5; + } + oneof version { GetNullifiersBranchStateRequestV0 v0 = 1; } +} + +message GetNullifiersBranchStateResponse { + message GetNullifiersBranchStateResponseV0 { + bytes merk_proof = 2; + } + oneof version { GetNullifiersBranchStateResponseV0 v0 = 1; } +} + +// --- Recent Nullifier Changes --- + +message BlockNullifierChanges { + uint64 block_height = 1 [ jstype = JS_STRING ]; + repeated bytes nullifiers = 2; // Each is 32 bytes +} + +message NullifierUpdateEntries { + repeated BlockNullifierChanges block_changes = 1; +} + +message GetRecentNullifierChangesRequest { + message GetRecentNullifierChangesRequestV0 { + uint64 start_height = 1 [ jstype = JS_STRING ]; + bool prove = 2; + } + oneof version { GetRecentNullifierChangesRequestV0 v0 = 1; } +} + +message GetRecentNullifierChangesResponse { + message GetRecentNullifierChangesResponseV0 { + oneof result { + NullifierUpdateEntries nullifier_update_entries = 1; + Proof proof = 2; + } + ResponseMetadata metadata = 3; + } + oneof version { GetRecentNullifierChangesResponseV0 v0 = 1; } +} + +// --- Compacted Nullifier Changes --- + +message CompactedBlockNullifierChanges { + uint64 start_block_height = 1 [ jstype = JS_STRING ]; + uint64 end_block_height = 2 [ jstype = JS_STRING ]; + repeated bytes nullifiers = 3; // Each is 32 bytes +} + +message CompactedNullifierUpdateEntries { + repeated CompactedBlockNullifierChanges compacted_block_changes = 1; +} + +message GetRecentCompactedNullifierChangesRequest { + message GetRecentCompactedNullifierChangesRequestV0 { + uint64 start_block_height = 1 [ jstype = JS_STRING ]; + bool prove = 2; + } + oneof version { GetRecentCompactedNullifierChangesRequestV0 v0 = 1; } +} + +message GetRecentCompactedNullifierChangesResponse { + message GetRecentCompactedNullifierChangesResponseV0 { + oneof result { + CompactedNullifierUpdateEntries compacted_nullifier_update_entries = 1; + Proof proof = 2; + } + ResponseMetadata metadata = 3; + } + oneof version { GetRecentCompactedNullifierChangesResponseV0 v0 = 1; } +} diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index 7b776e19698..3307f8b3653 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -71,7 +71,7 @@ strum = { version = "0.26", features = ["derive"] } json-schema-compatibility-validator = { path = '../rs-json-schema-compatibility-validator', optional = true } once_cell = "1.19.0" tracing = { version = "0.1.41" } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8", optional = true } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444", optional = true } [dev-dependencies] tokio = { version = "1.40", features = ["full"] } diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index aef0dc90623..3bc43af9483 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -82,7 +82,7 @@ derive_more = { version = "1.0", features = ["from", "deref", "deref_mut"] } async-trait = "0.1.77" console-subscriber = { version = "0.4", optional = true } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f", optional = true } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8" } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444" } sha2 = "0.10" nonempty = "0.11" @@ -105,7 +105,7 @@ dpp = { path = "../rs-dpp", default-features = false, features = [ drive = { path = "../rs-drive", features = ["fixtures-and-mocks"] } drive-proof-verifier = { path = "../rs-drive-proof-verifier" } strategy-tests = { path = "../strategy-tests" } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8", features = ["client"] } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444", features = ["client"] } assert_matches = "1.5.0" drive-abci = { path = ".", features = ["testing-config", "mocks"] } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f" } 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 41a01c2d8eb..eebc3691498 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 @@ -344,6 +344,17 @@ where platform_version, )?; + // Store nullifiers inserted during this block to recent block storage + self.store_nullifiers_to_recent_block_storage( + &state_transitions_result.nullifiers_inserted, + &block_info, + transaction, + platform_version, + )?; + + // Clean up expired compacted nullifier entries + self.cleanup_recent_block_storage_nullifiers(&block_info, transaction, platform_version)?; + // Record shielded pool anchor if the commitment tree changed this block. // This stores block_height → anchor_bytes so shielded transactions can // reference a recent anchor for spend authorization. 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 7fe26966ae5..efccfabb745 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 @@ -637,11 +637,11 @@ impl Platform { &platform_version.drive, )?; - // Nullifiers tree (NormalTree): [AddressBalances, "s"] / [2] + // Nullifiers tree (ProvableCountTree): [AddressBalances, "s"] / [2] self.drive.grove_insert_if_not_exists( (&shielded_pool_path).into(), &[SHIELDED_NULLIFIERS_KEY], - Element::empty_tree(), + Element::empty_provable_count_tree(), Some(transaction), None, &platform_version.drive, diff --git a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/cleanup_recent_block_storage_nullifiers/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/cleanup_recent_block_storage_nullifiers/mod.rs new file mode 100644 index 00000000000..8acb0bbb838 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/cleanup_recent_block_storage_nullifiers/mod.rs @@ -0,0 +1,41 @@ +mod v0; + +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::version::PlatformVersion; +use drive::grovedb::Transaction; + +impl Platform +where + C: CoreRPCLike, +{ + /// Cleans up expired compacted nullifier entries from recent block storage. + pub(in crate::execution) fn cleanup_recent_block_storage_nullifiers( + &self, + block_info: &BlockInfo, + transaction: &Transaction, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version + .drive_abci + .methods + .state_transition_processing + .cleanup_recent_block_storage_nullifiers + { + None => Ok(()), + Some(0) => self.cleanup_recent_block_storage_nullifiers_v0( + block_info, + transaction, + platform_version, + ), + Some(version) => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "cleanup_recent_block_storage_nullifiers".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/cleanup_recent_block_storage_nullifiers/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/cleanup_recent_block_storage_nullifiers/v0/mod.rs new file mode 100644 index 00000000000..cfdebde75be --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/cleanup_recent_block_storage_nullifiers/v0/mod.rs @@ -0,0 +1,27 @@ +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::rpc::core::CoreRPCLike; +use dpp::block::block_info::BlockInfo; +use dpp::version::PlatformVersion; +use drive::grovedb::Transaction; + +impl Platform +where + C: CoreRPCLike, +{ + /// Version 0 implementation of cleaning up expired compacted nullifier entries. + pub(super) fn cleanup_recent_block_storage_nullifiers_v0( + &self, + block_info: &BlockInfo, + transaction: &Transaction, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + self.drive.cleanup_expired_nullifiers( + block_info.time_ms, + Some(transaction), + platform_version, + )?; + + Ok(()) + } +} diff --git a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs index 1008df6c18b..404ceee029c 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs @@ -488,6 +488,7 @@ where ExecutionEvent::PaidFixedCost { operations, fees_to_add_to_pool, + .. } => { if consensus_errors.is_empty() { self.drive diff --git a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/mod.rs index 84b91ec6afb..52c39e1102f 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/mod.rs @@ -1,6 +1,8 @@ mod cleanup_recent_block_storage_address_balances; +mod cleanup_recent_block_storage_nullifiers; mod decode_raw_state_transitions; mod execute_event; mod process_raw_state_transitions; mod store_address_balances_to_recent_block_storage; +mod store_nullifiers_to_recent_block_storage; mod validate_fees_of_event; diff --git a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs index fa1b3012917..c8c28f74f14 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs @@ -368,6 +368,9 @@ where } })?; + // Extract nullifiers before the execution event is consumed + let nullifiers = execution_event.nullifiers().to_vec(); + let mut address_balances = BTreeMap::new(); let event_execution_result = self .execute_event( @@ -404,6 +407,7 @@ where estimated_fees, fee_result: actual_fees, address_balance_changes: address_balances, + nullifiers_inserted: nullifiers, } } EventExecutionResult::UnsuccessfulPaidExecution( @@ -450,6 +454,7 @@ where estimated_fees: None, fee_result: FeeResult::default(), address_balance_changes: BTreeMap::new(), + nullifiers_inserted: nullifiers, } } EventExecutionResult::UnpaidConsensusExecutionError(mut errors) => { diff --git a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/store_nullifiers_to_recent_block_storage/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/store_nullifiers_to_recent_block_storage/mod.rs new file mode 100644 index 00000000000..cb964419d5a --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/store_nullifiers_to_recent_block_storage/mod.rs @@ -0,0 +1,43 @@ +mod v0; + +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::version::PlatformVersion; +use drive::grovedb::Transaction; + +impl Platform +where + C: CoreRPCLike, +{ + /// Stores nullifiers inserted during this block to recent block storage for sync purposes. + pub(in crate::execution) fn store_nullifiers_to_recent_block_storage( + &self, + nullifiers: &[[u8; 32]], + block_info: &BlockInfo, + transaction: &Transaction, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version + .drive_abci + .methods + .state_transition_processing + .store_nullifiers_to_recent_block_storage + { + None => Ok(()), + Some(0) => self.store_nullifiers_to_recent_block_storage_v0( + nullifiers, + block_info, + transaction, + platform_version, + ), + Some(version) => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "store_nullifiers_to_recent_block_storage".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/store_nullifiers_to_recent_block_storage/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/store_nullifiers_to_recent_block_storage/v0/mod.rs new file mode 100644 index 00000000000..779393ee242 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/store_nullifiers_to_recent_block_storage/v0/mod.rs @@ -0,0 +1,30 @@ +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::rpc::core::CoreRPCLike; +use dpp::block::block_info::BlockInfo; +use dpp::version::PlatformVersion; +use drive::grovedb::Transaction; + +impl Platform +where + C: CoreRPCLike, +{ + /// Version 0 implementation of storing nullifiers to recent block storage. + pub(super) fn store_nullifiers_to_recent_block_storage_v0( + &self, + nullifiers: &[[u8; 32]], + block_info: &BlockInfo, + transaction: &Transaction, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + self.drive.store_nullifiers_for_block( + nullifiers, + block_info.height, + block_info.time_ms, + Some(transaction), + platform_version, + )?; + + Ok(()) + } +} diff --git a/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs b/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs index c342a1ad6f5..a923ed9dad5 100644 --- a/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs +++ b/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs @@ -67,6 +67,8 @@ pub(in crate::execution) enum ExecutionEvent<'a> { operations: Vec>, /// fees to add fees_to_add_to_pool: Credits, + /// Nullifiers inserted by this action (for shielded spends) + nullifiers: Vec<[u8; 32]>, }, /// A drive event that is paid from an asset lock PaidFromAssetLock { @@ -108,6 +110,16 @@ pub(in crate::execution) enum ExecutionEvent<'a> { } impl ExecutionEvent<'_> { + /// Extract nullifiers from this execution event, if any. + /// Shielded spend actions (ShieldedTransfer, Unshield, ShieldedWithdrawal) + /// carry nullifiers that were consumed. + pub(crate) fn nullifiers(&self) -> &[[u8; 32]] { + match self { + ExecutionEvent::PaidFixedCost { nullifiers, .. } => nullifiers.as_slice(), + _ => &[], + } + } + pub(crate) fn create_from_state_transition_action( action: StateTransitionAction, identity: Option, @@ -233,6 +245,7 @@ impl ExecutionEvent<'_> { .fee_version .vote_resolution_fund_fees .contested_document_single_vote_cost, + nullifiers: vec![], }) } StateTransitionAction::DataContractCreateAction(data_contract_create_action) => { @@ -471,22 +484,26 @@ impl ExecutionEvent<'_> { user_fee_increase, }) } - StateTransitionAction::ShieldedTransferAction(shielded_transfer_action) => { + StateTransitionAction::ShieldedTransferAction(ref shielded_transfer_action) => { let fee_amount = shielded_transfer_action.fee_amount(); + let nullifiers = shielded_transfer_action.nullifiers().to_vec(); let operations = action.into_high_level_drive_operations(epoch, platform_version)?; Ok(ExecutionEvent::PaidFixedCost { operations, fees_to_add_to_pool: fee_amount, + nullifiers, }) } StateTransitionAction::UnshieldAction(ref unshield_action) => { let fee_amount = unshield_action.fee_amount(); + let nullifiers = unshield_action.nullifiers().to_vec(); let operations = action.into_high_level_drive_operations(epoch, platform_version)?; Ok(ExecutionEvent::PaidFixedCost { operations, fees_to_add_to_pool: fee_amount, + nullifiers, }) } StateTransitionAction::ShieldFromAssetLockAction(ref shield_from_asset_lock_action) => { @@ -506,11 +523,13 @@ impl ExecutionEvent<'_> { } StateTransitionAction::ShieldedWithdrawalAction(ref shielded_withdrawal_action) => { let fee_amount = shielded_withdrawal_action.fee_amount(); + let nullifiers = shielded_withdrawal_action.nullifiers().to_vec(); let operations = action.into_high_level_drive_operations(epoch, platform_version)?; Ok(ExecutionEvent::PaidFixedCost { operations, fees_to_add_to_pool: fee_amount, + nullifiers, }) } StateTransitionAction::PenalizeShieldedPoolAction(ref penalize_action) => { @@ -520,6 +539,7 @@ impl ExecutionEvent<'_> { Ok(ExecutionEvent::PaidFixedCost { operations, fees_to_add_to_pool: penalty_amount, + nullifiers: vec![], }) } _ => { diff --git a/packages/rs-drive-abci/src/platform_types/state_transitions_processing_result/mod.rs b/packages/rs-drive-abci/src/platform_types/state_transitions_processing_result/mod.rs index c785fad0d93..122947ad77b 100644 --- a/packages/rs-drive-abci/src/platform_types/state_transitions_processing_result/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/state_transitions_processing_result/mod.rs @@ -42,6 +42,8 @@ pub enum StateTransitionExecutionResult { fee_result: FeeResult, /// Address balance changes from this state transition address_balance_changes: BTreeMap, + /// Nullifiers inserted by shielded spend actions + nullifiers_inserted: Vec<[u8; 32]>, }, /// State Transition was not executed at all. /// The only current reason for this is that the proposer reached the maximum time limit @@ -55,6 +57,7 @@ pub enum StateTransitionExecutionResult { pub struct StateTransitionsProcessingResult { execution_results: Vec, pub(crate) address_balances_updated: BTreeMap, + pub(crate) nullifiers_inserted: Vec<[u8; 32]>, invalid_paid_count: usize, invalid_unpaid_count: usize, valid_count: usize, @@ -117,6 +120,7 @@ impl StateTransitionsProcessingResult { StateTransitionExecutionResult::SuccessfulExecution { fee_result: actual_fees, address_balance_changes, + nullifiers_inserted, .. } => { self.valid_count += 1; @@ -125,6 +129,11 @@ impl StateTransitionsProcessingResult { // Merge address balance changes self.add_address_balances_in_update(address_balance_changes.clone()); + + // Collect nullifiers from shielded spend actions + if !nullifiers_inserted.is_empty() { + self.nullifiers_inserted.extend(nullifiers_inserted); + } } StateTransitionExecutionResult::NotExecuted(_) => { self.failed_count += 1; @@ -170,4 +179,9 @@ impl StateTransitionsProcessingResult { pub fn execution_results(&self) -> &Vec { &self.execution_results } + + /// Add nullifiers that were inserted during state transition processing + pub fn add_nullifiers_inserted(&mut self, nullifiers: Vec<[u8; 32]>) { + self.nullifiers_inserted.extend(nullifiers); + } } diff --git a/packages/rs-drive-abci/src/query/service.rs b/packages/rs-drive-abci/src/query/service.rs index d36444bd9f1..b3e0479cc91 100644 --- a/packages/rs-drive-abci/src/query/service.rs +++ b/packages/rs-drive-abci/src/query/service.rs @@ -38,17 +38,21 @@ use dapi_grpc::platform::v0::{ GetIdentityContractNonceRequest, GetIdentityContractNonceResponse, GetIdentityKeysRequest, GetIdentityKeysResponse, GetIdentityNonceRequest, GetIdentityNonceResponse, GetIdentityRequest, GetIdentityResponse, GetIdentityTokenBalancesRequest, GetIdentityTokenBalancesResponse, - GetIdentityTokenInfosRequest, GetIdentityTokenInfosResponse, GetPathElementsRequest, - GetPathElementsResponse, GetPrefundedSpecializedBalanceRequest, - GetPrefundedSpecializedBalanceResponse, GetProtocolVersionUpgradeStateRequest, - GetProtocolVersionUpgradeStateResponse, GetProtocolVersionUpgradeVoteStatusRequest, - GetProtocolVersionUpgradeVoteStatusResponse, GetRecentAddressBalanceChangesRequest, - GetRecentAddressBalanceChangesResponse, GetRecentCompactedAddressBalanceChangesRequest, - GetRecentCompactedAddressBalanceChangesResponse, GetShieldedAnchorsRequest, - GetShieldedAnchorsResponse, GetShieldedEncryptedNotesRequest, - GetShieldedEncryptedNotesResponse, GetShieldedNullifiersRequest, GetShieldedNullifiersResponse, - GetShieldedPoolStateRequest, GetShieldedPoolStateResponse, GetStatusRequest, GetStatusResponse, - GetTokenContractInfoRequest, GetTokenContractInfoResponse, GetTokenDirectPurchasePricesRequest, + GetIdentityTokenInfosRequest, GetIdentityTokenInfosResponse, GetNullifiersBranchStateRequest, + GetNullifiersBranchStateResponse, GetNullifiersTrunkStateRequest, + GetNullifiersTrunkStateResponse, GetPathElementsRequest, GetPathElementsResponse, + GetPrefundedSpecializedBalanceRequest, GetPrefundedSpecializedBalanceResponse, + GetProtocolVersionUpgradeStateRequest, GetProtocolVersionUpgradeStateResponse, + GetProtocolVersionUpgradeVoteStatusRequest, GetProtocolVersionUpgradeVoteStatusResponse, + GetRecentAddressBalanceChangesRequest, GetRecentAddressBalanceChangesResponse, + GetRecentCompactedAddressBalanceChangesRequest, + GetRecentCompactedAddressBalanceChangesResponse, GetRecentCompactedNullifierChangesRequest, + GetRecentCompactedNullifierChangesResponse, GetRecentNullifierChangesRequest, + GetRecentNullifierChangesResponse, GetShieldedAnchorsRequest, GetShieldedAnchorsResponse, + GetShieldedEncryptedNotesRequest, GetShieldedEncryptedNotesResponse, + GetShieldedNullifiersRequest, GetShieldedNullifiersResponse, GetShieldedPoolStateRequest, + GetShieldedPoolStateResponse, GetStatusRequest, GetStatusResponse, GetTokenContractInfoRequest, + GetTokenContractInfoResponse, GetTokenDirectPurchasePricesRequest, GetTokenDirectPurchasePricesResponse, GetTokenPerpetualDistributionLastClaimRequest, GetTokenPerpetualDistributionLastClaimResponse, GetTokenPreProgrammedDistributionsRequest, GetTokenPreProgrammedDistributionsResponse, GetTokenStatusesRequest, GetTokenStatusesResponse, @@ -929,6 +933,54 @@ impl PlatformService for QueryService { ) .await } + + async fn get_nullifiers_trunk_state( + &self, + request: Request, + ) -> Result, Status> { + self.handle_blocking_query( + request, + Platform::::query_nullifiers_trunk_state, + "get_nullifiers_trunk_state", + ) + .await + } + + async fn get_nullifiers_branch_state( + &self, + request: Request, + ) -> Result, Status> { + self.handle_blocking_query( + request, + Platform::::query_nullifiers_branch_state, + "get_nullifiers_branch_state", + ) + .await + } + + async fn get_recent_nullifier_changes( + &self, + request: Request, + ) -> Result, Status> { + self.handle_blocking_query( + request, + Platform::::query_recent_nullifier_changes, + "get_recent_nullifier_changes", + ) + .await + } + + async fn get_recent_compacted_nullifier_changes( + &self, + request: Request, + ) -> Result, Status> { + self.handle_blocking_query( + request, + Platform::::query_recent_compacted_nullifier_changes, + "get_recent_compacted_nullifier_changes", + ) + .await + } } #[async_trait] diff --git a/packages/rs-drive-abci/src/query/shielded/mod.rs b/packages/rs-drive-abci/src/query/shielded/mod.rs index c8cb1fb0643..50d2acf245b 100644 --- a/packages/rs-drive-abci/src/query/shielded/mod.rs +++ b/packages/rs-drive-abci/src/query/shielded/mod.rs @@ -1,4 +1,8 @@ mod anchors; mod encrypted_notes; mod nullifiers; +mod nullifiers_branch_state; +mod nullifiers_trunk_state; mod pool_state; +mod recent_compacted_nullifier_changes; +mod recent_nullifier_changes; diff --git a/packages/rs-drive-abci/src/query/shielded/nullifiers_branch_state/mod.rs b/packages/rs-drive-abci/src/query/shielded/nullifiers_branch_state/mod.rs new file mode 100644 index 00000000000..f50032376dc --- /dev/null +++ b/packages/rs-drive-abci/src/query/shielded/nullifiers_branch_state/mod.rs @@ -0,0 +1,62 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_nullifiers_branch_state_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_nullifiers_branch_state_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{GetNullifiersBranchStateRequest, GetNullifiersBranchStateResponse}; +use dpp::version::PlatformVersion; +mod v0; + +impl Platform { + /// Querying of the nullifiers branch state (merk proof for sync) + pub fn query_nullifiers_branch_state( + &self, + GetNullifiersBranchStateRequest { version }: GetNullifiersBranchStateRequest, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let Some(version) = version else { + return Ok(QueryValidationResult::new_with_error( + QueryError::DecodingError( + "could not decode nullifiers branch state query".to_string(), + ), + )); + }; + + let feature_version_bounds = &platform_version + .drive_abci + .query + .shielded_queries + .nullifiers_branch_state; + + let feature_version = match &version { + RequestVersion::V0(_) => 0, + }; + if !feature_version_bounds.check_version(feature_version) { + return Ok(QueryValidationResult::new_with_error( + QueryError::UnsupportedQueryVersion( + "nullifiers_branch_state".to_string(), + feature_version_bounds.min_version, + feature_version_bounds.max_version, + platform_version.protocol_version, + feature_version, + ), + )); + } + + match version { + RequestVersion::V0(request_v0) => { + let result = self.query_nullifiers_branch_state_v0( + request_v0, + platform_state, + platform_version, + )?; + Ok(result.map(|response_v0| GetNullifiersBranchStateResponse { + version: Some(ResponseVersion::V0(response_v0)), + })) + } + } + } +} diff --git a/packages/rs-drive-abci/src/query/shielded/nullifiers_branch_state/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/nullifiers_branch_state/v0/mod.rs new file mode 100644 index 00000000000..322ac20bcc4 --- /dev/null +++ b/packages/rs-drive-abci/src/query/shielded/nullifiers_branch_state/v0/mod.rs @@ -0,0 +1,41 @@ +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_nullifiers_branch_state_request::GetNullifiersBranchStateRequestV0; +use dapi_grpc::platform::v0::get_nullifiers_branch_state_response::GetNullifiersBranchStateResponseV0; +use dpp::version::PlatformVersion; + +impl Platform { + pub(super) fn query_nullifiers_branch_state_v0( + &self, + GetNullifiersBranchStateRequestV0 { + pool_type, + pool_identifier, + key, + depth, + checkpoint_height, + }: GetNullifiersBranchStateRequestV0, + _platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let pool_id = if pool_identifier.is_empty() { + None + } else { + Some(pool_identifier) + }; + + let merk_proof = self.drive.prove_nullifiers_branch_query( + pool_type, + pool_id, + key, + depth as u8, + checkpoint_height, + platform_version, + )?; + + let response = GetNullifiersBranchStateResponseV0 { merk_proof }; + + Ok(QueryValidationResult::new_with_data(response)) + } +} diff --git a/packages/rs-drive-abci/src/query/shielded/nullifiers_trunk_state/mod.rs b/packages/rs-drive-abci/src/query/shielded/nullifiers_trunk_state/mod.rs new file mode 100644 index 00000000000..728b32f9131 --- /dev/null +++ b/packages/rs-drive-abci/src/query/shielded/nullifiers_trunk_state/mod.rs @@ -0,0 +1,62 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_nullifiers_trunk_state_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_nullifiers_trunk_state_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{GetNullifiersTrunkStateRequest, GetNullifiersTrunkStateResponse}; +use dpp::version::PlatformVersion; +mod v0; + +impl Platform { + /// Querying of the nullifiers trunk state (proof for sync) + pub fn query_nullifiers_trunk_state( + &self, + GetNullifiersTrunkStateRequest { version }: GetNullifiersTrunkStateRequest, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let Some(version) = version else { + return Ok(QueryValidationResult::new_with_error( + QueryError::DecodingError( + "could not decode nullifiers trunk state query".to_string(), + ), + )); + }; + + let feature_version_bounds = &platform_version + .drive_abci + .query + .shielded_queries + .nullifiers_trunk_state; + + let feature_version = match &version { + RequestVersion::V0(_) => 0, + }; + if !feature_version_bounds.check_version(feature_version) { + return Ok(QueryValidationResult::new_with_error( + QueryError::UnsupportedQueryVersion( + "nullifiers_trunk_state".to_string(), + feature_version_bounds.min_version, + feature_version_bounds.max_version, + platform_version.protocol_version, + feature_version, + ), + )); + } + + match version { + RequestVersion::V0(request_v0) => { + let result = self.query_nullifiers_trunk_state_v0( + request_v0, + platform_state, + platform_version, + )?; + Ok(result.map(|response_v0| GetNullifiersTrunkStateResponse { + version: Some(ResponseVersion::V0(response_v0)), + })) + } + } + } +} diff --git a/packages/rs-drive-abci/src/query/shielded/nullifiers_trunk_state/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/nullifiers_trunk_state/v0/mod.rs new file mode 100644 index 00000000000..2b754d850d5 --- /dev/null +++ b/packages/rs-drive-abci/src/query/shielded/nullifiers_trunk_state/v0/mod.rs @@ -0,0 +1,44 @@ +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_nullifiers_trunk_state_request::GetNullifiersTrunkStateRequestV0; +use dapi_grpc::platform::v0::get_nullifiers_trunk_state_response::GetNullifiersTrunkStateResponseV0; +use dpp::check_validation_result_with_data; +use dpp::validation::ValidationResult; +use dpp::version::PlatformVersion; +use drive::util::grove_operations::GroveDBToUse; + +impl Platform { + pub(super) fn query_nullifiers_trunk_state_v0( + &self, + GetNullifiersTrunkStateRequestV0 { + pool_type, + pool_identifier, + }: GetNullifiersTrunkStateRequestV0, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let pool_id = if pool_identifier.is_empty() { + None + } else { + Some(pool_identifier) + }; + + let proof = check_validation_result_with_data!(self.drive.prove_nullifiers_trunk_query( + pool_type, + pool_id, + platform_version + )); + + let (grovedb_used, proof) = + self.response_proof_v0(platform_state, proof, GroveDBToUse::LatestCheckpoint)?; + + let response = GetNullifiersTrunkStateResponseV0 { + proof: Some(proof), + metadata: Some(self.response_metadata_v0(platform_state, grovedb_used)), + }; + + Ok(QueryValidationResult::new_with_data(response)) + } +} diff --git a/packages/rs-drive-abci/src/query/shielded/recent_compacted_nullifier_changes/mod.rs b/packages/rs-drive-abci/src/query/shielded/recent_compacted_nullifier_changes/mod.rs new file mode 100644 index 00000000000..61d778b2682 --- /dev/null +++ b/packages/rs-drive-abci/src/query/shielded/recent_compacted_nullifier_changes/mod.rs @@ -0,0 +1,67 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_recent_compacted_nullifier_changes_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_recent_compacted_nullifier_changes_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{ + GetRecentCompactedNullifierChangesRequest, GetRecentCompactedNullifierChangesResponse, +}; +use dpp::version::PlatformVersion; + +mod v0; + +impl Platform { + /// Querying of recent compacted nullifier changes + pub fn query_recent_compacted_nullifier_changes( + &self, + GetRecentCompactedNullifierChangesRequest { version }: GetRecentCompactedNullifierChangesRequest, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let Some(version) = version else { + return Ok(QueryValidationResult::new_with_error( + QueryError::DecodingError( + "could not decode recent compacted nullifier changes query".to_string(), + ), + )); + }; + + let feature_version_bounds = &platform_version + .drive_abci + .query + .shielded_queries + .recent_compacted_nullifier_changes; + + let feature_version = match &version { + RequestVersion::V0(_) => 0, + }; + if !feature_version_bounds.check_version(feature_version) { + return Ok(QueryValidationResult::new_with_error( + QueryError::UnsupportedQueryVersion( + "recent_compacted_nullifier_changes".to_string(), + feature_version_bounds.min_version, + feature_version_bounds.max_version, + platform_version.protocol_version, + feature_version, + ), + )); + } + + match version { + RequestVersion::V0(request_v0) => { + let result = self.query_recent_compacted_nullifier_changes_v0( + request_v0, + platform_state, + platform_version, + )?; + Ok( + result.map(|response_v0| GetRecentCompactedNullifierChangesResponse { + version: Some(ResponseVersion::V0(response_v0)), + }), + ) + } + } + } +} diff --git a/packages/rs-drive-abci/src/query/shielded/recent_compacted_nullifier_changes/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/recent_compacted_nullifier_changes/v0/mod.rs new file mode 100644 index 00000000000..64ce61cd827 --- /dev/null +++ b/packages/rs-drive-abci/src/query/shielded/recent_compacted_nullifier_changes/v0/mod.rs @@ -0,0 +1,78 @@ +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::response_metadata::CheckpointUsed; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_recent_compacted_nullifier_changes_request::GetRecentCompactedNullifierChangesRequestV0; +use dapi_grpc::platform::v0::get_recent_compacted_nullifier_changes_response::{ + get_recent_compacted_nullifier_changes_response_v0, + GetRecentCompactedNullifierChangesResponseV0, +}; +use dapi_grpc::platform::v0::{CompactedBlockNullifierChanges, CompactedNullifierUpdateEntries}; +use dpp::version::PlatformVersion; +use drive::util::grove_operations::GroveDBToUse; + +impl Platform { + pub(super) fn query_recent_compacted_nullifier_changes_v0( + &self, + GetRecentCompactedNullifierChangesRequestV0 { + start_block_height, + prove, + }: GetRecentCompactedNullifierChangesRequestV0, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let limit = Some(25u16); + + let response = if prove { + let proof = self.drive.prove_compacted_nullifier_changes( + start_block_height, + limit, + None, + platform_version, + )?; + + let (grovedb_used, proof) = + self.response_proof_v0(platform_state, proof, GroveDBToUse::Current)?; + + GetRecentCompactedNullifierChangesResponseV0 { + result: Some( + get_recent_compacted_nullifier_changes_response_v0::Result::Proof(proof), + ), + metadata: Some(self.response_metadata_v0(platform_state, grovedb_used)), + } + } else { + let compacted_nullifier_changes = self.drive.fetch_compacted_nullifier_changes( + start_block_height, + limit, + None, + platform_version, + )?; + + let compacted_block_changes: Vec = + compacted_nullifier_changes + .into_iter() + .map( + |(start_block, end_block, nullifiers)| CompactedBlockNullifierChanges { + start_block_height: start_block, + end_block_height: end_block, + nullifiers: nullifiers.into_iter().map(|n| n.to_vec()).collect(), + }, + ) + .collect(); + + GetRecentCompactedNullifierChangesResponseV0 { + result: Some( + get_recent_compacted_nullifier_changes_response_v0::Result::CompactedNullifierUpdateEntries( + CompactedNullifierUpdateEntries { compacted_block_changes }, + ), + ), + metadata: Some( + self.response_metadata_v0(platform_state, CheckpointUsed::Current), + ), + } + }; + + Ok(QueryValidationResult::new_with_data(response)) + } +} diff --git a/packages/rs-drive-abci/src/query/shielded/recent_nullifier_changes/mod.rs b/packages/rs-drive-abci/src/query/shielded/recent_nullifier_changes/mod.rs new file mode 100644 index 00000000000..8409234c17d --- /dev/null +++ b/packages/rs-drive-abci/src/query/shielded/recent_nullifier_changes/mod.rs @@ -0,0 +1,65 @@ +use crate::error::query::QueryError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_recent_nullifier_changes_request::Version as RequestVersion; +use dapi_grpc::platform::v0::get_recent_nullifier_changes_response::Version as ResponseVersion; +use dapi_grpc::platform::v0::{ + GetRecentNullifierChangesRequest, GetRecentNullifierChangesResponse, +}; +use dpp::version::PlatformVersion; + +mod v0; + +impl Platform { + /// Querying of recent nullifier changes + pub fn query_recent_nullifier_changes( + &self, + GetRecentNullifierChangesRequest { version }: GetRecentNullifierChangesRequest, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let Some(version) = version else { + return Ok(QueryValidationResult::new_with_error( + QueryError::DecodingError( + "could not decode recent nullifier changes query".to_string(), + ), + )); + }; + + let feature_version_bounds = &platform_version + .drive_abci + .query + .shielded_queries + .recent_nullifier_changes; + + let feature_version = match &version { + RequestVersion::V0(_) => 0, + }; + if !feature_version_bounds.check_version(feature_version) { + return Ok(QueryValidationResult::new_with_error( + QueryError::UnsupportedQueryVersion( + "recent_nullifier_changes".to_string(), + feature_version_bounds.min_version, + feature_version_bounds.max_version, + platform_version.protocol_version, + feature_version, + ), + )); + } + + match version { + RequestVersion::V0(request_v0) => { + let result = self.query_recent_nullifier_changes_v0( + request_v0, + platform_state, + platform_version, + )?; + Ok(result.map(|response_v0| GetRecentNullifierChangesResponse { + version: Some(ResponseVersion::V0(response_v0)), + })) + } + } + } +} diff --git a/packages/rs-drive-abci/src/query/shielded/recent_nullifier_changes/v0/mod.rs b/packages/rs-drive-abci/src/query/shielded/recent_nullifier_changes/v0/mod.rs new file mode 100644 index 00000000000..bd03c0c6e4b --- /dev/null +++ b/packages/rs-drive-abci/src/query/shielded/recent_nullifier_changes/v0/mod.rs @@ -0,0 +1,71 @@ +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use crate::query::response_metadata::CheckpointUsed; +use crate::query::QueryValidationResult; +use dapi_grpc::platform::v0::get_recent_nullifier_changes_request::GetRecentNullifierChangesRequestV0; +use dapi_grpc::platform::v0::get_recent_nullifier_changes_response::{ + get_recent_nullifier_changes_response_v0, GetRecentNullifierChangesResponseV0, +}; +use dapi_grpc::platform::v0::{BlockNullifierChanges, NullifierUpdateEntries}; +use dpp::version::PlatformVersion; +use drive::util::grove_operations::GroveDBToUse; + +impl Platform { + pub(super) fn query_recent_nullifier_changes_v0( + &self, + GetRecentNullifierChangesRequestV0 { + start_height, + prove, + }: GetRecentNullifierChangesRequestV0, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let limit = Some(100u16); + + let response = if prove { + let proof = self.drive.prove_recent_nullifier_changes( + start_height, + limit, + None, + platform_version, + )?; + + let (grovedb_used, proof) = + self.response_proof_v0(platform_state, proof, GroveDBToUse::Current)?; + + GetRecentNullifierChangesResponseV0 { + result: Some(get_recent_nullifier_changes_response_v0::Result::Proof( + proof, + )), + metadata: Some(self.response_metadata_v0(platform_state, grovedb_used)), + } + } else { + let nullifier_changes = self.drive.fetch_recent_nullifier_changes( + start_height, + limit, + None, + platform_version, + )?; + + let block_changes: Vec = nullifier_changes + .into_iter() + .map(|(block_height, nullifiers)| BlockNullifierChanges { + block_height, + nullifiers: nullifiers.into_iter().map(|n| n.to_vec()).collect(), + }) + .collect(); + + GetRecentNullifierChangesResponseV0 { + result: Some( + get_recent_nullifier_changes_response_v0::Result::NullifierUpdateEntries( + NullifierUpdateEntries { block_changes }, + ), + ), + metadata: Some(self.response_metadata_v0(platform_state, CheckpointUsed::Current)), + } + }; + + Ok(QueryValidationResult::new_with_data(response)) + } +} diff --git a/packages/rs-drive-proof-verifier/src/proof.rs b/packages/rs-drive-proof-verifier/src/proof.rs index 98d1f2052a0..b320a062018 100644 --- a/packages/rs-drive-proof-verifier/src/proof.rs +++ b/packages/rs-drive-proof-verifier/src/proof.rs @@ -1087,18 +1087,87 @@ impl FromProof for PlatformAddressTrunk where PlatformAddressTrunkState: 'a, { - let (result, metadata, proof) = GroveTrunkQueryResult::maybe_from_proof_with_metadata( - request, - response, - network, - platform_version, - provider, + let (result, metadata, proof) = >::maybe_from_proof_with_metadata( + request, response, network, platform_version, provider )?; Ok((result.map(PlatformAddressTrunkState), metadata, proof)) } } +impl FromProof for GroveTrunkQueryResult { + type Request = platform::GetNullifiersTrunkStateRequest; + type Response = platform::GetNullifiersTrunkStateResponse; + + fn maybe_from_proof_with_metadata<'a, I: Into, O: Into>( + request: I, + response: O, + _network: Network, + platform_version: &PlatformVersion, + provider: &'a dyn ContextProvider, + ) -> Result<(Option, ResponseMetadata, Proof), Error> + where + GroveTrunkQueryResult: 'a, + { + let request: Self::Request = request.into(); + let response: Self::Response = response.into(); + + let proof = response.proof().or(Err(Error::NoProofInResult))?; + let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?; + + // Extract pool_type and pool_identifier from request + let (pool_type, pool_identifier) = match &request.version { + Some(platform::get_nullifiers_trunk_state_request::Version::V0(v0)) => { + let pool_id = if v0.pool_identifier.is_empty() { + None + } else { + Some(v0.pool_identifier.as_slice()) + }; + (v0.pool_type, pool_id) + } + None => return Err(Error::EmptyVersion), + }; + + let (root_hash, trunk_result) = Drive::verify_nullifiers_trunk_query( + &proof.grovedb_proof, + pool_type, + pool_identifier, + platform_version, + ) + .map_drive_error(proof, mtd)?; + + verify_tenderdash_proof(proof, mtd, &root_hash, provider)?; + + Ok((Some(trunk_result), mtd.clone(), proof.clone())) + } +} + +impl FromProof for NullifiersTrunkState { + type Request = platform::GetNullifiersTrunkStateRequest; + type Response = platform::GetNullifiersTrunkStateResponse; + + fn maybe_from_proof_with_metadata<'a, I: Into, O: Into>( + request: I, + response: O, + network: Network, + platform_version: &PlatformVersion, + provider: &'a dyn ContextProvider, + ) -> Result<(Option, ResponseMetadata, Proof), Error> + where + NullifiersTrunkState: 'a, + { + let (result, metadata, proof) = >::maybe_from_proof_with_metadata( + request, response, network, platform_version, provider + )?; + + Ok((result.map(NullifiersTrunkState), metadata, proof)) + } +} + impl FromProof for DataContract { type Request = platform::GetDataContractRequest; type Response = platform::GetDataContractResponse; @@ -2462,6 +2531,118 @@ impl FromProof for ShieldedNullifierStat } } +impl FromProof for RecentNullifierChanges { + type Request = platform::GetRecentNullifierChangesRequest; + type Response = platform::GetRecentNullifierChangesResponse; + + fn maybe_from_proof_with_metadata<'a, I: Into, O: Into>( + request: I, + response: O, + _network: Network, + platform_version: &PlatformVersion, + provider: &'a dyn ContextProvider, + ) -> Result<(Option, ResponseMetadata, Proof), Error> + where + RecentNullifierChanges: 'a, + { + use dapi_grpc::platform::v0::get_recent_nullifier_changes_request; + + let request: Self::Request = request.into(); + let response: Self::Response = response.into(); + + let proof = response.proof().or(Err(Error::NoProofInResult))?; + let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?; + + let start_height = match request.version.ok_or(Error::EmptyVersion)? { + get_recent_nullifier_changes_request::Version::V0(v0) => v0.start_height, + }; + + let limit = Some(100u16); // Same limit as in query handler + + let (root_hash, verified_changes) = Drive::verify_recent_nullifier_changes( + &proof.grovedb_proof, + start_height, + limit, + false, + platform_version, + ) + .map_drive_error(proof, mtd)?; + + verify_tenderdash_proof(proof, mtd, &root_hash, provider)?; + + let result = RecentNullifierChanges( + verified_changes + .into_iter() + .map(|(block_height, nullifiers)| BlockNullifierChanges { + block_height, + nullifiers, + }) + .collect(), + ); + + Ok((Some(result), mtd.clone(), proof.clone())) + } +} + +impl FromProof + for RecentCompactedNullifierChanges +{ + type Request = platform::GetRecentCompactedNullifierChangesRequest; + type Response = platform::GetRecentCompactedNullifierChangesResponse; + + fn maybe_from_proof_with_metadata<'a, I: Into, O: Into>( + request: I, + response: O, + _network: Network, + platform_version: &PlatformVersion, + provider: &'a dyn ContextProvider, + ) -> Result<(Option, ResponseMetadata, Proof), Error> + where + RecentCompactedNullifierChanges: 'a, + { + use dapi_grpc::platform::v0::get_recent_compacted_nullifier_changes_request; + + let request: Self::Request = request.into(); + let response: Self::Response = response.into(); + + let proof = response.proof().or(Err(Error::NoProofInResult))?; + let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?; + + let start_block_height = match request.version.ok_or(Error::EmptyVersion)? { + get_recent_compacted_nullifier_changes_request::Version::V0(v0) => { + v0.start_block_height + } + }; + + let limit = Some(25u16); // Same limit as in query handler + + let (root_hash, verified_changes) = Drive::verify_compacted_nullifier_changes( + &proof.grovedb_proof, + start_block_height, + limit, + platform_version, + ) + .map_drive_error(proof, mtd)?; + + verify_tenderdash_proof(proof, mtd, &root_hash, provider)?; + + let result = RecentCompactedNullifierChanges( + verified_changes + .into_iter() + .map(|(start_block_height, end_block_height, nullifiers)| { + CompactedBlockNullifierChanges { + start_block_height, + end_block_height, + nullifiers, + } + }) + .collect(), + ); + + Ok((Some(result), mtd.clone(), proof.clone())) + } +} + /// Determine number of non-None elements pub trait Length { /// Return number of non-None elements in the data structure diff --git a/packages/rs-drive-proof-verifier/src/types.rs b/packages/rs-drive-proof-verifier/src/types.rs index 929b905e209..d6577516a83 100644 --- a/packages/rs-drive-proof-verifier/src/types.rs +++ b/packages/rs-drive-proof-verifier/src/types.rs @@ -760,6 +760,34 @@ impl std::ops::DerefMut for PlatformAddressTrunkState { } } +/// Nullifiers trunk state for nullifier tree synchronization. +/// +/// This is a newtype wrapper around [`GroveTrunkQueryResult`](drive::grovedb::GroveTrunkQueryResult) +/// that represents the result of querying the trunk (top levels) of the nullifiers tree. +#[derive(Debug)] +pub struct NullifiersTrunkState(pub drive::grovedb::GroveTrunkQueryResult); + +impl NullifiersTrunkState { + /// Get the inner `GroveTrunkQueryResult`. + pub fn into_inner(self) -> drive::grovedb::GroveTrunkQueryResult { + self.0 + } +} + +impl std::ops::Deref for NullifiersTrunkState { + type Target = drive::grovedb::GroveTrunkQueryResult; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl std::ops::DerefMut for NullifiersTrunkState { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + /// Shielded pool total balance #[derive(Debug, derive_more::From, Clone, Copy)] #[cfg_attr( @@ -848,3 +876,65 @@ pub struct ShieldedEncryptedNotesQuery { platform_serialize(unversioned) )] pub struct ShieldedNullifiersQuery(pub Vec>); + +/// Nullifier changes for a single block. +#[derive(Debug, Clone)] +#[cfg_attr( + feature = "mocks", + derive(Encode, Decode, PlatformSerialize, PlatformDeserialize), + platform_serialize(unversioned) +)] +pub struct BlockNullifierChanges { + /// The block height + pub block_height: u64, + /// Nullifiers inserted in this block (each 32 bytes) + pub nullifiers: Vec<[u8; 32]>, +} + +/// Recent nullifier changes across multiple blocks. +#[derive(Debug, Clone, Default, derive_more::From)] +#[cfg_attr( + feature = "mocks", + derive(Encode, Decode, PlatformSerialize, PlatformDeserialize), + platform_serialize(unversioned) +)] +pub struct RecentNullifierChanges(pub Vec); + +impl RecentNullifierChanges { + /// Get the inner vector + pub fn into_inner(self) -> Vec { + self.0 + } +} + +/// Compacted nullifier changes for a range of blocks. +#[derive(Debug, Clone)] +#[cfg_attr( + feature = "mocks", + derive(Encode, Decode, PlatformSerialize, PlatformDeserialize), + platform_serialize(unversioned) +)] +pub struct CompactedBlockNullifierChanges { + /// The start block height of the compacted range + pub start_block_height: u64, + /// The end block height of the compacted range + pub end_block_height: u64, + /// Nullifiers from this block range (each 32 bytes) + pub nullifiers: Vec<[u8; 32]>, +} + +/// Compacted nullifier changes across multiple ranges. +#[derive(Debug, Clone, Default, derive_more::From)] +#[cfg_attr( + feature = "mocks", + derive(Encode, Decode, PlatformSerialize, PlatformDeserialize), + platform_serialize(unversioned) +)] +pub struct RecentCompactedNullifierChanges(pub Vec); + +impl RecentCompactedNullifierChanges { + /// Get the inner vector + pub fn into_inner(self) -> Vec { + self.0 + } +} diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index 76bb43bf626..89beb64afce 100644 --- a/packages/rs-drive/Cargo.toml +++ b/packages/rs-drive/Cargo.toml @@ -52,12 +52,12 @@ enum-map = { version = "2.0.3", optional = true } intmap = { version = "3.0.1", features = ["serde"], optional = true } chrono = { version = "0.4.35", optional = true } itertools = { version = "0.13", optional = true } -grovedb = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8", optional = true, default-features = false } -grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8", optional = true } -grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8" } -grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8", optional = true } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8" } -grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8" } +grovedb = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444", optional = true, default-features = false } +grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444", optional = true } +grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444" } +grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444", optional = true } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444" } +grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444" } [dev-dependencies] criterion = "0.5" diff --git a/packages/rs-drive/src/drive/initialization/v3/mod.rs b/packages/rs-drive/src/drive/initialization/v3/mod.rs index b406520197b..6675b95589a 100644 --- a/packages/rs-drive/src/drive/initialization/v3/mod.rs +++ b/packages/rs-drive/src/drive/initialization/v3/mod.rs @@ -1,5 +1,8 @@ //! Drive Initialization +use crate::drive::saved_block_transactions::{ + COMPACTED_NULLIFIERS_KEY_U8, NULLIFIERS_EXPIRATION_TIME_KEY_U8, NULLIFIERS_KEY_U8, +}; use crate::drive::shielded::paths::*; use crate::drive::{Drive, RootTree}; use crate::error::Error; @@ -85,11 +88,11 @@ impl Drive { Element::empty_commitment_tree(11), ); - // 3. Nullifiers tree (NormalTree) + // 3. Nullifiers tree (ProvableCountTree) batch.add_insert( shielded_credit_pool_path_vec(), vec![SHIELDED_NULLIFIERS_KEY], - Element::empty_tree(), + Element::empty_provable_count_tree(), ); // 4. Total balance SumItem(0) @@ -106,6 +109,32 @@ impl Drive { Element::empty_tree(), ); + // 6. Nullifiers CountSumTree under SavedBlockTransactions for storing + // per-block nullifier lists. Each item is an ItemWithSumItem + // (serialized Vec<[u8;32]> + nullifier count as sum). + batch.add_insert( + Self::saved_block_transactions_path(), + vec![NULLIFIERS_KEY_U8], + Element::empty_count_sum_tree(), + ); + + // 7. Compacted nullifiers NormalTree under SavedBlockTransactions for storing + // compacted/aggregated nullifier lists spanning multiple blocks. + // Key: (start_block, end_block) as 16 bytes, Value: serialized Vec<[u8;32]> + batch.add_insert( + Self::saved_block_transactions_path(), + vec![COMPACTED_NULLIFIERS_KEY_U8], + Element::empty_tree(), + ); + + // 8. Nullifiers expiration time NormalTree under SavedBlockTransactions for storing + // expiration timestamps for compacted nullifier ranges. + batch.add_insert( + Self::saved_block_transactions_path(), + vec![NULLIFIERS_EXPIRATION_TIME_KEY_U8], + Element::empty_tree(), + ); + Ok(()) } } diff --git a/packages/rs-drive/src/drive/saved_block_transactions/cleanup_expired_nullifiers/mod.rs b/packages/rs-drive/src/drive/saved_block_transactions/cleanup_expired_nullifiers/mod.rs new file mode 100644 index 00000000000..a3288990f1b --- /dev/null +++ b/packages/rs-drive/src/drive/saved_block_transactions/cleanup_expired_nullifiers/mod.rs @@ -0,0 +1,49 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use grovedb::TransactionArg; +use platform_version::version::PlatformVersion; + +impl Drive { + /// Cleans up expired compacted nullifier entries. + /// + /// This function queries the nullifier expiration time tree for entries with + /// expiration time <= current_block_time_ms, then deletes: + /// 1. The corresponding compacted nullifier entries + /// 2. The expiration time entries themselves + /// + /// # Arguments + /// * `current_block_time_ms` - The current block time in milliseconds + /// * `transaction` - Optional database transaction + /// * `platform_version` - The platform version + /// + /// # Returns + /// * `Ok(usize)` - The number of compacted entries that were cleaned up + /// * `Err` - An error occurred + pub fn cleanup_expired_nullifiers( + &self, + current_block_time_ms: u64, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive + .methods + .saved_block_transactions + .cleanup_expired_nullifiers + { + 0 => self.cleanup_expired_nullifiers_v0( + current_block_time_ms, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "cleanup_expired_nullifiers".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/saved_block_transactions/cleanup_expired_nullifiers/v0/mod.rs b/packages/rs-drive/src/drive/saved_block_transactions/cleanup_expired_nullifiers/v0/mod.rs new file mode 100644 index 00000000000..e9a48f2e051 --- /dev/null +++ b/packages/rs-drive/src/drive/saved_block_transactions/cleanup_expired_nullifiers/v0/mod.rs @@ -0,0 +1,95 @@ +use crate::drive::Drive; +use crate::error::Error; +use crate::util::batch::grovedb_op_batch::GroveDbOpBatchV0Methods; +use crate::util::batch::GroveDbOpBatch; +use dpp::ProtocolError; +use grovedb::query_result_type::QueryResultType; +use grovedb::{PathQuery, Query, QueryItem, SizedQuery, TransactionArg}; +use platform_version::version::PlatformVersion; + +impl Drive { + /// Version 0 implementation of cleaning up expired compacted nullifier entries. + /// + /// Queries for all expiration entries with time <= current_block_time_ms, + /// then deletes the corresponding compacted entries and the expiration entries. + pub(super) fn cleanup_expired_nullifiers_v0( + &self, + current_block_time_ms: u64, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let expiration_path = Self::saved_nullifiers_expiration_time_path_vec(); + + // Query all entries with expiration time <= current_block_time_ms + let mut query = Query::new(); + // Range from 0 to current_block_time_ms (inclusive) + query.insert_item(QueryItem::RangeToInclusive( + ..=current_block_time_ms.to_be_bytes().to_vec(), + )); + + let path_query = + PathQuery::new(expiration_path.clone(), SizedQuery::new(query, None, None)); + + let (results, _) = self.grove_get_path_query( + &path_query, + transaction, + QueryResultType::QueryKeyElementPairResultType, + &mut vec![], + &platform_version.drive, + )?; + + let key_elements = results.to_key_elements(); + + if key_elements.is_empty() { + return Ok(0); + } + + let config = bincode::config::standard() + .with_big_endian() + .with_no_limit(); + + let mut batch = GroveDbOpBatch::new(); + let mut total_cleaned = 0usize; + + let compacted_path = Self::saved_compacted_block_transactions_nullifiers_path_vec(); + + for (expiration_key, element) in key_elements { + // Get the vec of block ranges from the element + let grovedb::Element::Item(serialized_ranges, _) = element else { + return Err(Error::Protocol(Box::new( + ProtocolError::CorruptedSerialization( + "expected item element for expiration block ranges".to_string(), + ), + ))); + }; + + // Deserialize the vec of block ranges + let (ranges, _): (Vec<(u64, u64)>, usize) = + bincode::decode_from_slice(&serialized_ranges, config).map_err(|e| { + Error::Protocol(Box::new(ProtocolError::CorruptedSerialization(format!( + "cannot decode expiration block ranges: {}", + e + )))) + })?; + + // Delete each compacted nullifier entry + for (start_block, end_block) in &ranges { + let mut compacted_key = Vec::with_capacity(16); + compacted_key.extend_from_slice(&start_block.to_be_bytes()); + compacted_key.extend_from_slice(&end_block.to_be_bytes()); + + batch.add_delete(compacted_path.clone(), compacted_key); + total_cleaned += 1; + } + + // Delete the expiration entry itself + batch.add_delete(expiration_path.clone(), expiration_key); + } + + if !batch.is_empty() { + self.grove_apply_batch(batch, false, transaction, &platform_version.drive)?; + } + + Ok(total_cleaned) + } +} diff --git a/packages/rs-drive/src/drive/saved_block_transactions/compact_nullifiers/mod.rs b/packages/rs-drive/src/drive/saved_block_transactions/compact_nullifiers/mod.rs new file mode 100644 index 00000000000..d85d2815fa1 --- /dev/null +++ b/packages/rs-drive/src/drive/saved_block_transactions/compact_nullifiers/mod.rs @@ -0,0 +1,61 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use grovedb::TransactionArg; +use platform_version::version::PlatformVersion; + +/// One week in milliseconds (used for compacted nullifier expiration) +pub const ONE_WEEK_IN_MS: u64 = 7 * 24 * 60 * 60 * 1000; + +impl Drive { + /// Compacts nullifiers from recent blocks, including the current block, + /// into a single compacted entry. + /// + /// This function drains all entries from the nullifiers tree, concatenates them + /// with the provided current block's nullifiers, and stores the result in + /// the compacted nullifiers tree with a (start_block, end_block) key. + /// + /// Also stores the expiration time (current block time + 1 week) in the + /// nullifiers expiration time tree. + /// + /// # Arguments + /// * `current_nullifiers` - The current block's nullifiers to include + /// * `current_block_height` - The height of the current block + /// * `current_block_time_ms` - The current block time in milliseconds + /// * `transaction` - Optional database transaction + /// * `platform_version` - The platform version + /// + /// # Returns + /// * `Ok((start, end))` - The block range that was compacted + /// * `Err` - An error occurred + pub fn compact_nullifiers_with_current_block( + &self, + current_nullifiers: &[[u8; 32]], + current_block_height: u64, + current_block_time_ms: u64, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(u64, u64), Error> { + match platform_version + .drive + .methods + .saved_block_transactions + .compact_nullifiers + { + 0 => self.compact_nullifiers_with_current_block_v0( + current_nullifiers, + current_block_height, + current_block_time_ms, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "compact_nullifiers_with_current_block".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/saved_block_transactions/compact_nullifiers/v0/mod.rs b/packages/rs-drive/src/drive/saved_block_transactions/compact_nullifiers/v0/mod.rs new file mode 100644 index 00000000000..849c6d7d037 --- /dev/null +++ b/packages/rs-drive/src/drive/saved_block_transactions/compact_nullifiers/v0/mod.rs @@ -0,0 +1,194 @@ +use crate::drive::saved_block_transactions::compact_nullifiers::ONE_WEEK_IN_MS; +use crate::drive::Drive; +use crate::error::Error; +use crate::util::batch::grovedb_op_batch::GroveDbOpBatchV0Methods; +use crate::util::batch::GroveDbOpBatch; +use crate::util::grove_operations::DirectQueryType; +use dpp::ProtocolError; +use grovedb::query_result_type::QueryResultType; +use grovedb::{Element, PathQuery, Query, SizedQuery, TransactionArg}; +use grovedb_path::SubtreePath; +use platform_version::version::PlatformVersion; + +impl Drive { + /// Version 0 implementation of compacting nullifiers including a current block. + /// + /// Drains all entries from the nullifiers count sum tree, + /// concatenates them with the provided current block's nullifiers, + /// and stores the result in the compacted nullifiers tree + /// with a (start_block, end_block) key. + /// + /// Also stores the expiration time (current block time + 1 week) in the + /// nullifiers expiration time tree with the same (start_block, end_block) key. + /// + /// Returns the range of blocks that were compacted (start_block, end_block). + pub(super) fn compact_nullifiers_with_current_block_v0( + &self, + current_nullifiers: &[[u8; 32]], + current_block_height: u64, + current_block_time_ms: u64, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(u64, u64), Error> { + let path = Self::saved_block_transactions_nullifiers_path_vec(); + + // Query all entries from the nullifiers tree + let mut query = Query::new(); + query.insert_all(); + + let path_query = PathQuery::new(path.clone(), SizedQuery::new(query, None, None)); + + let (results, _) = self.grove_get_path_query( + &path_query, + transaction, + QueryResultType::QueryKeyElementPairResultType, + &mut vec![], + &platform_version.drive, + )?; + + let key_elements = results.to_key_elements(); + + let config = bincode::config::standard() + .with_big_endian() + .with_no_limit(); + + // Track block range - start with current block + let mut start_block: u64 = current_block_height; + let mut end_block: u64 = current_block_height; + + // Concatenate all nullifiers together (no merge semantics needed) + let mut combined_nullifiers: Vec<[u8; 32]> = Vec::new(); + let mut keys_to_delete: Vec> = Vec::new(); + + // Process stored blocks in chronological order (ascending by block height) + // Keys are big-endian u64, so they're already in ascending order + for (key, element) in key_elements { + // Parse block height from key (8 bytes, big-endian) + let height_bytes: [u8; 8] = key.clone().try_into().map_err(|_| { + Error::Protocol(Box::new(ProtocolError::CorruptedSerialization( + "invalid block height key length".to_string(), + ))) + })?; + let block_height = u64::from_be_bytes(height_bytes); + + // Track start and end blocks + if block_height < start_block { + start_block = block_height; + } + if block_height > end_block { + end_block = block_height; + } + + // Get the serialized data from the ItemWithSumItem element + let Element::ItemWithSumItem(serialized_data, _, _) = element else { + return Err(Error::Protocol(Box::new( + ProtocolError::CorruptedSerialization( + "expected item with sum item element for nullifiers".to_string(), + ), + ))); + }; + + // Deserialize the nullifier list + let (block_nullifiers, _): (Vec<[u8; 32]>, usize) = + bincode::decode_from_slice(&serialized_data, config).map_err(|e| { + Error::Protocol(Box::new(ProtocolError::CorruptedSerialization(format!( + "cannot decode nullifiers: {}", + e + )))) + })?; + + // Simply concatenate - no merge semantics needed for nullifiers + combined_nullifiers.extend(block_nullifiers); + + keys_to_delete.push(key); + } + + // Append the current block's nullifiers + combined_nullifiers.extend_from_slice(current_nullifiers); + + // Serialize the combined nullifiers + let serialized = bincode::encode_to_vec(&combined_nullifiers, config).map_err(|e| { + Error::Protocol(Box::new(ProtocolError::CorruptedSerialization(format!( + "cannot encode compacted nullifiers: {}", + e + )))) + })?; + + // Create the compacted key: (start_block, end_block) as 16 bytes + let mut compacted_key = Vec::with_capacity(16); + compacted_key.extend_from_slice(&start_block.to_be_bytes()); + compacted_key.extend_from_slice(&end_block.to_be_bytes()); + + // Build batch operations + let mut batch = GroveDbOpBatch::new(); + + // Delete all original entries from the count sum tree + for key in keys_to_delete { + batch.add_delete(path.clone(), key); + } + + // Insert the compacted entry as a plain Item (not ItemWithSumItem) + batch.add_insert( + Self::saved_compacted_block_transactions_nullifiers_path_vec(), + compacted_key.clone(), + Element::new_item(serialized), + ); + + // Calculate expiration time (current block time + 1 week) + let expiration_time_ms = current_block_time_ms.saturating_add(ONE_WEEK_IN_MS); + let expiration_key = expiration_time_ms.to_be_bytes().to_vec(); + + // Check if an entry with this expiration time already exists + // If so, we need to append to the existing vec of block ranges + let expiration_path = Self::saved_nullifiers_expiration_time_path(); + + let mut drive_operations = vec![]; + let existing_ranges = self.grove_get_raw_optional( + SubtreePath::from(expiration_path.as_ref()), + &expiration_key, + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )?; + + let expiration_value = if let Some(Element::Item(existing_data, _)) = existing_ranges { + // Deserialize existing vec of block ranges and append the new one + let (mut ranges, _): (Vec<(u64, u64)>, usize) = + bincode::decode_from_slice(&existing_data, config).map_err(|e| { + Error::Protocol(Box::new(ProtocolError::CorruptedSerialization(format!( + "cannot decode expiration block ranges: {}", + e + )))) + })?; + ranges.push((start_block, end_block)); + bincode::encode_to_vec(&ranges, config).map_err(|e| { + Error::Protocol(Box::new(ProtocolError::CorruptedSerialization(format!( + "cannot encode expiration block ranges: {}", + e + )))) + })? + } else { + // No existing entry, create new vec with single range + let ranges: Vec<(u64, u64)> = vec![(start_block, end_block)]; + bincode::encode_to_vec(&ranges, config).map_err(|e| { + Error::Protocol(Box::new(ProtocolError::CorruptedSerialization(format!( + "cannot encode expiration block ranges: {}", + e + )))) + })? + }; + + // Store in the expiration tree: key = expiration_time, value = vec of (start_block, end_block) + batch.add_insert( + Self::saved_nullifiers_expiration_time_path_vec(), + expiration_key, + Element::new_item(expiration_value), + ); + + // Apply the batch + self.grove_apply_batch(batch, false, transaction, &platform_version.drive)?; + + Ok((start_block, end_block)) + } +} diff --git a/packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_nullifiers/mod.rs b/packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_nullifiers/mod.rs new file mode 100644 index 00000000000..49892a3f085 --- /dev/null +++ b/packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_nullifiers/mod.rs @@ -0,0 +1,85 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use grovedb::TransactionArg; +use platform_version::version::PlatformVersion; + +pub use v0::CompactedNullifierChanges; + +impl Drive { + /// Fetches compacted nullifier changes starting from a given block height. + /// + /// # Arguments + /// * `start_block_height` - The block height to start fetching from + /// * `limit` - Optional maximum number of compacted entries to return + /// * `transaction` - Optional database transaction + /// * `platform_version` - The platform version + /// + /// # Returns + /// A vector of (start_block, end_block, nullifiers) tuples + pub fn fetch_compacted_nullifier_changes( + &self, + start_block_height: u64, + limit: Option, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive + .methods + .saved_block_transactions + .fetch_nullifiers + { + 0 => self.fetch_compacted_nullifier_changes_v0( + start_block_height, + limit, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_compacted_nullifier_changes".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Proves compacted nullifier changes starting from a given block height. + /// + /// # Arguments + /// * `start_block_height` - The block height to start from + /// * `limit` - Optional maximum number of compacted entries to prove + /// * `transaction` - Optional database transaction + /// * `platform_version` - The platform version + /// + /// # Returns + /// A grovedb proof + pub fn prove_compacted_nullifier_changes( + &self, + start_block_height: u64, + limit: Option, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .saved_block_transactions + .fetch_nullifiers + { + 0 => self.prove_compacted_nullifier_changes_v0( + start_block_height, + limit, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_compacted_nullifier_changes".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_nullifiers/v0/mod.rs b/packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_nullifiers/v0/mod.rs new file mode 100644 index 00000000000..d95e5c5a3b3 --- /dev/null +++ b/packages/rs-drive/src/drive/saved_block_transactions/fetch_compacted_nullifiers/v0/mod.rs @@ -0,0 +1,277 @@ +use crate::drive::Drive; +use crate::error::Error; +use dpp::ProtocolError; +use grovedb::query_result_type::QueryResultType; +use grovedb::{Element, PathQuery, Query, SizedQuery, TransactionArg}; +use platform_version::version::PlatformVersion; + +/// Result type for fetched compacted nullifier changes +/// Each entry is (start_block, end_block, nullifiers) +pub type CompactedNullifierChanges = Vec<(u64, u64, Vec<[u8; 32]>)>; + +impl Drive { + /// Version 0 implementation of fetching compacted nullifier changes. + /// + /// Retrieves all compacted nullifier change records where `end_block >= start_block_height`. + /// This includes ranges that contain `start_block_height` (e.g., range 400-600 when querying + /// from block 505) as well as ranges that start after `start_block_height`. + /// + /// Returns a vector of (start_block, end_block, nullifiers) tuples. + pub(super) fn fetch_compacted_nullifier_changes_v0( + &self, + start_block_height: u64, + limit: Option, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let path = Self::saved_compacted_block_transactions_nullifiers_path_vec(); + + // Keys are 16 bytes: (start_block, end_block), both big-endian. + // We want ranges where end_block >= start_block_height, which includes: + // - Ranges that contain start_block_height (e.g., 400-600 contains 505) + // - Ranges that start at or after start_block_height + // + // Strategy: + // 1. First query: descending from (start_block_height, u64::MAX) with limit 1 + // to find any range where start_block <= start_block_height that might contain it + // 2. Second query: ascending from (start_block_height, 0) to get ranges + // that start at or after start_block_height + + let config = bincode::config::standard() + .with_big_endian() + .with_no_limit(); + + let mut compacted_changes = Vec::new(); + let limit_usize = limit.map(|l| l as usize); + + // Query 1: Find if there's a range containing start_block_height + // Query descending from (start_block_height, u64::MAX) with limit 1 + let mut desc_end_key = Vec::with_capacity(16); + desc_end_key.extend_from_slice(&start_block_height.to_be_bytes()); + desc_end_key.extend_from_slice(&u64::MAX.to_be_bytes()); + + let mut desc_query = Query::new_with_direction(false); // descending + desc_query.insert_range_to_inclusive(..=desc_end_key); + + let desc_path_query = + PathQuery::new(path.clone(), SizedQuery::new(desc_query, Some(1), None)); + + let (desc_results, _) = self.grove_get_path_query( + &desc_path_query, + transaction, + QueryResultType::QueryKeyElementPairResultType, + &mut vec![], + &platform_version.drive, + )?; + + // Check if we found a range that contains start_block_height + if let Some((key, element)) = desc_results.to_key_elements().into_iter().next() { + if key.len() != 16 { + return Err(Error::Protocol(Box::new( + ProtocolError::CorruptedSerialization( + "invalid compacted block key length, expected 16 bytes".to_string(), + ), + ))); + } + + let start_block = u64::from_be_bytes( + key[0..8] + .try_into() + .expect("slice is exactly 8 bytes from a 16-byte key"), + ); + let end_block = u64::from_be_bytes( + key[8..16] + .try_into() + .expect("slice is exactly 8 bytes from a 16-byte key"), + ); + + // Only include if end_block >= start_block_height (range contains our block) + if end_block >= start_block_height { + let Element::Item(serialized_data, _) = element else { + return Err(Error::Protocol(Box::new( + ProtocolError::CorruptedSerialization( + "expected item element for compacted nullifiers".to_string(), + ), + ))); + }; + + let (nullifiers, _): (Vec<[u8; 32]>, usize) = + bincode::decode_from_slice(&serialized_data, config).map_err(|e| { + Error::Protocol(Box::new(ProtocolError::CorruptedSerialization(format!( + "cannot decode compacted nullifiers: {}", + e + )))) + })?; + + compacted_changes.push((start_block, end_block, nullifiers)); + } + } + + // Check if we've already hit the limit + if let Some(l) = limit_usize { + if compacted_changes.len() >= l { + return Ok(compacted_changes); + } + } + + // Query 2: Get ranges that start at or after start_block_height (ascending) + // Always use (start_block_height, 0) for consistent proof verification + // The result may overlap with descending query if descending found a range + // starting exactly at start_block_height - we dedupe below + let mut asc_start_key = Vec::with_capacity(16); + asc_start_key.extend_from_slice(&start_block_height.to_be_bytes()); + asc_start_key.extend_from_slice(&0u64.to_be_bytes()); + + let mut asc_query = Query::new(); + asc_query.insert_range_from(asc_start_key..); + + let asc_path_query = PathQuery::new(path, SizedQuery::new(asc_query, limit, None)); + + let (asc_results, _) = self.grove_get_path_query( + &asc_path_query, + transaction, + QueryResultType::QueryKeyElementPairResultType, + &mut vec![], + &platform_version.drive, + )?; + + // Track the start_block from descending query to avoid duplicates + let desc_start_block = compacted_changes.first().map(|(start, _, _)| *start); + + for (key, element) in asc_results.to_key_elements() { + // Check if we've reached the limit + if let Some(l) = limit_usize { + if compacted_changes.len() >= l { + break; + } + } + + if key.len() != 16 { + return Err(Error::Protocol(Box::new( + ProtocolError::CorruptedSerialization( + "invalid compacted block key length, expected 16 bytes".to_string(), + ), + ))); + } + + let start_block = u64::from_be_bytes( + key[0..8] + .try_into() + .expect("slice is exactly 8 bytes from a 16-byte key"), + ); + let end_block = u64::from_be_bytes( + key[8..16] + .try_into() + .expect("slice is exactly 8 bytes from a 16-byte key"), + ); + + // Skip if this is the same range we got from descending query + if Some(start_block) == desc_start_block { + continue; + } + + let Element::Item(serialized_data, _) = element else { + return Err(Error::Protocol(Box::new( + ProtocolError::CorruptedSerialization( + "expected item element for compacted nullifiers".to_string(), + ), + ))); + }; + + let (nullifiers, _): (Vec<[u8; 32]>, usize) = + bincode::decode_from_slice(&serialized_data, config).map_err(|e| { + Error::Protocol(Box::new(ProtocolError::CorruptedSerialization(format!( + "cannot decode compacted nullifiers: {}", + e + )))) + })?; + + compacted_changes.push((start_block, end_block, nullifiers)); + } + + Ok(compacted_changes) + } + + /// Version 0 implementation for proving compacted nullifier changes. + /// + /// Uses a two-step approach: + /// 1. First query (non-proving): descending to find any range containing start_block_height + /// 2. Second query (proving): ascending from the found start_block or start_block_height + /// + /// This ensures the proof covers all relevant ranges efficiently. + pub(super) fn prove_compacted_nullifier_changes_v0( + &self, + start_block_height: u64, + limit: Option, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let path = Self::saved_compacted_block_transactions_nullifiers_path_vec(); + + // Step 1: Non-proving descending query to find any range containing start_block_height + let mut desc_end_key = Vec::with_capacity(16); + desc_end_key.extend_from_slice(&start_block_height.to_be_bytes()); + desc_end_key.extend_from_slice(&u64::MAX.to_be_bytes()); + + let mut desc_query = Query::new_with_direction(false); // descending + desc_query.insert_range_to_inclusive(..=desc_end_key); + + let desc_path_query = + PathQuery::new(path.clone(), SizedQuery::new(desc_query, Some(1), None)); + + let (desc_results, _) = self.grove_get_path_query( + &desc_path_query, + transaction, + QueryResultType::QueryKeyElementPairResultType, + &mut vec![], + &platform_version.drive, + )?; + + // Determine the actual start key for the proved query + // If we found a containing range, use its exact key + // Otherwise use (start_block_height, start_block_height) since end_block >= start_block always + let start_key = if let Some((key, _)) = desc_results.to_key_elements().into_iter().next() { + if key.len() == 16 { + let end_block = u64::from_be_bytes( + key[8..16] + .try_into() + .expect("slice is exactly 8 bytes from a 16-byte key"), + ); + // If this range contains start_block_height, use its exact key + if end_block >= start_block_height { + key + } else { + // No containing range, use (start_block_height, start_block_height) + let mut key = Vec::with_capacity(16); + key.extend_from_slice(&start_block_height.to_be_bytes()); + key.extend_from_slice(&start_block_height.to_be_bytes()); + key + } + } else { + let mut key = Vec::with_capacity(16); + key.extend_from_slice(&start_block_height.to_be_bytes()); + key.extend_from_slice(&start_block_height.to_be_bytes()); + key + } + } else { + let mut key = Vec::with_capacity(16); + key.extend_from_slice(&start_block_height.to_be_bytes()); + key.extend_from_slice(&start_block_height.to_be_bytes()); + key + }; + + // Step 2: Proved ascending query from start_key + + let mut query = Query::new(); + query.insert_range_from(start_key..); + + let path_query = PathQuery::new(path, SizedQuery::new(query, limit, None)); + + self.grove_get_proved_path_query( + &path_query, + transaction, + &mut vec![], + &platform_version.drive, + ) + } +} diff --git a/packages/rs-drive/src/drive/saved_block_transactions/fetch_nullifiers/mod.rs b/packages/rs-drive/src/drive/saved_block_transactions/fetch_nullifiers/mod.rs new file mode 100644 index 00000000000..fb7ed9694ae --- /dev/null +++ b/packages/rs-drive/src/drive/saved_block_transactions/fetch_nullifiers/mod.rs @@ -0,0 +1,85 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use grovedb::TransactionArg; +use platform_version::version::PlatformVersion; + +pub use v0::NullifierChangesPerBlock; + +impl Drive { + /// Fetches recent nullifier changes starting from a given block height. + /// + /// # Arguments + /// * `start_height` - The block height to start fetching from + /// * `limit` - Optional maximum number of blocks to return + /// * `transaction` - Optional database transaction + /// * `platform_version` - The platform version + /// + /// # Returns + /// A vector of (block_height, nullifiers) tuples + pub fn fetch_recent_nullifier_changes( + &self, + start_height: u64, + limit: Option, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive + .methods + .saved_block_transactions + .fetch_nullifiers + { + 0 => self.fetch_recent_nullifier_changes_v0( + start_height, + limit, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_recent_nullifier_changes".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Proves recent nullifier changes starting from a given block height. + /// + /// # Arguments + /// * `start_height` - The block height to start from + /// * `limit` - Optional maximum number of blocks to prove + /// * `transaction` - Optional database transaction + /// * `platform_version` - The platform version + /// + /// # Returns + /// A grovedb proof + pub fn prove_recent_nullifier_changes( + &self, + start_height: u64, + limit: Option, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .saved_block_transactions + .fetch_nullifiers + { + 0 => self.prove_recent_nullifier_changes_v0( + start_height, + limit, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_recent_nullifier_changes".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/saved_block_transactions/fetch_nullifiers/v0/mod.rs b/packages/rs-drive/src/drive/saved_block_transactions/fetch_nullifiers/v0/mod.rs new file mode 100644 index 00000000000..c44662fa8a3 --- /dev/null +++ b/packages/rs-drive/src/drive/saved_block_transactions/fetch_nullifiers/v0/mod.rs @@ -0,0 +1,101 @@ +use crate::drive::Drive; +use crate::error::Error; +use dpp::ProtocolError; +use grovedb::query_result_type::QueryResultType; +use grovedb::{Element, PathQuery, Query, SizedQuery, TransactionArg}; +use platform_version::version::PlatformVersion; + +/// Result type for fetched nullifier changes per block +pub type NullifierChangesPerBlock = Vec<(u64, Vec<[u8; 32]>)>; + +impl Drive { + /// Version 0 implementation of fetching nullifier changes from a start height. + /// + /// Retrieves all nullifier change records from `start_height` onwards. + /// Returns a vector of (block_height, nullifiers) tuples. + pub(super) fn fetch_recent_nullifier_changes_v0( + &self, + start_height: u64, + limit: Option, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let path = Self::saved_block_transactions_nullifiers_path_vec(); + + // Create a range query starting from the specified height + let mut query = Query::new(); + query.insert_range_from(start_height.to_be_bytes().to_vec()..); + + let path_query = PathQuery::new(path, SizedQuery::new(query, limit, None)); + + let (results, _) = self.grove_get_path_query( + &path_query, + transaction, + QueryResultType::QueryKeyElementPairResultType, + &mut vec![], + &platform_version.drive, + )?; + + let config = bincode::config::standard() + .with_big_endian() + .with_no_limit(); + + let mut nullifier_changes = Vec::new(); + + for (key, element) in results.to_key_elements() { + // Parse block height from key (8 bytes, big-endian) + let height_bytes: [u8; 8] = key.try_into().map_err(|_| { + Error::Protocol(Box::new(ProtocolError::CorruptedSerialization( + "invalid block height key length".to_string(), + ))) + })?; + let block_height = u64::from_be_bytes(height_bytes); + + // Get the serialized data from the ItemWithSumItem element + let Element::ItemWithSumItem(serialized_data, _, _) = element else { + return Err(Error::Protocol(Box::new( + ProtocolError::CorruptedSerialization( + "expected item with sum item element for nullifiers".to_string(), + ), + ))); + }; + + // Deserialize the nullifier list + let (nullifiers, _): (Vec<[u8; 32]>, usize) = + bincode::decode_from_slice(&serialized_data, config).map_err(|e| { + Error::Protocol(Box::new(ProtocolError::CorruptedSerialization(format!( + "cannot decode nullifiers: {}", + e + )))) + })?; + + nullifier_changes.push((block_height, nullifiers)); + } + + Ok(nullifier_changes) + } + + /// Version 0 implementation for proving nullifier changes from a start height. + pub(super) fn prove_recent_nullifier_changes_v0( + &self, + start_height: u64, + limit: Option, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let path = Self::saved_block_transactions_nullifiers_path_vec(); + + // Create a range query starting from the specified height + let mut query = Query::new(); + query.insert_range_from(start_height.to_be_bytes().to_vec()..); + + let path_query = PathQuery::new(path, SizedQuery::new(query, limit, None)); + + self.grove_get_proved_path_query( + &path_query, + transaction, + &mut vec![], + &platform_version.drive, + ) + } +} diff --git a/packages/rs-drive/src/drive/saved_block_transactions/mod.rs b/packages/rs-drive/src/drive/saved_block_transactions/mod.rs index 5b1a1652331..0e82340f0af 100644 --- a/packages/rs-drive/src/drive/saved_block_transactions/mod.rs +++ b/packages/rs-drive/src/drive/saved_block_transactions/mod.rs @@ -5,6 +5,15 @@ mod fetch_compacted_address_balances; mod queries; mod store_address_balances; +mod cleanup_expired_nullifiers; +/// Compaction of per-block nullifier entries into range-keyed compacted entries +pub mod compact_nullifiers; +mod fetch_compacted_nullifiers; +mod fetch_nullifiers; +mod store_nullifiers; + pub use fetch_address_balances::AddressBalanceChangesPerBlock; pub use fetch_compacted_address_balances::CompactedAddressBalanceChanges; +pub use fetch_compacted_nullifiers::CompactedNullifierChanges; +pub use fetch_nullifiers::NullifierChangesPerBlock; pub use queries::*; diff --git a/packages/rs-drive/src/drive/saved_block_transactions/queries.rs b/packages/rs-drive/src/drive/saved_block_transactions/queries.rs index 2b8556805d8..082056600fb 100644 --- a/packages/rs-drive/src/drive/saved_block_transactions/queries.rs +++ b/packages/rs-drive/src/drive/saved_block_transactions/queries.rs @@ -19,6 +19,24 @@ pub const COMPACTED_ADDRESSES_EXPIRATION_TIME_KEY: &[u8; 1] = b"e"; /// The subtree key for compacted addresses expiration time storage as u8 pub const COMPACTED_ADDRESSES_EXPIRATION_TIME_KEY_U8: u8 = b'e'; +/// The subtree key for nullifiers storage (per-block nullifier lists) +pub const NULLIFIERS_KEY: &[u8; 1] = b"n"; + +/// The subtree key for nullifiers storage as u8 +pub const NULLIFIERS_KEY_U8: u8 = b'n'; + +/// The subtree key for compacted nullifiers storage +pub const COMPACTED_NULLIFIERS_KEY: &[u8; 1] = b"o"; + +/// The subtree key for compacted nullifiers storage as u8 +pub const COMPACTED_NULLIFIERS_KEY_U8: u8 = b'o'; + +/// The subtree key for nullifiers expiration time storage +pub const NULLIFIERS_EXPIRATION_TIME_KEY: &[u8; 1] = b"p"; + +/// The subtree key for nullifiers expiration time storage as u8 +pub const NULLIFIERS_EXPIRATION_TIME_KEY_U8: u8 = b'p'; + impl Drive { /// Path to saved block transactions storage. pub fn saved_block_transactions_path() -> Vec> { @@ -72,4 +90,52 @@ impl Drive { &[COMPACTED_ADDRESSES_EXPIRATION_TIME_KEY_U8], ] } + + /// Path to nullifiers under saved block transactions (Vec version). + pub fn saved_block_transactions_nullifiers_path_vec() -> Vec> { + vec![ + vec![RootTree::SavedBlockTransactions as u8], + vec![NULLIFIERS_KEY_U8], + ] + } + + /// Path to nullifiers under saved block transactions. + pub fn saved_block_transactions_nullifiers_path() -> [&'static [u8]; 2] { + [ + Into::<&[u8; 1]>::into(RootTree::SavedBlockTransactions), + &[NULLIFIERS_KEY_U8], + ] + } + + /// Path to compacted nullifiers under saved block transactions (Vec version). + pub fn saved_compacted_block_transactions_nullifiers_path_vec() -> Vec> { + vec![ + vec![RootTree::SavedBlockTransactions as u8], + vec![COMPACTED_NULLIFIERS_KEY_U8], + ] + } + + /// Path to compacted nullifiers under saved block transactions. + pub fn saved_compacted_block_transactions_nullifiers_path() -> [&'static [u8]; 2] { + [ + Into::<&[u8; 1]>::into(RootTree::SavedBlockTransactions), + &[COMPACTED_NULLIFIERS_KEY_U8], + ] + } + + /// Path to nullifiers expiration time under saved block transactions (Vec version). + pub fn saved_nullifiers_expiration_time_path_vec() -> Vec> { + vec![ + vec![RootTree::SavedBlockTransactions as u8], + vec![NULLIFIERS_EXPIRATION_TIME_KEY_U8], + ] + } + + /// Path to nullifiers expiration time under saved block transactions. + pub fn saved_nullifiers_expiration_time_path() -> [&'static [u8]; 2] { + [ + Into::<&[u8; 1]>::into(RootTree::SavedBlockTransactions), + &[NULLIFIERS_EXPIRATION_TIME_KEY_U8], + ] + } } diff --git a/packages/rs-drive/src/drive/saved_block_transactions/store_nullifiers/mod.rs b/packages/rs-drive/src/drive/saved_block_transactions/store_nullifiers/mod.rs new file mode 100644 index 00000000000..ece1654af51 --- /dev/null +++ b/packages/rs-drive/src/drive/saved_block_transactions/store_nullifiers/mod.rs @@ -0,0 +1,55 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use grovedb::TransactionArg; +use platform_version::version::PlatformVersion; + +impl Drive { + /// Stores nullifiers for a block in the SavedBlockTransactions tree. + /// + /// This method serializes the nullifiers using bincode and stores + /// them keyed by block height. If compaction thresholds are exceeded, it will + /// compact existing entries along with the current block's data and store + /// an expiration time for the compacted entry. + /// + /// # Parameters + /// - `nullifiers`: The nullifiers to store for this block + /// - `block_height`: The height of the block these nullifiers belong to + /// - `block_time_ms`: The block time in milliseconds (used for expiration calculation) + /// - `transaction`: The database transaction + /// - `platform_version`: The platform version + /// + /// # Returns + /// - `Ok(())` on success + /// - `Err(Error)` if the operation fails + pub fn store_nullifiers_for_block( + &self, + nullifiers: &[[u8; 32]], + block_height: u64, + block_time_ms: u64, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version + .drive + .methods + .saved_block_transactions + .store_nullifiers + { + 0 => self.store_nullifiers_for_block_v0( + nullifiers, + block_height, + block_time_ms, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "store_nullifiers_for_block".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/saved_block_transactions/store_nullifiers/v0/mod.rs b/packages/rs-drive/src/drive/saved_block_transactions/store_nullifiers/v0/mod.rs new file mode 100644 index 00000000000..15bcad2a6ef --- /dev/null +++ b/packages/rs-drive/src/drive/saved_block_transactions/store_nullifiers/v0/mod.rs @@ -0,0 +1,154 @@ +use crate::drive::saved_block_transactions::NULLIFIERS_KEY_U8; +use crate::drive::Drive; +use crate::error::Error; +use crate::util::grove_operations::DirectQueryType; +use dpp::ProtocolError; +use grovedb::Element; +use grovedb::TransactionArg; +use grovedb_path::SubtreePath; +use platform_version::version::PlatformVersion; + +impl Drive { + /// Version 0 implementation of storing nullifiers for a block. + /// + /// Serializes the nullifier list using bincode and stores it in the + /// SavedBlockTransactions/Nullifiers count sum tree keyed by block height. + /// Each entry is an ItemWithSumItem where: + /// - The item contains the serialized nullifiers + /// - The sum value is the number of nullifiers + /// + /// Before storing, checks if compaction thresholds are exceeded and triggers + /// compaction if necessary. If compaction occurs, the current block's nullifiers + /// are included in the compaction rather than stored separately. + pub(super) fn store_nullifiers_for_block_v0( + &self, + nullifiers: &[[u8; 32]], + block_height: u64, + block_time_ms: u64, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + // Early return if there are no nullifiers to store + if nullifiers.is_empty() { + return Ok(()); + } + + // Check if compaction is needed - if so, include current nullifiers in compaction + let compacted = self.check_and_compact_nullifiers_if_needed( + nullifiers, + block_height, + block_time_ms, + transaction, + platform_version, + )?; + + // If we compacted, the current nullifiers are already included - don't store separately + if compacted { + return Ok(()); + } + + // Serialize the nullifiers using bincode + let config = bincode::config::standard() + .with_big_endian() + .with_no_limit(); + + let serialized = bincode::encode_to_vec(nullifiers, config).map_err(|e| { + Error::Protocol(Box::new(ProtocolError::CorruptedSerialization(format!( + "cannot encode nullifiers: {}", + e + )))) + })?; + + // The sum value is the number of nullifiers + let entry_count = nullifiers.len() as i64; + + // Store in the SavedBlockTransactions/Nullifiers count sum tree with block height as key + let path: [&[u8]; 2] = Drive::saved_block_transactions_nullifiers_path(); + + // Use block height as the key (big-endian for proper ordering) + let key = block_height.to_be_bytes(); + + // Insert as ItemWithSumItem where: + // - item data = serialized nullifiers + // - sum value = number of nullifiers + let mut drive_operations = vec![]; + self.grove_insert( + path.as_ref().into(), + &key, + Element::new_item_with_sum_item(serialized, entry_count), + transaction, + None, + &mut drive_operations, + &platform_version.drive, + )?; + + // Apply any operations that were generated + self.apply_batch_low_level_drive_operations( + None, + transaction, + drive_operations, + &mut vec![], + &platform_version.drive, + )?; + + Ok(()) + } + + /// Checks if compaction thresholds are exceeded and triggers compaction if needed. + /// If compaction occurs, the provided nullifiers are included in the compaction. + /// + /// Returns true if compaction was performed (meaning the nullifiers were included). + fn check_and_compact_nullifiers_if_needed( + &self, + nullifiers: &[[u8; 32]], + block_height: u64, + block_time_ms: u64, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result { + let saved_block_tx_path = Self::saved_block_transactions_path(); + + // Get the count sum tree element to check current count and sum + let mut drive_operations = vec![]; + let tree_element = self.grove_get_raw( + SubtreePath::from(saved_block_tx_path.as_slice()), + &[NULLIFIERS_KEY_U8], + DirectQueryType::StatefulDirectQuery, + transaction, + &mut drive_operations, + &platform_version.drive, + )?; + + if let Some(Element::CountSumTree(_, count, sum, _)) = tree_element { + let max_blocks = platform_version + .drive + .methods + .saved_block_transactions + .max_blocks_before_nullifier_compaction as u64; + let max_nullifiers = platform_version + .drive + .methods + .saved_block_transactions + .max_nullifiers_before_compaction as i64; + + // Check if either threshold would be exceeded after adding the current block + // count + 1 for the new block, sum + current nullifiers count + let new_count = count + 1; + let new_sum = sum + nullifiers.len() as i64; + + if new_count >= max_blocks || new_sum >= max_nullifiers { + // Trigger compaction, including the current block's nullifiers + self.compact_nullifiers_with_current_block( + nullifiers, + block_height, + block_time_ms, + transaction, + platform_version, + )?; + return Ok(true); + } + } + + Ok(false) + } +} diff --git a/packages/rs-drive/src/drive/shielded/mod.rs b/packages/rs-drive/src/drive/shielded/mod.rs index 5b1d638eb1f..1515f442dd6 100644 --- a/packages/rs-drive/src/drive/shielded/mod.rs +++ b/packages/rs-drive/src/drive/shielded/mod.rs @@ -5,3 +5,7 @@ pub mod paths; /// Estimation costs for shielded pool operations #[cfg(feature = "server")] pub(crate) mod estimated_costs; + +/// Prove methods for shielded pool queries +#[cfg(feature = "server")] +pub mod prove; diff --git a/packages/rs-drive/src/drive/shielded/paths.rs b/packages/rs-drive/src/drive/shielded/paths.rs index dabe5d37eee..5d4be51c73d 100644 --- a/packages/rs-drive/src/drive/shielded/paths.rs +++ b/packages/rs-drive/src/drive/shielded/paths.rs @@ -87,3 +87,28 @@ pub fn shielded_credit_pool_anchors_path_vec() -> Vec> { vec![SHIELDED_ANCHORS_IN_POOL_KEY], ] } + +/// Resolves the nullifiers path based on pool type. +/// +/// Pool types: +/// - 0: Main credit shielded pool → `[AddressBalances, "s", [2]]` +/// - 1: Main token shielded pool (not yet implemented) +/// - 2: Individual token shielded pool (not yet implemented, requires pool_identifier) +pub fn nullifiers_path_for_pool( + pool_type: u32, + _pool_identifier: Option<&[u8]>, +) -> Result>, crate::error::Error> { + use crate::error::drive::DriveError; + use crate::error::Error; + + match pool_type { + 0 => Ok(shielded_credit_pool_nullifiers_path_vec()), + 1 | 2 => Err(Error::Drive(DriveError::NotSupported( + "Token shielded pools not yet implemented", + ))), + _ => Err(Error::Drive(DriveError::InvalidInput(format!( + "Unknown pool type: {}", + pool_type + )))), + } +} diff --git a/packages/rs-drive/src/drive/shielded/prove/mod.rs b/packages/rs-drive/src/drive/shielded/prove/mod.rs new file mode 100644 index 00000000000..c979a8d57c5 --- /dev/null +++ b/packages/rs-drive/src/drive/shielded/prove/mod.rs @@ -0,0 +1,5 @@ +/// Proves nullifiers using a trunk chunk query. +pub mod prove_nullifiers_trunk_query; + +/// Proves nullifiers using a branch chunk query. +pub mod prove_nullifiers_branch_query; diff --git a/packages/rs-drive/src/drive/shielded/prove/prove_nullifiers_branch_query/mod.rs b/packages/rs-drive/src/drive/shielded/prove/prove_nullifiers_branch_query/mod.rs new file mode 100644 index 00000000000..a393eb3639e --- /dev/null +++ b/packages/rs-drive/src/drive/shielded/prove/prove_nullifiers_branch_query/mod.rs @@ -0,0 +1,93 @@ +//! Proves nullifiers using a branch chunk query. + +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use dpp::prelude::BlockHeight; +use platform_version::version::PlatformVersion; + +impl Drive { + /// Proves nullifiers using a branch chunk query. + /// + /// This function generates a branch chunk proof for navigating deeper into + /// the nullifiers tree after an initial trunk query. + /// + /// # Parameters + /// - `pool_type`: The shielded pool type (0 = credit, 1 = main token, 2 = individual token). + /// - `pool_identifier`: Optional 32-byte identifier for individual token pools (pool_type=2). + /// - `key`: The key to navigate to in the nullifiers tree before extracting the branch. + /// - `depth`: The depth of the branch to return from the key. + /// - `checkpoint_height`: Block height of the checkpoint to use for consistency. + /// - `platform_version`: The version of the platform that determines the correct method version. + /// + /// # Returns + /// - `Ok(Vec)`: The serialized proof bytes. + /// - `Err(Error)`: If an error occurs during the proof generation. + pub fn prove_nullifiers_branch_query( + &self, + pool_type: u32, + pool_identifier: Option>, + key: Vec, + depth: u8, + checkpoint_height: BlockHeight, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .shielded + .prove_nullifiers_branch_query + { + 0 => self.prove_nullifiers_branch_query_v0( + pool_type, + pool_identifier, + key, + depth, + checkpoint_height, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_nullifiers_branch_query".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Proves nullifiers using a branch chunk query and tracks operations. + pub fn prove_nullifiers_branch_query_operations( + &self, + pool_type: u32, + pool_identifier: Option>, + key: Vec, + depth: u8, + checkpoint_height: BlockHeight, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .shielded + .prove_nullifiers_branch_query + { + 0 => self.prove_nullifiers_branch_query_operations_v0( + pool_type, + pool_identifier, + key, + depth, + checkpoint_height, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_nullifiers_branch_query_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/shielded/prove/prove_nullifiers_branch_query/v0/mod.rs b/packages/rs-drive/src/drive/shielded/prove/prove_nullifiers_branch_query/v0/mod.rs new file mode 100644 index 00000000000..2712a8f63b8 --- /dev/null +++ b/packages/rs-drive/src/drive/shielded/prove/prove_nullifiers_branch_query/v0/mod.rs @@ -0,0 +1,70 @@ +use crate::drive::shielded::paths::nullifiers_path_for_pool; +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::GroveDBToUse; +use dpp::prelude::BlockHeight; +use dpp::version::PlatformVersion; +use grovedb::PathBranchChunkQuery; + +impl Drive { + pub(super) fn prove_nullifiers_branch_query_v0( + &self, + pool_type: u32, + pool_identifier: Option>, + key: Vec, + depth: u8, + checkpoint_height: BlockHeight, + platform_version: &PlatformVersion, + ) -> Result, Error> { + self.prove_nullifiers_branch_query_operations_v0( + pool_type, + pool_identifier, + key, + depth, + checkpoint_height, + &mut vec![], + platform_version, + ) + } + + pub(super) fn prove_nullifiers_branch_query_operations_v0( + &self, + pool_type: u32, + pool_identifier: Option>, + key: Vec, + depth: u8, + checkpoint_height: BlockHeight, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let min_depth = platform_version + .drive + .methods + .shielded + .nullifiers_query_min_depth; + let max_depth = platform_version + .drive + .methods + .shielded + .nullifiers_query_max_depth; + + if depth < min_depth || depth > max_depth { + return Err(Error::Drive(DriveError::InvalidInput(format!( + "depth {} is outside the allowed range [{}, {}]", + depth, min_depth, max_depth + )))); + } + + let path = nullifiers_path_for_pool(pool_type, pool_identifier.as_deref())?; + let query = PathBranchChunkQuery { path, key, depth }; + + self.grove_get_proved_branch_chunk_query( + &query, + GroveDBToUse::Checkpoint(checkpoint_height), + drive_operations, + &platform_version.drive, + ) + } +} diff --git a/packages/rs-drive/src/drive/shielded/prove/prove_nullifiers_trunk_query/mod.rs b/packages/rs-drive/src/drive/shielded/prove/prove_nullifiers_trunk_query/mod.rs new file mode 100644 index 00000000000..bc0eff645d9 --- /dev/null +++ b/packages/rs-drive/src/drive/shielded/prove/prove_nullifiers_trunk_query/mod.rs @@ -0,0 +1,74 @@ +//! Proves nullifiers using a trunk chunk query. + +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use platform_version::version::PlatformVersion; + +impl Drive { + /// Proves nullifiers using a trunk chunk query. + /// + /// This function generates a trunk chunk proof for the nullifiers tree of a shielded pool, + /// useful for retrieving the initial structure of the tree up to the configured depth. + /// + /// # Parameters + /// - `pool_type`: The shielded pool type (0 = credit, 1 = main token, 2 = individual token). + /// - `pool_identifier`: Optional 32-byte identifier for individual token pools (pool_type=2). + /// - `platform_version`: The version of the platform that determines the correct method version + /// and the trunk query depth. + /// + /// # Returns + /// - `Ok(Vec)`: The serialized proof bytes. + /// - `Err(Error)`: If an error occurs during the proof generation. + pub fn prove_nullifiers_trunk_query( + &self, + pool_type: u32, + pool_identifier: Option>, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .shielded + .prove_nullifiers_trunk_query + { + 0 => self.prove_nullifiers_trunk_query_v0(pool_type, pool_identifier, platform_version), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_nullifiers_trunk_query".to_string(), + known_versions: vec![0], + received: version, + })), + } + } + + /// Proves nullifiers using a trunk chunk query and tracks operations. + pub fn prove_nullifiers_trunk_query_operations( + &self, + pool_type: u32, + pool_identifier: Option>, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive + .methods + .shielded + .prove_nullifiers_trunk_query + { + 0 => self.prove_nullifiers_trunk_query_operations_v0( + pool_type, + pool_identifier, + drive_operations, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "prove_nullifiers_trunk_query_operations".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/shielded/prove/prove_nullifiers_trunk_query/v0/mod.rs b/packages/rs-drive/src/drive/shielded/prove/prove_nullifiers_trunk_query/v0/mod.rs new file mode 100644 index 00000000000..0b632a78a10 --- /dev/null +++ b/packages/rs-drive/src/drive/shielded/prove/prove_nullifiers_trunk_query/v0/mod.rs @@ -0,0 +1,56 @@ +use crate::drive::shielded::paths::nullifiers_path_for_pool; +use crate::drive::Drive; +use crate::error::Error; +use crate::fees::op::LowLevelDriveOperation; +use crate::util::grove_operations::GroveDBToUse; +use dpp::version::PlatformVersion; +use grovedb::PathTrunkChunkQuery; + +impl Drive { + pub(super) fn prove_nullifiers_trunk_query_v0( + &self, + pool_type: u32, + pool_identifier: Option>, + platform_version: &PlatformVersion, + ) -> Result, Error> { + self.prove_nullifiers_trunk_query_operations_v0( + pool_type, + pool_identifier, + &mut vec![], + platform_version, + ) + } + + pub(super) fn prove_nullifiers_trunk_query_operations_v0( + &self, + pool_type: u32, + pool_identifier: Option>, + drive_operations: &mut Vec, + platform_version: &PlatformVersion, + ) -> Result, Error> { + let path = nullifiers_path_for_pool(pool_type, pool_identifier.as_deref())?; + let min_depth = platform_version + .drive + .methods + .shielded + .nullifiers_query_min_depth; + let max_depth = platform_version + .drive + .methods + .shielded + .nullifiers_query_max_depth; + + let query = PathTrunkChunkQuery { + path, + min_depth: Some(min_depth), + max_depth, + }; + + self.grove_get_proved_trunk_chunk_query( + &query, + GroveDBToUse::LatestCheckpoint, + drive_operations, + &platform_version.drive, + ) + } +} diff --git a/packages/rs-drive/src/verify/shielded/mod.rs b/packages/rs-drive/src/verify/shielded/mod.rs index f7343add55f..1f9c6b31cad 100644 --- a/packages/rs-drive/src/verify/shielded/mod.rs +++ b/packages/rs-drive/src/verify/shielded/mod.rs @@ -1,3 +1,11 @@ +/// Module for verifying compacted nullifier changes +pub mod verify_compacted_nullifier_changes; +/// Module for verifying nullifiers branch chunk queries +pub mod verify_nullifiers_branch_query; +/// Module for verifying nullifiers trunk chunk queries +pub mod verify_nullifiers_trunk_query; +/// Module for verifying recent nullifier changes +pub mod verify_recent_nullifier_changes; /// Module for verifying shielded anchors pub mod verify_shielded_anchors; /// Module for verifying shielded encrypted notes diff --git a/packages/rs-drive/src/verify/shielded/verify_compacted_nullifier_changes/mod.rs b/packages/rs-drive/src/verify/shielded/verify_compacted_nullifier_changes/mod.rs new file mode 100644 index 00000000000..01f5baa98a7 --- /dev/null +++ b/packages/rs-drive/src/verify/shielded/verify_compacted_nullifier_changes/mod.rs @@ -0,0 +1,56 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::verify::RootHash; +use dpp::version::PlatformVersion; + +/// Result type for verified compacted nullifier changes +/// Each entry is (start_block, end_block, nullifiers) +pub type VerifiedCompactedNullifierChanges = Vec<(u64, u64, Vec<[u8; 32]>)>; + +impl Drive { + /// Verifies the proof of compacted nullifier changes starting from a given block height. + /// + /// This method validates and extracts compacted nullifier changes from the provided proof. + /// Compacted entries represent concatenated data from multiple blocks. + /// + /// # Arguments + /// - `proof`: A byte slice containing the cryptographic proof for the compacted nullifier changes. + /// - `start_block_height`: The block height to start verifying from. + /// - `limit`: Optional maximum number of compacted entries to verify. + /// - `platform_version`: A reference to the platform version. + /// + /// # Returns + /// - `Ok((RootHash, VerifiedCompactedNullifierChanges))`: On success, returns: + /// - `RootHash`: The root hash of the Merkle tree. + /// - `VerifiedCompactedNullifierChanges`: Vector of (start_block, end_block, nullifiers) tuples. + /// - `Err(Error)`: If verification fails. + pub fn verify_compacted_nullifier_changes( + proof: &[u8], + start_block_height: u64, + limit: Option, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, VerifiedCompactedNullifierChanges), Error> { + match platform_version + .drive + .methods + .verify + .shielded + .verify_compacted_nullifier_changes + { + 0 => Self::verify_compacted_nullifier_changes_v0( + proof, + start_block_height, + limit, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_compacted_nullifier_changes".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/verify/shielded/verify_compacted_nullifier_changes/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_compacted_nullifier_changes/v0/mod.rs new file mode 100644 index 00000000000..371c52588b9 --- /dev/null +++ b/packages/rs-drive/src/verify/shielded/verify_compacted_nullifier_changes/v0/mod.rs @@ -0,0 +1,207 @@ +use crate::drive::Drive; +use crate::drive::RootTree; +use crate::error::proof::ProofError; +use crate::error::Error; +use crate::verify::RootHash; + +/// The subtree key for compacted nullifiers storage as u8 +const COMPACTED_NULLIFIERS_KEY_U8: u8 = b'o'; +use grovedb::operations::proof::{GroveDBProof, ProofBytes}; +use grovedb::{ + GroveDb, MerkProofDecoder, MerkProofNode, MerkProofOp, PathQuery, Query, SizedQuery, +}; +use platform_version::version::PlatformVersion; + +use super::VerifiedCompactedNullifierChanges; + +/// Extract KV entries from merk proof bytes using the proper decoder. +#[allow(clippy::type_complexity)] +fn extract_kv_entries_from_merk_proof(merk_proof: &[u8]) -> Result, Vec)>, Error> { + let mut entries = Vec::new(); + + let decoder = MerkProofDecoder::new(merk_proof); + + for op in decoder { + match op { + Ok(MerkProofOp::Push(MerkProofNode::KV(key, value))) + | Ok(MerkProofOp::PushInverted(MerkProofNode::KV(key, value))) => { + entries.push((key, value)); + } + Err(e) => { + tracing::error!(%e, "merk proof decode error"); + return Err(Error::Proof(ProofError::CorruptedProof(format!( + "failed to decode merk proof op: {}", + e + )))); + } + _ => {} + } + } + + Ok(entries) +} + +impl Drive { + /// Verifies compacted nullifier changes proof. + /// + /// This verification works by: + /// 1. Decoding the GroveDBProof structure + /// 2. Navigating to the compacted nullifiers layer ('o') + /// 3. Extracting KV entries from the merk proof + /// 4. Filtering entries where the key range contains start_block_height + /// 5. Verifying the root hash using a subset query + pub(super) fn verify_compacted_nullifier_changes_v0( + proof: &[u8], + start_block_height: u64, + limit: Option, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, VerifiedCompactedNullifierChanges), Error> { + let bincode_config = bincode::config::standard() + .with_big_endian() + .with_no_limit(); + + // Decode the GroveDBProof to navigate its structure + let grovedb_proof: GroveDBProof = bincode::decode_from_slice(proof, bincode_config) + .map(|(p, _)| p) + .map_err(|e| { + Error::Proof(ProofError::CorruptedProof(format!( + "cannot decode GroveDBProof: {}", + e + ))) + })?; + + // Navigate to the compacted nullifiers layer + // Path: SavedBlockTransactions ('$' = 0x24) -> CompactedNullifiers ('o' = 0x6f) + let saved_block_key = vec![RootTree::SavedBlockTransactions as u8]; + let compacted_key = vec![COMPACTED_NULLIFIERS_KEY_U8]; + + // Extract KV entries from the compacted layer's merk proof to find + // if there's a containing range for start_block_height. + // V0 and V1 proofs have different layer types (MerkOnlyLayerProof vs LayerProof), + // so we handle them separately. + let kv_entries = match &grovedb_proof { + GroveDBProof::V0(v0) => { + let compacted_layer = v0 + .root_layer + .lower_layers + .get(&saved_block_key) + .and_then(|layer| layer.lower_layers.get(&compacted_key)); + compacted_layer + .map(|layer| extract_kv_entries_from_merk_proof(&layer.merk_proof)) + .transpose()? + .unwrap_or_default() + } + GroveDBProof::V1(v1) => { + let compacted_layer = v1 + .root_layer + .lower_layers + .get(&saved_block_key) + .and_then(|layer| layer.lower_layers.get(&compacted_key)); + compacted_layer + .map(|layer| match &layer.merk_proof { + ProofBytes::Merk(bytes) => extract_kv_entries_from_merk_proof(bytes), + _ => Ok(vec![]), + }) + .transpose()? + .unwrap_or_default() + } + }; + + // Look for a KV entry where the range contains start_block_height + // Keys are 16 bytes: (start_block, end_block), both big-endian + let containing_key = kv_entries.iter().find_map(|(key, _)| { + if key.len() != 16 { + return None; + } + let range_start = u64::from_be_bytes( + key[0..8] + .try_into() + .expect("slice is exactly 8 bytes from a 16-byte key"), + ); + let range_end = u64::from_be_bytes( + key[8..16] + .try_into() + .expect("slice is exactly 8 bytes from a 16-byte key"), + ); + + // Check if this range contains start_block_height + if range_start <= start_block_height && start_block_height <= range_end { + Some(key.clone()) + } else { + None + } + }); + + // Determine the start_key for the query + // Use the containing range's key if found, otherwise (start_block_height, start_block_height) + let start_key = containing_key.unwrap_or_else(|| { + let mut key = Vec::with_capacity(16); + key.extend_from_slice(&start_block_height.to_be_bytes()); + key.extend_from_slice(&start_block_height.to_be_bytes()); + key + }); + + // Verify the proof and get results using subset query + let path = vec![ + vec![RootTree::SavedBlockTransactions as u8], + vec![COMPACTED_NULLIFIERS_KEY_U8], + ]; + + let mut query = Query::new(); + query.insert_range_from(start_key..); + + let path_query = PathQuery::new(path, SizedQuery::new(query, limit, None)); + + let (root_hash, proved_key_values) = GroveDb::verify_subset_query( + proof, + &path_query, + &platform_version.drive.grove_version, + )?; + + // Process the verified results + let mut compacted_changes = Vec::new(); + + for (_path, key, maybe_element) in proved_key_values { + let Some(element) = maybe_element else { + continue; + }; + + if key.len() != 16 { + return Err(Error::Proof(ProofError::CorruptedProof( + "invalid compacted block key length, expected 16 bytes".to_string(), + ))); + } + + let range_start = u64::from_be_bytes( + key[0..8] + .try_into() + .expect("slice is exactly 8 bytes from a 16-byte key"), + ); + let range_end = u64::from_be_bytes( + key[8..16] + .try_into() + .expect("slice is exactly 8 bytes from a 16-byte key"), + ); + + // Get the serialized data from the Item element + let grovedb::Element::Item(serialized_data, _) = element else { + return Err(Error::Proof(ProofError::CorruptedProof( + "expected item element for compacted nullifiers".to_string(), + ))); + }; + + // Deserialize the nullifier list + let (nullifiers, _): (Vec<[u8; 32]>, usize) = + bincode::decode_from_slice(&serialized_data, bincode_config).map_err(|e| { + Error::Proof(ProofError::CorruptedProof(format!( + "cannot decode compacted nullifiers: {}", + e + ))) + })?; + + compacted_changes.push((range_start, range_end, nullifiers)); + } + + Ok((root_hash, compacted_changes)) + } +} diff --git a/packages/rs-drive/src/verify/shielded/verify_nullifiers_branch_query/mod.rs b/packages/rs-drive/src/verify/shielded/verify_nullifiers_branch_query/mod.rs new file mode 100644 index 00000000000..dd2b56fc9fb --- /dev/null +++ b/packages/rs-drive/src/verify/shielded/verify_nullifiers_branch_query/mod.rs @@ -0,0 +1,58 @@ +//! Module for verifying nullifiers branch chunk queries. + +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use grovedb::GroveBranchQueryResult; +use platform_version::version::PlatformVersion; + +impl Drive { + /// Verifies a branch chunk proof for the nullifiers tree of a shielded pool. + /// + /// # Arguments + /// - `proof`: A byte slice containing the serialized branch chunk proof. + /// - `pool_type`: The shielded pool type (0 = credit, 1 = main token, 2 = individual token). + /// - `pool_identifier`: Optional 32-byte identifier for individual token pools. + /// - `key`: The key that was navigated to in the tree. + /// - `depth`: The depth of the branch that was returned. + /// - `expected_root_hash`: The expected root hash from the parent trunk/branch proof. + /// - `platform_version`: A reference to the platform version. + /// + /// # Returns + /// - `Ok(GroveBranchQueryResult)`: The verified branch query result. + /// - `Err(Error)`: If verification fails. + pub fn verify_nullifiers_branch_query( + proof: &[u8], + pool_type: u32, + pool_identifier: Option<&[u8]>, + key: Vec, + depth: u8, + expected_root_hash: [u8; 32], + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive + .methods + .verify + .shielded + .verify_nullifiers_branch_query + { + 0 => Self::verify_nullifiers_branch_query_v0( + proof, + pool_type, + pool_identifier, + key, + depth, + expected_root_hash, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_nullifiers_branch_query".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/verify/shielded/verify_nullifiers_branch_query/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_nullifiers_branch_query/v0/mod.rs new file mode 100644 index 00000000000..3bf881ce221 --- /dev/null +++ b/packages/rs-drive/src/verify/shielded/verify_nullifiers_branch_query/v0/mod.rs @@ -0,0 +1,48 @@ +use crate::drive::shielded::paths::nullifiers_path_for_pool; +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use grovedb::{GroveBranchQueryResult, GroveDb, PathBranchChunkQuery}; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn verify_nullifiers_branch_query_v0( + proof: &[u8], + pool_type: u32, + pool_identifier: Option<&[u8]>, + key: Vec, + depth: u8, + expected_root_hash: [u8; 32], + platform_version: &PlatformVersion, + ) -> Result { + let min_depth = platform_version + .drive + .methods + .shielded + .nullifiers_query_min_depth; + let max_depth = platform_version + .drive + .methods + .shielded + .nullifiers_query_max_depth; + + if depth < min_depth || depth > max_depth { + return Err(Error::Drive(DriveError::InvalidInput(format!( + "depth {} is outside the allowed range [{}, {}]", + depth, min_depth, max_depth + )))); + } + + let path = nullifiers_path_for_pool(pool_type, pool_identifier)?; + let query = PathBranchChunkQuery { path, key, depth }; + + let result = GroveDb::verify_branch_chunk_proof( + proof, + &query, + expected_root_hash, + &platform_version.drive.grove_version, + )?; + + Ok(result) + } +} diff --git a/packages/rs-drive/src/verify/shielded/verify_nullifiers_trunk_query/mod.rs b/packages/rs-drive/src/verify/shielded/verify_nullifiers_trunk_query/mod.rs new file mode 100644 index 00000000000..1e4aa59717e --- /dev/null +++ b/packages/rs-drive/src/verify/shielded/verify_nullifiers_trunk_query/mod.rs @@ -0,0 +1,50 @@ +//! Module for verifying nullifiers trunk chunk queries. + +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::verify::RootHash; +use grovedb::GroveTrunkQueryResult; +use platform_version::version::PlatformVersion; + +impl Drive { + /// Verifies a trunk chunk proof for the nullifiers tree of a shielded pool. + /// + /// # Arguments + /// - `proof`: A byte slice containing the serialized trunk chunk proof. + /// - `pool_type`: The shielded pool type (0 = credit, 1 = main token, 2 = individual token). + /// - `pool_identifier`: Optional 32-byte identifier for individual token pools. + /// - `platform_version`: A reference to the platform version. + /// + /// # Returns + /// - `Ok((RootHash, GroveTrunkQueryResult))`: The root hash and verified trunk result. + /// - `Err(Error)`: If verification fails. + pub fn verify_nullifiers_trunk_query( + proof: &[u8], + pool_type: u32, + pool_identifier: Option<&[u8]>, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, GroveTrunkQueryResult), Error> { + match platform_version + .drive + .methods + .verify + .shielded + .verify_nullifiers_trunk_query + { + 0 => Self::verify_nullifiers_trunk_query_v0( + proof, + pool_type, + pool_identifier, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_nullifiers_trunk_query".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/verify/shielded/verify_nullifiers_trunk_query/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_nullifiers_trunk_query/v0/mod.rs new file mode 100644 index 00000000000..fdae3be8508 --- /dev/null +++ b/packages/rs-drive/src/verify/shielded/verify_nullifiers_trunk_query/v0/mod.rs @@ -0,0 +1,36 @@ +use crate::drive::shielded::paths::nullifiers_path_for_pool; +use crate::drive::Drive; +use crate::error::Error; +use crate::verify::RootHash; +use grovedb::{GroveDb, GroveTrunkQueryResult, PathTrunkChunkQuery}; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn verify_nullifiers_trunk_query_v0( + proof: &[u8], + pool_type: u32, + pool_identifier: Option<&[u8]>, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, GroveTrunkQueryResult), Error> { + let path = nullifiers_path_for_pool(pool_type, pool_identifier)?; + let max_depth = platform_version + .drive + .methods + .shielded + .nullifiers_query_max_depth; + + let query = PathTrunkChunkQuery { + path, + max_depth, + min_depth: None, + }; + + let (root_hash, result) = GroveDb::verify_trunk_chunk_proof( + proof, + &query, + &platform_version.drive.grove_version, + )?; + + Ok((root_hash, result)) + } +} diff --git a/packages/rs-drive/src/verify/shielded/verify_recent_nullifier_changes/mod.rs b/packages/rs-drive/src/verify/shielded/verify_recent_nullifier_changes/mod.rs new file mode 100644 index 00000000000..72ca1383e87 --- /dev/null +++ b/packages/rs-drive/src/verify/shielded/verify_recent_nullifier_changes/mod.rs @@ -0,0 +1,57 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use crate::verify::RootHash; +use dpp::version::PlatformVersion; + +/// Result type for verified nullifier changes per block +pub type VerifiedNullifierChangesPerBlock = Vec<(u64, Vec<[u8; 32]>)>; + +impl Drive { + /// Verifies the proof of recent nullifier changes starting from a given block height. + /// + /// This method validates and extracts nullifier changes from the provided proof. + /// + /// # Arguments + /// - `proof`: A byte slice containing the cryptographic proof for the nullifier changes. + /// - `start_block_height`: The block height to start verifying from. + /// - `limit`: Optional maximum number of blocks to verify. + /// - `verify_subset_of_proof`: A boolean flag indicating whether to verify only a subset of the proof. + /// - `platform_version`: A reference to the platform version. + /// + /// # Returns + /// - `Ok((RootHash, VerifiedNullifierChangesPerBlock))`: On success, returns: + /// - `RootHash`: The root hash of the Merkle tree. + /// - `VerifiedNullifierChangesPerBlock`: Vector of (block_height, nullifiers) tuples. + /// - `Err(Error)`: If verification fails. + pub fn verify_recent_nullifier_changes( + proof: &[u8], + start_block_height: u64, + limit: Option, + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, VerifiedNullifierChangesPerBlock), Error> { + match platform_version + .drive + .methods + .verify + .shielded + .verify_recent_nullifier_changes + { + 0 => Self::verify_recent_nullifier_changes_v0( + proof, + start_block_height, + limit, + verify_subset_of_proof, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_recent_nullifier_changes".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/verify/shielded/verify_recent_nullifier_changes/v0/mod.rs b/packages/rs-drive/src/verify/shielded/verify_recent_nullifier_changes/v0/mod.rs new file mode 100644 index 00000000000..e8da02c8a2b --- /dev/null +++ b/packages/rs-drive/src/verify/shielded/verify_recent_nullifier_changes/v0/mod.rs @@ -0,0 +1,83 @@ +use crate::drive::Drive; +use crate::drive::RootTree; +use crate::error::proof::ProofError; +use crate::error::Error; +use crate::verify::RootHash; + +/// The subtree key for nullifiers storage as u8 +const NULLIFIERS_KEY_U8: u8 = b'n'; +use grovedb::{Element, GroveDb, PathQuery, Query, SizedQuery}; +use platform_version::version::PlatformVersion; + +use super::VerifiedNullifierChangesPerBlock; + +impl Drive { + /// Verifies recent nullifier changes proof. + /// + /// Uses the same query as the prove function: a simple range query + /// starting from start_block_height. + pub(super) fn verify_recent_nullifier_changes_v0( + proof: &[u8], + start_block_height: u64, + limit: Option, + verify_subset_of_proof: bool, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, VerifiedNullifierChangesPerBlock), Error> { + let path = vec![ + vec![RootTree::SavedBlockTransactions as u8], + vec![NULLIFIERS_KEY_U8], + ]; + + let config = bincode::config::standard() + .with_big_endian() + .with_no_limit(); + + // Create the same range query as the prove function + let mut query = Query::new(); + query.insert_range_from(start_block_height.to_be_bytes().to_vec()..); + + let path_query = PathQuery::new(path, SizedQuery::new(query, limit, None)); + + let (root_hash, proved_key_values) = if verify_subset_of_proof { + GroveDb::verify_subset_query(proof, &path_query, &platform_version.drive.grove_version)? + } else { + GroveDb::verify_query(proof, &path_query, &platform_version.drive.grove_version)? + }; + + let mut nullifier_changes = Vec::new(); + + for (_path, key, maybe_element) in proved_key_values { + let Some(element) = maybe_element else { + continue; + }; + + // Parse block height from key (8 bytes, big-endian) + let height_bytes: [u8; 8] = key.try_into().map_err(|_| { + Error::Proof(ProofError::CorruptedProof( + "invalid block height key length".to_string(), + )) + })?; + let block_height = u64::from_be_bytes(height_bytes); + + // Get the serialized data from the ItemWithSumItem element + let Element::ItemWithSumItem(serialized_data, _, _) = element else { + return Err(Error::Proof(ProofError::CorruptedProof( + "expected item with sum item element for nullifiers".to_string(), + ))); + }; + + // Deserialize the nullifier list + let (nullifiers, _): (Vec<[u8; 32]>, usize) = + bincode::decode_from_slice(&serialized_data, config).map_err(|e| { + Error::Proof(ProofError::CorruptedProof(format!( + "cannot decode nullifiers: {}", + e + ))) + })?; + + nullifier_changes.push((block_height, nullifiers)); + } + + Ok((root_hash, nullifier_changes)) + } +} diff --git a/packages/rs-platform-version/Cargo.toml b/packages/rs-platform-version/Cargo.toml index 55839797ad2..bd8b8cad15c 100644 --- a/packages/rs-platform-version/Cargo.toml +++ b/packages/rs-platform-version/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT" thiserror = { version = "2.0.12" } bincode = { version = "=2.0.1" } versioned-feature-core = { git = "https://github.com/dashpay/versioned-feature-core", version = "1.0.0" } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8" } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444" } [features] mock-versions = [] 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 ea5c2dc17e7..407894c714a 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 @@ -177,4 +177,6 @@ pub struct DriveAbciStateTransitionProcessingMethodVersions { pub validate_fees_of_event: FeatureVersion, pub store_address_balances_to_recent_block_storage: OptionalFeatureVersion, pub cleanup_recent_block_storage_address_balances: OptionalFeatureVersion, + pub store_nullifiers_to_recent_block_storage: OptionalFeatureVersion, + pub cleanup_recent_block_storage_nullifiers: OptionalFeatureVersion, } diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v1.rs index 652a29ca66f..1ae899885c7 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v1.rs @@ -107,6 +107,8 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V1: DriveAbciMethodVersions = DriveAbciMeth validate_fees_of_event: 0, store_address_balances_to_recent_block_storage: None, cleanup_recent_block_storage_address_balances: None, + store_nullifiers_to_recent_block_storage: None, + cleanup_recent_block_storage_nullifiers: None, }, epoch: DriveAbciEpochMethodVersions { gather_epoch_info: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v2.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v2.rs index ca20542a937..61c77c3d6e5 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v2.rs @@ -108,6 +108,8 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V2: DriveAbciMethodVersions = DriveAbciMeth validate_fees_of_event: 0, store_address_balances_to_recent_block_storage: None, cleanup_recent_block_storage_address_balances: None, + store_nullifiers_to_recent_block_storage: None, + cleanup_recent_block_storage_nullifiers: None, }, epoch: DriveAbciEpochMethodVersions { gather_epoch_info: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v3.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v3.rs index 40d6b8d3a17..ef5a11f866d 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v3.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v3.rs @@ -107,6 +107,8 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V3: DriveAbciMethodVersions = DriveAbciMeth validate_fees_of_event: 0, store_address_balances_to_recent_block_storage: None, cleanup_recent_block_storage_address_balances: None, + store_nullifiers_to_recent_block_storage: None, + cleanup_recent_block_storage_nullifiers: None, }, epoch: DriveAbciEpochMethodVersions { gather_epoch_info: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v4.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v4.rs index 87e70731216..2b31351c7f2 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v4.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v4.rs @@ -107,6 +107,8 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V4: DriveAbciMethodVersions = DriveAbciMeth validate_fees_of_event: 0, store_address_balances_to_recent_block_storage: None, cleanup_recent_block_storage_address_balances: None, + store_nullifiers_to_recent_block_storage: None, + cleanup_recent_block_storage_nullifiers: None, }, epoch: DriveAbciEpochMethodVersions { gather_epoch_info: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v5.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v5.rs index faf90d1b788..42db9291958 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v5.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v5.rs @@ -111,6 +111,8 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V5: DriveAbciMethodVersions = DriveAbciMeth validate_fees_of_event: 0, store_address_balances_to_recent_block_storage: None, cleanup_recent_block_storage_address_balances: None, + store_nullifiers_to_recent_block_storage: None, + cleanup_recent_block_storage_nullifiers: None, }, epoch: DriveAbciEpochMethodVersions { gather_epoch_info: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v6.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v6.rs index ed161b042c7..72b37d3b7c4 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v6.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v6.rs @@ -109,6 +109,8 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V6: DriveAbciMethodVersions = DriveAbciMeth validate_fees_of_event: 0, store_address_balances_to_recent_block_storage: None, cleanup_recent_block_storage_address_balances: None, + store_nullifiers_to_recent_block_storage: None, + cleanup_recent_block_storage_nullifiers: None, }, epoch: DriveAbciEpochMethodVersions { gather_epoch_info: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v7.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v7.rs index 718555743ab..daab10e1d6c 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v7.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v7.rs @@ -108,6 +108,8 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V7: DriveAbciMethodVersions = DriveAbciMeth validate_fees_of_event: 0, store_address_balances_to_recent_block_storage: Some(0), // changed cleanup_recent_block_storage_address_balances: Some(0), // cleanup enabled when store is enabled + store_nullifiers_to_recent_block_storage: Some(0), + cleanup_recent_block_storage_nullifiers: Some(0), }, epoch: DriveAbciEpochMethodVersions { gather_epoch_info: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs index 2cdeb9299c5..20b93183e74 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/mod.rs @@ -99,6 +99,10 @@ pub struct DriveAbciQueryShieldedVersions { pub anchors: FeatureVersionBounds, pub pool_state: FeatureVersionBounds, pub nullifiers: FeatureVersionBounds, + pub nullifiers_trunk_state: FeatureVersionBounds, + pub nullifiers_branch_state: FeatureVersionBounds, + pub recent_nullifier_changes: FeatureVersionBounds, + pub recent_compacted_nullifier_changes: FeatureVersionBounds, /// Maximum number of encrypted notes returned per query. /// Should match the BulkAppendTree buffer capacity (2^chunk_power). pub max_encrypted_notes_per_query: u16, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs index a31fb8c12e7..3554ff647be 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_query_versions/v1.rs @@ -268,6 +268,26 @@ pub const DRIVE_ABCI_QUERY_VERSIONS_V1: DriveAbciQueryVersions = DriveAbciQueryV max_version: 0, default_current_version: 0, }, + nullifiers_trunk_state: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + nullifiers_branch_state: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + recent_nullifier_changes: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + recent_compacted_nullifier_changes: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, max_encrypted_notes_per_query: 2048, }, address_funds_queries: DriveAbciQueryAddressFundsVersions { diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs index 4766055d3af..0d7a67b58f7 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_group_method_versions/mod.rs @@ -63,3 +63,11 @@ pub struct DriveGroupCostEstimationMethodVersions { pub struct DriveAddressFundsCostEstimationMethodVersions { pub for_address_balance_update: FeatureVersion, } + +#[derive(Clone, Debug, Default)] +pub struct DriveShieldedMethodVersions { + pub prove_nullifiers_trunk_query: FeatureVersion, + pub prove_nullifiers_branch_query: FeatureVersion, + pub nullifiers_query_min_depth: u8, + pub nullifiers_query_max_depth: u8, +} diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs index aa602a504c6..a5448463776 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/mod.rs @@ -23,6 +23,10 @@ pub struct DriveVerifyShieldedMethodVersions { pub verify_shielded_anchors: FeatureVersion, pub verify_shielded_encrypted_notes: FeatureVersion, pub verify_shielded_nullifiers: FeatureVersion, + pub verify_nullifiers_trunk_query: FeatureVersion, + pub verify_nullifiers_branch_query: FeatureVersion, + pub verify_recent_nullifier_changes: FeatureVersion, + pub verify_compacted_nullifier_changes: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs index 288c009b854..1ad8c7d77cb 100644 --- a/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/drive_verify_method_versions/v1.rs @@ -96,5 +96,9 @@ pub const DRIVE_VERIFY_METHOD_VERSIONS_V1: DriveVerifyMethodVersions = DriveVeri verify_shielded_anchors: 0, verify_shielded_encrypted_notes: 0, verify_shielded_nullifiers: 0, + verify_nullifiers_trunk_query: 0, + verify_nullifiers_branch_query: 0, + verify_recent_nullifier_changes: 0, + verify_compacted_nullifier_changes: 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 bb441c2b103..2f547c3c391 100644 --- a/packages/rs-platform-version/src/version/drive_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/mod.rs @@ -1,4 +1,6 @@ -use crate::version::drive_versions::drive_group_method_versions::DriveAddressFundsMethodVersions; +use crate::version::drive_versions::drive_group_method_versions::{ + DriveAddressFundsMethodVersions, DriveShieldedMethodVersions, +}; use crate::version::FeatureVersion; use drive_contract_method_versions::DriveContractMethodVersions; use drive_credit_pool_method_versions::DriveCreditPoolMethodVersions; @@ -66,6 +68,7 @@ pub struct DriveMethodVersions { pub platform_state: DrivePlatformStateMethodVersions, pub group: DriveGroupMethodVersions, pub address_funds: DriveAddressFundsMethodVersions, + pub shielded: DriveShieldedMethodVersions, pub saved_block_transactions: DriveSavedBlockTransactionsMethodVersions, } @@ -85,6 +88,14 @@ pub struct DriveSavedBlockTransactionsMethodVersions { pub max_blocks_before_compaction: u16, /// Maximum number of address balance entries before compaction is triggered pub max_addresses_before_compaction: u32, + pub store_nullifiers: FeatureVersion, + pub fetch_nullifiers: FeatureVersion, + pub compact_nullifiers: FeatureVersion, + pub cleanup_expired_nullifiers: FeatureVersion, + /// Maximum number of blocks to store before nullifier compaction is triggered + pub max_blocks_before_nullifier_compaction: u16, + /// Maximum number of nullifier entries before compaction is triggered + pub max_nullifiers_before_compaction: u32, } #[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 e6c0a2722db..227c6dbb5ca 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v1.rs @@ -3,6 +3,7 @@ use crate::version::drive_versions::drive_contract_method_versions::v1::DRIVE_CO use crate::version::drive_versions::drive_credit_pool_method_versions::v1::CREDIT_POOL_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_document_method_versions::v1::DRIVE_DOCUMENT_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_group_method_versions::v1::DRIVE_GROUP_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_group_method_versions::DriveShieldedMethodVersions; 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; @@ -103,6 +104,12 @@ pub const DRIVE_VERSION_V1: DriveVersion = DriveVersion { }, group: DRIVE_GROUP_METHOD_VERSIONS_V1, address_funds: DRIVE_ADDRESS_FUNDS_METHOD_VERSIONS_V1, + shielded: DriveShieldedMethodVersions { + prove_nullifiers_trunk_query: 0, + prove_nullifiers_branch_query: 0, + nullifiers_query_min_depth: 6, + nullifiers_query_max_depth: 10, + }, saved_block_transactions: DriveSavedBlockTransactionsMethodVersions { store_address_balances: 0, fetch_address_balances: 0, @@ -110,6 +117,12 @@ pub const DRIVE_VERSION_V1: DriveVersion = DriveVersion { cleanup_expired_address_balances: 0, max_blocks_before_compaction: 64, max_addresses_before_compaction: 2048, + store_nullifiers: 0, + fetch_nullifiers: 0, + compact_nullifiers: 0, + cleanup_expired_nullifiers: 0, + max_blocks_before_nullifier_compaction: 64, + max_nullifiers_before_compaction: 2048, }, }, 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 b8dce7adf7f..203f1afa59f 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v2.rs @@ -3,6 +3,7 @@ use crate::version::drive_versions::drive_contract_method_versions::v1::DRIVE_CO use crate::version::drive_versions::drive_credit_pool_method_versions::v1::CREDIT_POOL_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_document_method_versions::v1::DRIVE_DOCUMENT_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_group_method_versions::v1::DRIVE_GROUP_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_group_method_versions::DriveShieldedMethodVersions; 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; @@ -103,6 +104,12 @@ pub const DRIVE_VERSION_V2: DriveVersion = DriveVersion { }, group: DRIVE_GROUP_METHOD_VERSIONS_V1, address_funds: DRIVE_ADDRESS_FUNDS_METHOD_VERSIONS_V1, + shielded: DriveShieldedMethodVersions { + prove_nullifiers_trunk_query: 0, + prove_nullifiers_branch_query: 0, + nullifiers_query_min_depth: 6, + nullifiers_query_max_depth: 10, + }, saved_block_transactions: DriveSavedBlockTransactionsMethodVersions { store_address_balances: 0, fetch_address_balances: 0, @@ -110,6 +117,12 @@ pub const DRIVE_VERSION_V2: DriveVersion = DriveVersion { cleanup_expired_address_balances: 0, max_blocks_before_compaction: 64, max_addresses_before_compaction: 2048, + store_nullifiers: 0, + fetch_nullifiers: 0, + compact_nullifiers: 0, + cleanup_expired_nullifiers: 0, + max_blocks_before_nullifier_compaction: 64, + max_nullifiers_before_compaction: 2048, }, }, 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 index d48d17bc84f..408a49cab6e 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v3.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v3.rs @@ -3,6 +3,7 @@ use crate::version::drive_versions::drive_contract_method_versions::v1::DRIVE_CO use crate::version::drive_versions::drive_credit_pool_method_versions::v1::CREDIT_POOL_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_document_method_versions::v1::DRIVE_DOCUMENT_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_group_method_versions::v1::DRIVE_GROUP_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_group_method_versions::DriveShieldedMethodVersions; 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; @@ -103,6 +104,12 @@ pub const DRIVE_VERSION_V3: DriveVersion = DriveVersion { }, group: DRIVE_GROUP_METHOD_VERSIONS_V1, address_funds: DRIVE_ADDRESS_FUNDS_METHOD_VERSIONS_V1, + shielded: DriveShieldedMethodVersions { + prove_nullifiers_trunk_query: 0, + prove_nullifiers_branch_query: 0, + nullifiers_query_min_depth: 6, + nullifiers_query_max_depth: 10, + }, saved_block_transactions: DriveSavedBlockTransactionsMethodVersions { store_address_balances: 0, fetch_address_balances: 0, @@ -110,6 +117,12 @@ pub const DRIVE_VERSION_V3: DriveVersion = DriveVersion { cleanup_expired_address_balances: 0, max_blocks_before_compaction: 64, max_addresses_before_compaction: 2048, + store_nullifiers: 0, + fetch_nullifiers: 0, + compact_nullifiers: 0, + cleanup_expired_nullifiers: 0, + max_blocks_before_nullifier_compaction: 64, + max_nullifiers_before_compaction: 2048, }, }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/drive_versions/v4.rs b/packages/rs-platform-version/src/version/drive_versions/v4.rs index 510942261b6..4ad9c1ee18c 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v4.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v4.rs @@ -3,6 +3,7 @@ use crate::version::drive_versions::drive_contract_method_versions::v2::DRIVE_CO use crate::version::drive_versions::drive_credit_pool_method_versions::v1::CREDIT_POOL_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_document_method_versions::v1::DRIVE_DOCUMENT_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_group_method_versions::v1::DRIVE_GROUP_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_group_method_versions::DriveShieldedMethodVersions; 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; @@ -103,6 +104,12 @@ pub const DRIVE_VERSION_V4: DriveVersion = DriveVersion { }, group: DRIVE_GROUP_METHOD_VERSIONS_V1, address_funds: DRIVE_ADDRESS_FUNDS_METHOD_VERSIONS_V1, + shielded: DriveShieldedMethodVersions { + prove_nullifiers_trunk_query: 0, + prove_nullifiers_branch_query: 0, + nullifiers_query_min_depth: 6, + nullifiers_query_max_depth: 10, + }, saved_block_transactions: DriveSavedBlockTransactionsMethodVersions { store_address_balances: 0, fetch_address_balances: 0, @@ -110,6 +117,12 @@ pub const DRIVE_VERSION_V4: DriveVersion = DriveVersion { cleanup_expired_address_balances: 0, max_blocks_before_compaction: 64, max_addresses_before_compaction: 2048, + store_nullifiers: 0, + fetch_nullifiers: 0, + compact_nullifiers: 0, + cleanup_expired_nullifiers: 0, + max_blocks_before_nullifier_compaction: 64, + max_nullifiers_before_compaction: 2048, }, }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/drive_versions/v5.rs b/packages/rs-platform-version/src/version/drive_versions/v5.rs index 76710f4a9f7..85808b0f126 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v5.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v5.rs @@ -3,6 +3,7 @@ use crate::version::drive_versions::drive_contract_method_versions::v2::DRIVE_CO 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::v2::DRIVE_DOCUMENT_METHOD_VERSIONS_V2; use crate::version::drive_versions::drive_group_method_versions::v1::DRIVE_GROUP_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_group_method_versions::DriveShieldedMethodVersions; 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; @@ -105,6 +106,12 @@ pub const DRIVE_VERSION_V5: DriveVersion = DriveVersion { }, group: DRIVE_GROUP_METHOD_VERSIONS_V1, address_funds: DRIVE_ADDRESS_FUNDS_METHOD_VERSIONS_V1, + shielded: DriveShieldedMethodVersions { + prove_nullifiers_trunk_query: 0, + prove_nullifiers_branch_query: 0, + nullifiers_query_min_depth: 6, + nullifiers_query_max_depth: 10, + }, saved_block_transactions: DriveSavedBlockTransactionsMethodVersions { store_address_balances: 0, fetch_address_balances: 0, @@ -112,6 +119,12 @@ pub const DRIVE_VERSION_V5: DriveVersion = DriveVersion { cleanup_expired_address_balances: 0, max_blocks_before_compaction: 64, max_addresses_before_compaction: 2048, + store_nullifiers: 0, + fetch_nullifiers: 0, + compact_nullifiers: 0, + cleanup_expired_nullifiers: 0, + max_blocks_before_nullifier_compaction: 64, + max_nullifiers_before_compaction: 2048, }, }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/drive_versions/v6.rs b/packages/rs-platform-version/src/version/drive_versions/v6.rs index 75131aba245..768caeb5580 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v6.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v6.rs @@ -3,6 +3,7 @@ use crate::version::drive_versions::drive_contract_method_versions::v2::DRIVE_CO 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::v2::DRIVE_DOCUMENT_METHOD_VERSIONS_V2; use crate::version::drive_versions::drive_group_method_versions::v1::DRIVE_GROUP_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_group_method_versions::DriveShieldedMethodVersions; 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::v2::DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V2; @@ -107,6 +108,12 @@ pub const DRIVE_VERSION_V6: DriveVersion = DriveVersion { }, group: DRIVE_GROUP_METHOD_VERSIONS_V1, address_funds: DRIVE_ADDRESS_FUNDS_METHOD_VERSIONS_V1, + shielded: DriveShieldedMethodVersions { + prove_nullifiers_trunk_query: 0, + prove_nullifiers_branch_query: 0, + nullifiers_query_min_depth: 6, + nullifiers_query_max_depth: 10, + }, saved_block_transactions: DriveSavedBlockTransactionsMethodVersions { store_address_balances: 0, fetch_address_balances: 0, @@ -114,6 +121,12 @@ pub const DRIVE_VERSION_V6: DriveVersion = DriveVersion { cleanup_expired_address_balances: 0, max_blocks_before_compaction: 64, max_addresses_before_compaction: 2048, + store_nullifiers: 0, + fetch_nullifiers: 0, + compact_nullifiers: 0, + cleanup_expired_nullifiers: 0, + max_blocks_before_nullifier_compaction: 64, + max_nullifiers_before_compaction: 2048, }, }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/drive_versions/v7.rs b/packages/rs-platform-version/src/version/drive_versions/v7.rs index 940cd9b2f7c..f0af92ec592 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v7.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v7.rs @@ -3,6 +3,7 @@ use crate::version::drive_versions::drive_contract_method_versions::v2::DRIVE_CO 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::v2::DRIVE_DOCUMENT_METHOD_VERSIONS_V2; use crate::version::drive_versions::drive_group_method_versions::v1::DRIVE_GROUP_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_group_method_versions::DriveShieldedMethodVersions; 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::v2::DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V2; @@ -104,6 +105,12 @@ pub const DRIVE_VERSION_V7: DriveVersion = DriveVersion { }, group: DRIVE_GROUP_METHOD_VERSIONS_V1, address_funds: DRIVE_ADDRESS_FUNDS_METHOD_VERSIONS_V1, + shielded: DriveShieldedMethodVersions { + prove_nullifiers_trunk_query: 0, + prove_nullifiers_branch_query: 0, + nullifiers_query_min_depth: 6, + nullifiers_query_max_depth: 10, + }, saved_block_transactions: DriveSavedBlockTransactionsMethodVersions { store_address_balances: 0, fetch_address_balances: 0, @@ -111,6 +118,12 @@ pub const DRIVE_VERSION_V7: DriveVersion = DriveVersion { cleanup_expired_address_balances: 0, max_blocks_before_compaction: 64, max_addresses_before_compaction: 2048, + store_nullifiers: 0, + fetch_nullifiers: 0, + compact_nullifiers: 0, + cleanup_expired_nullifiers: 0, + max_blocks_before_nullifier_compaction: 64, + max_nullifiers_before_compaction: 2048, }, }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_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 6141068900e..38d19591d29 100644 --- a/packages/rs-platform-version/src/version/mocks/v2_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v2_test.rs @@ -141,7 +141,7 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { }, group: DRIVE_GROUP_METHOD_VERSIONS_V1, address_funds: DRIVE_ADDRESS_FUNDS_METHOD_VERSIONS_V1, - saved_block_transactions: DriveSavedBlockTransactionsMethodVersions { store_address_balances: 0, fetch_address_balances: 0, compact_address_balances: 0, cleanup_expired_address_balances: 0, max_blocks_before_compaction: 64, max_addresses_before_compaction: 2048 }, + saved_block_transactions: DriveSavedBlockTransactionsMethodVersions { store_address_balances: 0, fetch_address_balances: 0, compact_address_balances: 0, cleanup_expired_address_balances: 0, max_blocks_before_compaction: 64, max_addresses_before_compaction: 2048, store_nullifiers: 0, fetch_nullifiers: 0, compact_nullifiers: 0, cleanup_expired_nullifiers: 0, max_blocks_before_nullifier_compaction: 64, max_nullifiers_before_compaction: 2048 }, }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, grove_version: GROVE_V1, @@ -412,6 +412,26 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { max_version: 0, default_current_version: 0, }, + nullifiers_trunk_state: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + nullifiers_branch_state: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + recent_nullifier_changes: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, + recent_compacted_nullifier_changes: FeatureVersionBounds { + min_version: 0, + max_version: 0, + default_current_version: 0, + }, max_encrypted_notes_per_query: 2048, }, address_funds_queries: DriveAbciQueryAddressFundsVersions { diff --git a/packages/rs-platform-version/src/version/mocks/v3_test.rs b/packages/rs-platform-version/src/version/mocks/v3_test.rs index abb3281b626..2a978246821 100644 --- a/packages/rs-platform-version/src/version/mocks/v3_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v3_test.rs @@ -142,6 +142,8 @@ pub const TEST_PLATFORM_V3: PlatformVersion = PlatformVersion { validate_fees_of_event: 0, store_address_balances_to_recent_block_storage: None, cleanup_recent_block_storage_address_balances: None, + store_nullifiers_to_recent_block_storage: None, + cleanup_recent_block_storage_nullifiers: None, }, epoch: DriveAbciEpochMethodVersions { gather_epoch_info: 0, diff --git a/packages/rs-sdk/Cargo.toml b/packages/rs-sdk/Cargo.toml index 158aa59ae54..e48d4d9be22 100644 --- a/packages/rs-sdk/Cargo.toml +++ b/packages/rs-sdk/Cargo.toml @@ -18,7 +18,7 @@ drive = { path = "../rs-drive", default-features = false, features = [ platform-wallet = { path = "../rs-platform-wallet", optional = true } drive-proof-verifier = { path = "../rs-drive-proof-verifier", default-features = false } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "dc8c25023c5116374087b2c73008ae9167c567d8", features = ["client", "sqlite"], optional = true } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444", features = ["client", "sqlite"], optional = true } dash-context-provider = { path = "../rs-context-provider", default-features = false } dash-platform-macros = { path = "../rs-dash-platform-macros" } http = { version = "1.1" } diff --git a/packages/rs-sdk/src/shielded.rs b/packages/rs-sdk/src/shielded.rs index 1a14f091c6c..d8161764cbc 100644 --- a/packages/rs-sdk/src/shielded.rs +++ b/packages/rs-sdk/src/shielded.rs @@ -8,11 +8,9 @@ use crate::error::Error; use crate::platform::Fetch; use crate::Sdk; -use drive_proof_verifier::types::{ShieldedEncryptedNote, ShieldedEncryptedNotes}; use drive_proof_verifier::types::ShieldedEncryptedNotesQuery; +use drive_proof_verifier::types::{ShieldedEncryptedNote, ShieldedEncryptedNotes}; use futures::stream::{FuturesUnordered, StreamExt}; -use std::pin::Pin; -use std::future::Future; use grovedb_commitment_tree::{ try_compact_note_decryption, CompactAction, DashMemo, EphemeralKeyBytes, ExtractedNoteCommitment, Note, Nullifier, OrchardDomain, PaymentAddress, @@ -20,6 +18,8 @@ use grovedb_commitment_tree::{ }; use rs_dapi_client::RequestSettings; use std::collections::BTreeMap; +use std::future::Future; +use std::pin::Pin; use tracing::debug; /// Minimum length of the `encrypted_note` field for compact trial decryption. @@ -176,9 +176,8 @@ pub async fn sync_shielded_notes( let max_concurrent = config.max_concurrent.max(1); let settings = config.request_settings; - type ChunkFuture = Pin< - Box), Error>> + Send>, - >; + type ChunkFuture = + Pin), Error>> + Send>>; // Sliding-window parallel fetch using FuturesUnordered. // Each future fetches one chunk and returns (chunk_start_index, notes). @@ -191,9 +190,9 @@ pub async fn sync_shielded_notes( let chunk_idx = next_chunk_index; next_chunk_index += chunk_size; let sdk = sdk.clone(); - futures.push(Box::pin( - async move { fetch_chunk(&sdk, chunk_idx, chunk_size, settings).await }, - )); + futures.push(Box::pin(async move { + fetch_chunk(&sdk, chunk_idx, chunk_size, settings).await + })); } // Collect results keyed by chunk start_index for ordered reassembly @@ -213,9 +212,9 @@ pub async fn sync_shielded_notes( let chunk_idx = next_chunk_index; next_chunk_index += chunk_size; let sdk = sdk.clone(); - futures.push(Box::pin( - async move { fetch_chunk(&sdk, chunk_idx, chunk_size, settings).await }, - )); + futures.push(Box::pin(async move { + fetch_chunk(&sdk, chunk_idx, chunk_size, settings).await + })); } } @@ -228,16 +227,8 @@ pub async fn sync_shielded_notes( let position = chunk_start + i as u64; if let Some((decrypted, address)) = try_decrypt_note(ivk, note) { - let nf: [u8; 32] = note - .nullifier - .as_slice() - .try_into() - .unwrap_or([0u8; 32]); - let cmx: [u8; 32] = note - .cmx - .as_slice() - .try_into() - .unwrap_or([0u8; 32]); + let nf: [u8; 32] = note.nullifier.as_slice().try_into().unwrap_or([0u8; 32]); + let cmx: [u8; 32] = note.cmx.as_slice().try_into().unwrap_or([0u8; 32]); decrypted_notes.push(DecryptedNote { position, @@ -297,8 +288,7 @@ async fn fetch_chunk( debug!(chunk_start, chunk_size, "fetching shielded notes chunk"); - let result = - ShieldedEncryptedNotes::fetch_with_settings(sdk, query, settings).await?; + let result = ShieldedEncryptedNotes::fetch_with_settings(sdk, query, settings).await?; let notes = match result { Some(ShieldedEncryptedNotes(notes)) => notes, From a4c4871e045be819dbed1af49fbcdbdee55c8022 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 24 Feb 2026 05:06:12 +0700 Subject: [PATCH 27/40] more work --- .../clients/drive/v0/nodejs/drive_pbjs.js | 4696 +++++++++++++++++ .../dash/platform/dapi/v0/PlatformGrpc.java | 296 ++ .../platform/v0/nodejs/platform_pbjs.js | 4696 +++++++++++++++++ .../platform/v0/nodejs/platform_protoc.js | 4344 +++++++++++++++ .../platform/v0/objective-c/Platform.pbobjc.h | 439 ++ .../platform/v0/objective-c/Platform.pbobjc.m | 1211 +++++ .../platform/v0/objective-c/Platform.pbrpc.h | 52 + .../platform/v0/objective-c/Platform.pbrpc.m | 80 + .../platform/v0/python/platform_pb2.py | 1064 +++- .../platform/v0/python/platform_pb2_grpc.py | 132 + .../clients/platform/v0/web/platform_pb.d.ts | 574 ++ .../clients/platform/v0/web/platform_pb.js | 4344 +++++++++++++++ .../platform/v0/web/platform_pb_service.d.ts | 76 + .../platform/v0/web/platform_pb_service.js | 160 + .../src/services/platform_service/mod.rs | 24 + packages/rs-sdk/src/platform/fetch.rs | 8 + 16 files changed, 22191 insertions(+), 5 deletions(-) diff --git a/packages/dapi-grpc/clients/drive/v0/nodejs/drive_pbjs.js b/packages/dapi-grpc/clients/drive/v0/nodejs/drive_pbjs.js index a3f48de6292..726f88ae4cd 100644 --- a/packages/dapi-grpc/clients/drive/v0/nodejs/drive_pbjs.js +++ b/packages/dapi-grpc/clients/drive/v0/nodejs/drive_pbjs.js @@ -2475,6 +2475,138 @@ $root.org = (function() { * @variation 2 */ + /** + * Callback as used by {@link org.dash.platform.dapi.v0.Platform#getNullifiersTrunkState}. + * @memberof org.dash.platform.dapi.v0.Platform + * @typedef getNullifiersTrunkStateCallback + * @type {function} + * @param {Error|null} error Error, if any + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} [response] GetNullifiersTrunkStateResponse + */ + + /** + * Calls getNullifiersTrunkState. + * @function getNullifiersTrunkState + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateRequest} request GetNullifiersTrunkStateRequest message or plain object + * @param {org.dash.platform.dapi.v0.Platform.getNullifiersTrunkStateCallback} callback Node-style callback called with the error, if any, and GetNullifiersTrunkStateResponse + * @returns {undefined} + * @variation 1 + */ + Object.defineProperty(Platform.prototype.getNullifiersTrunkState = function getNullifiersTrunkState(request, callback) { + return this.rpcCall(getNullifiersTrunkState, $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest, $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse, request, callback); + }, "name", { value: "getNullifiersTrunkState" }); + + /** + * Calls getNullifiersTrunkState. + * @function getNullifiersTrunkState + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateRequest} request GetNullifiersTrunkStateRequest message or plain object + * @returns {Promise} Promise + * @variation 2 + */ + + /** + * Callback as used by {@link org.dash.platform.dapi.v0.Platform#getNullifiersBranchState}. + * @memberof org.dash.platform.dapi.v0.Platform + * @typedef getNullifiersBranchStateCallback + * @type {function} + * @param {Error|null} error Error, if any + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} [response] GetNullifiersBranchStateResponse + */ + + /** + * Calls getNullifiersBranchState. + * @function getNullifiersBranchState + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateRequest} request GetNullifiersBranchStateRequest message or plain object + * @param {org.dash.platform.dapi.v0.Platform.getNullifiersBranchStateCallback} callback Node-style callback called with the error, if any, and GetNullifiersBranchStateResponse + * @returns {undefined} + * @variation 1 + */ + Object.defineProperty(Platform.prototype.getNullifiersBranchState = function getNullifiersBranchState(request, callback) { + return this.rpcCall(getNullifiersBranchState, $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest, $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse, request, callback); + }, "name", { value: "getNullifiersBranchState" }); + + /** + * Calls getNullifiersBranchState. + * @function getNullifiersBranchState + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateRequest} request GetNullifiersBranchStateRequest message or plain object + * @returns {Promise} Promise + * @variation 2 + */ + + /** + * Callback as used by {@link org.dash.platform.dapi.v0.Platform#getRecentNullifierChanges}. + * @memberof org.dash.platform.dapi.v0.Platform + * @typedef getRecentNullifierChangesCallback + * @type {function} + * @param {Error|null} error Error, if any + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} [response] GetRecentNullifierChangesResponse + */ + + /** + * Calls getRecentNullifierChanges. + * @function getRecentNullifierChanges + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesRequest} request GetRecentNullifierChangesRequest message or plain object + * @param {org.dash.platform.dapi.v0.Platform.getRecentNullifierChangesCallback} callback Node-style callback called with the error, if any, and GetRecentNullifierChangesResponse + * @returns {undefined} + * @variation 1 + */ + Object.defineProperty(Platform.prototype.getRecentNullifierChanges = function getRecentNullifierChanges(request, callback) { + return this.rpcCall(getRecentNullifierChanges, $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest, $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse, request, callback); + }, "name", { value: "getRecentNullifierChanges" }); + + /** + * Calls getRecentNullifierChanges. + * @function getRecentNullifierChanges + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesRequest} request GetRecentNullifierChangesRequest message or plain object + * @returns {Promise} Promise + * @variation 2 + */ + + /** + * Callback as used by {@link org.dash.platform.dapi.v0.Platform#getRecentCompactedNullifierChanges}. + * @memberof org.dash.platform.dapi.v0.Platform + * @typedef getRecentCompactedNullifierChangesCallback + * @type {function} + * @param {Error|null} error Error, if any + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} [response] GetRecentCompactedNullifierChangesResponse + */ + + /** + * Calls getRecentCompactedNullifierChanges. + * @function getRecentCompactedNullifierChanges + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesRequest} request GetRecentCompactedNullifierChangesRequest message or plain object + * @param {org.dash.platform.dapi.v0.Platform.getRecentCompactedNullifierChangesCallback} callback Node-style callback called with the error, if any, and GetRecentCompactedNullifierChangesResponse + * @returns {undefined} + * @variation 1 + */ + Object.defineProperty(Platform.prototype.getRecentCompactedNullifierChanges = function getRecentCompactedNullifierChanges(request, callback) { + return this.rpcCall(getRecentCompactedNullifierChanges, $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest, $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse, request, callback); + }, "name", { value: "getRecentCompactedNullifierChanges" }); + + /** + * Calls getRecentCompactedNullifierChanges. + * @function getRecentCompactedNullifierChanges + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesRequest} request GetRecentCompactedNullifierChangesRequest message or plain object + * @returns {Promise} Promise + * @variation 2 + */ + return Platform; })(); @@ -87507,6 +87639,4570 @@ $root.org = (function() { return GetShieldedNullifiersResponse; })(); + v0.GetNullifiersTrunkStateRequest = (function() { + + /** + * Properties of a GetNullifiersTrunkStateRequest. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetNullifiersTrunkStateRequest + * @property {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.IGetNullifiersTrunkStateRequestV0|null} [v0] GetNullifiersTrunkStateRequest v0 + */ + + /** + * Constructs a new GetNullifiersTrunkStateRequest. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetNullifiersTrunkStateRequest. + * @implements IGetNullifiersTrunkStateRequest + * @constructor + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateRequest=} [properties] Properties to set + */ + function GetNullifiersTrunkStateRequest(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetNullifiersTrunkStateRequest v0. + * @member {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.IGetNullifiersTrunkStateRequestV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @instance + */ + GetNullifiersTrunkStateRequest.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetNullifiersTrunkStateRequest version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @instance + */ + Object.defineProperty(GetNullifiersTrunkStateRequest.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetNullifiersTrunkStateRequest instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateRequest=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} GetNullifiersTrunkStateRequest instance + */ + GetNullifiersTrunkStateRequest.create = function create(properties) { + return new GetNullifiersTrunkStateRequest(properties); + }; + + /** + * Encodes the specified GetNullifiersTrunkStateRequest message. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateRequest} message GetNullifiersTrunkStateRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersTrunkStateRequest.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetNullifiersTrunkStateRequest message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateRequest} message GetNullifiersTrunkStateRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersTrunkStateRequest.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetNullifiersTrunkStateRequest message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} GetNullifiersTrunkStateRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersTrunkStateRequest.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetNullifiersTrunkStateRequest message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} GetNullifiersTrunkStateRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersTrunkStateRequest.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetNullifiersTrunkStateRequest message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetNullifiersTrunkStateRequest.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetNullifiersTrunkStateRequest message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} GetNullifiersTrunkStateRequest + */ + GetNullifiersTrunkStateRequest.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetNullifiersTrunkStateRequest message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} message GetNullifiersTrunkStateRequest + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetNullifiersTrunkStateRequest.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetNullifiersTrunkStateRequest to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @instance + * @returns {Object.} JSON object + */ + GetNullifiersTrunkStateRequest.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 = (function() { + + /** + * Properties of a GetNullifiersTrunkStateRequestV0. + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @interface IGetNullifiersTrunkStateRequestV0 + * @property {number|null} [poolType] GetNullifiersTrunkStateRequestV0 poolType + * @property {Uint8Array|null} [poolIdentifier] GetNullifiersTrunkStateRequestV0 poolIdentifier + */ + + /** + * Constructs a new GetNullifiersTrunkStateRequestV0. + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @classdesc Represents a GetNullifiersTrunkStateRequestV0. + * @implements IGetNullifiersTrunkStateRequestV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.IGetNullifiersTrunkStateRequestV0=} [properties] Properties to set + */ + function GetNullifiersTrunkStateRequestV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetNullifiersTrunkStateRequestV0 poolType. + * @member {number} poolType + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @instance + */ + GetNullifiersTrunkStateRequestV0.prototype.poolType = 0; + + /** + * GetNullifiersTrunkStateRequestV0 poolIdentifier. + * @member {Uint8Array} poolIdentifier + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @instance + */ + GetNullifiersTrunkStateRequestV0.prototype.poolIdentifier = $util.newBuffer([]); + + /** + * Creates a new GetNullifiersTrunkStateRequestV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.IGetNullifiersTrunkStateRequestV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} GetNullifiersTrunkStateRequestV0 instance + */ + GetNullifiersTrunkStateRequestV0.create = function create(properties) { + return new GetNullifiersTrunkStateRequestV0(properties); + }; + + /** + * Encodes the specified GetNullifiersTrunkStateRequestV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.IGetNullifiersTrunkStateRequestV0} message GetNullifiersTrunkStateRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersTrunkStateRequestV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.poolType != null && Object.hasOwnProperty.call(message, "poolType")) + writer.uint32(/* id 1, wireType 0 =*/8).uint32(message.poolType); + if (message.poolIdentifier != null && Object.hasOwnProperty.call(message, "poolIdentifier")) + writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.poolIdentifier); + return writer; + }; + + /** + * Encodes the specified GetNullifiersTrunkStateRequestV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.IGetNullifiersTrunkStateRequestV0} message GetNullifiersTrunkStateRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersTrunkStateRequestV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetNullifiersTrunkStateRequestV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} GetNullifiersTrunkStateRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersTrunkStateRequestV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.poolType = reader.uint32(); + break; + case 2: + message.poolIdentifier = reader.bytes(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetNullifiersTrunkStateRequestV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} GetNullifiersTrunkStateRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersTrunkStateRequestV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetNullifiersTrunkStateRequestV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetNullifiersTrunkStateRequestV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.poolType != null && message.hasOwnProperty("poolType")) + if (!$util.isInteger(message.poolType)) + return "poolType: integer expected"; + if (message.poolIdentifier != null && message.hasOwnProperty("poolIdentifier")) + if (!(message.poolIdentifier && typeof message.poolIdentifier.length === "number" || $util.isString(message.poolIdentifier))) + return "poolIdentifier: buffer expected"; + return null; + }; + + /** + * Creates a GetNullifiersTrunkStateRequestV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} GetNullifiersTrunkStateRequestV0 + */ + GetNullifiersTrunkStateRequestV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0(); + if (object.poolType != null) + message.poolType = object.poolType >>> 0; + if (object.poolIdentifier != null) + if (typeof object.poolIdentifier === "string") + $util.base64.decode(object.poolIdentifier, message.poolIdentifier = $util.newBuffer($util.base64.length(object.poolIdentifier)), 0); + else if (object.poolIdentifier.length >= 0) + message.poolIdentifier = object.poolIdentifier; + return message; + }; + + /** + * Creates a plain object from a GetNullifiersTrunkStateRequestV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} message GetNullifiersTrunkStateRequestV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetNullifiersTrunkStateRequestV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.poolType = 0; + if (options.bytes === String) + object.poolIdentifier = ""; + else { + object.poolIdentifier = []; + if (options.bytes !== Array) + object.poolIdentifier = $util.newBuffer(object.poolIdentifier); + } + } + if (message.poolType != null && message.hasOwnProperty("poolType")) + object.poolType = message.poolType; + if (message.poolIdentifier != null && message.hasOwnProperty("poolIdentifier")) + object.poolIdentifier = options.bytes === String ? $util.base64.encode(message.poolIdentifier, 0, message.poolIdentifier.length) : options.bytes === Array ? Array.prototype.slice.call(message.poolIdentifier) : message.poolIdentifier; + return object; + }; + + /** + * Converts this GetNullifiersTrunkStateRequestV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @instance + * @returns {Object.} JSON object + */ + GetNullifiersTrunkStateRequestV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetNullifiersTrunkStateRequestV0; + })(); + + return GetNullifiersTrunkStateRequest; + })(); + + v0.GetNullifiersTrunkStateResponse = (function() { + + /** + * Properties of a GetNullifiersTrunkStateResponse. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetNullifiersTrunkStateResponse + * @property {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.IGetNullifiersTrunkStateResponseV0|null} [v0] GetNullifiersTrunkStateResponse v0 + */ + + /** + * Constructs a new GetNullifiersTrunkStateResponse. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetNullifiersTrunkStateResponse. + * @implements IGetNullifiersTrunkStateResponse + * @constructor + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateResponse=} [properties] Properties to set + */ + function GetNullifiersTrunkStateResponse(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetNullifiersTrunkStateResponse v0. + * @member {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.IGetNullifiersTrunkStateResponseV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @instance + */ + GetNullifiersTrunkStateResponse.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetNullifiersTrunkStateResponse version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @instance + */ + Object.defineProperty(GetNullifiersTrunkStateResponse.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetNullifiersTrunkStateResponse instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateResponse=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} GetNullifiersTrunkStateResponse instance + */ + GetNullifiersTrunkStateResponse.create = function create(properties) { + return new GetNullifiersTrunkStateResponse(properties); + }; + + /** + * Encodes the specified GetNullifiersTrunkStateResponse message. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateResponse} message GetNullifiersTrunkStateResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersTrunkStateResponse.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetNullifiersTrunkStateResponse message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateResponse} message GetNullifiersTrunkStateResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersTrunkStateResponse.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetNullifiersTrunkStateResponse message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} GetNullifiersTrunkStateResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersTrunkStateResponse.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetNullifiersTrunkStateResponse message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} GetNullifiersTrunkStateResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersTrunkStateResponse.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetNullifiersTrunkStateResponse message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetNullifiersTrunkStateResponse.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetNullifiersTrunkStateResponse message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} GetNullifiersTrunkStateResponse + */ + GetNullifiersTrunkStateResponse.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetNullifiersTrunkStateResponse message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} message GetNullifiersTrunkStateResponse + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetNullifiersTrunkStateResponse.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetNullifiersTrunkStateResponse to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @instance + * @returns {Object.} JSON object + */ + GetNullifiersTrunkStateResponse.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 = (function() { + + /** + * Properties of a GetNullifiersTrunkStateResponseV0. + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @interface IGetNullifiersTrunkStateResponseV0 + * @property {org.dash.platform.dapi.v0.IProof|null} [proof] GetNullifiersTrunkStateResponseV0 proof + * @property {org.dash.platform.dapi.v0.IResponseMetadata|null} [metadata] GetNullifiersTrunkStateResponseV0 metadata + */ + + /** + * Constructs a new GetNullifiersTrunkStateResponseV0. + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @classdesc Represents a GetNullifiersTrunkStateResponseV0. + * @implements IGetNullifiersTrunkStateResponseV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.IGetNullifiersTrunkStateResponseV0=} [properties] Properties to set + */ + function GetNullifiersTrunkStateResponseV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetNullifiersTrunkStateResponseV0 proof. + * @member {org.dash.platform.dapi.v0.IProof|null|undefined} proof + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @instance + */ + GetNullifiersTrunkStateResponseV0.prototype.proof = null; + + /** + * GetNullifiersTrunkStateResponseV0 metadata. + * @member {org.dash.platform.dapi.v0.IResponseMetadata|null|undefined} metadata + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @instance + */ + GetNullifiersTrunkStateResponseV0.prototype.metadata = null; + + /** + * Creates a new GetNullifiersTrunkStateResponseV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.IGetNullifiersTrunkStateResponseV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} GetNullifiersTrunkStateResponseV0 instance + */ + GetNullifiersTrunkStateResponseV0.create = function create(properties) { + return new GetNullifiersTrunkStateResponseV0(properties); + }; + + /** + * Encodes the specified GetNullifiersTrunkStateResponseV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.IGetNullifiersTrunkStateResponseV0} message GetNullifiersTrunkStateResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersTrunkStateResponseV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.proof != null && Object.hasOwnProperty.call(message, "proof")) + $root.org.dash.platform.dapi.v0.Proof.encode(message.proof, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + if (message.metadata != null && Object.hasOwnProperty.call(message, "metadata")) + $root.org.dash.platform.dapi.v0.ResponseMetadata.encode(message.metadata, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetNullifiersTrunkStateResponseV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.IGetNullifiersTrunkStateResponseV0} message GetNullifiersTrunkStateResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersTrunkStateResponseV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetNullifiersTrunkStateResponseV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} GetNullifiersTrunkStateResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersTrunkStateResponseV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 2: + message.proof = $root.org.dash.platform.dapi.v0.Proof.decode(reader, reader.uint32()); + break; + case 3: + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetNullifiersTrunkStateResponseV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} GetNullifiersTrunkStateResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersTrunkStateResponseV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetNullifiersTrunkStateResponseV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetNullifiersTrunkStateResponseV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.proof != null && message.hasOwnProperty("proof")) { + var error = $root.org.dash.platform.dapi.v0.Proof.verify(message.proof); + if (error) + return "proof." + error; + } + if (message.metadata != null && message.hasOwnProperty("metadata")) { + var error = $root.org.dash.platform.dapi.v0.ResponseMetadata.verify(message.metadata); + if (error) + return "metadata." + error; + } + return null; + }; + + /** + * Creates a GetNullifiersTrunkStateResponseV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} GetNullifiersTrunkStateResponseV0 + */ + GetNullifiersTrunkStateResponseV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0(); + if (object.proof != null) { + if (typeof object.proof !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.proof: object expected"); + message.proof = $root.org.dash.platform.dapi.v0.Proof.fromObject(object.proof); + } + if (object.metadata != null) { + if (typeof object.metadata !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.metadata: object expected"); + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.fromObject(object.metadata); + } + return message; + }; + + /** + * Creates a plain object from a GetNullifiersTrunkStateResponseV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} message GetNullifiersTrunkStateResponseV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetNullifiersTrunkStateResponseV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.proof = null; + object.metadata = null; + } + if (message.proof != null && message.hasOwnProperty("proof")) + object.proof = $root.org.dash.platform.dapi.v0.Proof.toObject(message.proof, options); + if (message.metadata != null && message.hasOwnProperty("metadata")) + object.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.toObject(message.metadata, options); + return object; + }; + + /** + * Converts this GetNullifiersTrunkStateResponseV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @instance + * @returns {Object.} JSON object + */ + GetNullifiersTrunkStateResponseV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetNullifiersTrunkStateResponseV0; + })(); + + return GetNullifiersTrunkStateResponse; + })(); + + v0.GetNullifiersBranchStateRequest = (function() { + + /** + * Properties of a GetNullifiersBranchStateRequest. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetNullifiersBranchStateRequest + * @property {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.IGetNullifiersBranchStateRequestV0|null} [v0] GetNullifiersBranchStateRequest v0 + */ + + /** + * Constructs a new GetNullifiersBranchStateRequest. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetNullifiersBranchStateRequest. + * @implements IGetNullifiersBranchStateRequest + * @constructor + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateRequest=} [properties] Properties to set + */ + function GetNullifiersBranchStateRequest(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetNullifiersBranchStateRequest v0. + * @member {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.IGetNullifiersBranchStateRequestV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @instance + */ + GetNullifiersBranchStateRequest.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetNullifiersBranchStateRequest version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @instance + */ + Object.defineProperty(GetNullifiersBranchStateRequest.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetNullifiersBranchStateRequest instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateRequest=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} GetNullifiersBranchStateRequest instance + */ + GetNullifiersBranchStateRequest.create = function create(properties) { + return new GetNullifiersBranchStateRequest(properties); + }; + + /** + * Encodes the specified GetNullifiersBranchStateRequest message. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateRequest} message GetNullifiersBranchStateRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersBranchStateRequest.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetNullifiersBranchStateRequest message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateRequest} message GetNullifiersBranchStateRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersBranchStateRequest.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetNullifiersBranchStateRequest message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} GetNullifiersBranchStateRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersBranchStateRequest.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetNullifiersBranchStateRequest message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} GetNullifiersBranchStateRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersBranchStateRequest.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetNullifiersBranchStateRequest message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetNullifiersBranchStateRequest.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetNullifiersBranchStateRequest message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} GetNullifiersBranchStateRequest + */ + GetNullifiersBranchStateRequest.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetNullifiersBranchStateRequest message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} message GetNullifiersBranchStateRequest + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetNullifiersBranchStateRequest.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetNullifiersBranchStateRequest to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @instance + * @returns {Object.} JSON object + */ + GetNullifiersBranchStateRequest.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 = (function() { + + /** + * Properties of a GetNullifiersBranchStateRequestV0. + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @interface IGetNullifiersBranchStateRequestV0 + * @property {number|null} [poolType] GetNullifiersBranchStateRequestV0 poolType + * @property {Uint8Array|null} [poolIdentifier] GetNullifiersBranchStateRequestV0 poolIdentifier + * @property {Uint8Array|null} [key] GetNullifiersBranchStateRequestV0 key + * @property {number|null} [depth] GetNullifiersBranchStateRequestV0 depth + * @property {number|Long|null} [checkpointHeight] GetNullifiersBranchStateRequestV0 checkpointHeight + */ + + /** + * Constructs a new GetNullifiersBranchStateRequestV0. + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @classdesc Represents a GetNullifiersBranchStateRequestV0. + * @implements IGetNullifiersBranchStateRequestV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.IGetNullifiersBranchStateRequestV0=} [properties] Properties to set + */ + function GetNullifiersBranchStateRequestV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetNullifiersBranchStateRequestV0 poolType. + * @member {number} poolType + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @instance + */ + GetNullifiersBranchStateRequestV0.prototype.poolType = 0; + + /** + * GetNullifiersBranchStateRequestV0 poolIdentifier. + * @member {Uint8Array} poolIdentifier + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @instance + */ + GetNullifiersBranchStateRequestV0.prototype.poolIdentifier = $util.newBuffer([]); + + /** + * GetNullifiersBranchStateRequestV0 key. + * @member {Uint8Array} key + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @instance + */ + GetNullifiersBranchStateRequestV0.prototype.key = $util.newBuffer([]); + + /** + * GetNullifiersBranchStateRequestV0 depth. + * @member {number} depth + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @instance + */ + GetNullifiersBranchStateRequestV0.prototype.depth = 0; + + /** + * GetNullifiersBranchStateRequestV0 checkpointHeight. + * @member {number|Long} checkpointHeight + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @instance + */ + GetNullifiersBranchStateRequestV0.prototype.checkpointHeight = $util.Long ? $util.Long.fromBits(0,0,true) : 0; + + /** + * Creates a new GetNullifiersBranchStateRequestV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.IGetNullifiersBranchStateRequestV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} GetNullifiersBranchStateRequestV0 instance + */ + GetNullifiersBranchStateRequestV0.create = function create(properties) { + return new GetNullifiersBranchStateRequestV0(properties); + }; + + /** + * Encodes the specified GetNullifiersBranchStateRequestV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.IGetNullifiersBranchStateRequestV0} message GetNullifiersBranchStateRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersBranchStateRequestV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.poolType != null && Object.hasOwnProperty.call(message, "poolType")) + writer.uint32(/* id 1, wireType 0 =*/8).uint32(message.poolType); + if (message.poolIdentifier != null && Object.hasOwnProperty.call(message, "poolIdentifier")) + writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.poolIdentifier); + if (message.key != null && Object.hasOwnProperty.call(message, "key")) + writer.uint32(/* id 3, wireType 2 =*/26).bytes(message.key); + if (message.depth != null && Object.hasOwnProperty.call(message, "depth")) + writer.uint32(/* id 4, wireType 0 =*/32).uint32(message.depth); + if (message.checkpointHeight != null && Object.hasOwnProperty.call(message, "checkpointHeight")) + writer.uint32(/* id 5, wireType 0 =*/40).uint64(message.checkpointHeight); + return writer; + }; + + /** + * Encodes the specified GetNullifiersBranchStateRequestV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.IGetNullifiersBranchStateRequestV0} message GetNullifiersBranchStateRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersBranchStateRequestV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetNullifiersBranchStateRequestV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} GetNullifiersBranchStateRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersBranchStateRequestV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.poolType = reader.uint32(); + break; + case 2: + message.poolIdentifier = reader.bytes(); + break; + case 3: + message.key = reader.bytes(); + break; + case 4: + message.depth = reader.uint32(); + break; + case 5: + message.checkpointHeight = reader.uint64(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetNullifiersBranchStateRequestV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} GetNullifiersBranchStateRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersBranchStateRequestV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetNullifiersBranchStateRequestV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetNullifiersBranchStateRequestV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.poolType != null && message.hasOwnProperty("poolType")) + if (!$util.isInteger(message.poolType)) + return "poolType: integer expected"; + if (message.poolIdentifier != null && message.hasOwnProperty("poolIdentifier")) + if (!(message.poolIdentifier && typeof message.poolIdentifier.length === "number" || $util.isString(message.poolIdentifier))) + return "poolIdentifier: buffer expected"; + if (message.key != null && message.hasOwnProperty("key")) + if (!(message.key && typeof message.key.length === "number" || $util.isString(message.key))) + return "key: buffer expected"; + if (message.depth != null && message.hasOwnProperty("depth")) + if (!$util.isInteger(message.depth)) + return "depth: integer expected"; + if (message.checkpointHeight != null && message.hasOwnProperty("checkpointHeight")) + if (!$util.isInteger(message.checkpointHeight) && !(message.checkpointHeight && $util.isInteger(message.checkpointHeight.low) && $util.isInteger(message.checkpointHeight.high))) + return "checkpointHeight: integer|Long expected"; + return null; + }; + + /** + * Creates a GetNullifiersBranchStateRequestV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} GetNullifiersBranchStateRequestV0 + */ + GetNullifiersBranchStateRequestV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0(); + if (object.poolType != null) + message.poolType = object.poolType >>> 0; + if (object.poolIdentifier != null) + if (typeof object.poolIdentifier === "string") + $util.base64.decode(object.poolIdentifier, message.poolIdentifier = $util.newBuffer($util.base64.length(object.poolIdentifier)), 0); + else if (object.poolIdentifier.length >= 0) + message.poolIdentifier = object.poolIdentifier; + if (object.key != null) + if (typeof object.key === "string") + $util.base64.decode(object.key, message.key = $util.newBuffer($util.base64.length(object.key)), 0); + else if (object.key.length >= 0) + message.key = object.key; + if (object.depth != null) + message.depth = object.depth >>> 0; + if (object.checkpointHeight != null) + if ($util.Long) + (message.checkpointHeight = $util.Long.fromValue(object.checkpointHeight)).unsigned = true; + else if (typeof object.checkpointHeight === "string") + message.checkpointHeight = parseInt(object.checkpointHeight, 10); + else if (typeof object.checkpointHeight === "number") + message.checkpointHeight = object.checkpointHeight; + else if (typeof object.checkpointHeight === "object") + message.checkpointHeight = new $util.LongBits(object.checkpointHeight.low >>> 0, object.checkpointHeight.high >>> 0).toNumber(true); + return message; + }; + + /** + * Creates a plain object from a GetNullifiersBranchStateRequestV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} message GetNullifiersBranchStateRequestV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetNullifiersBranchStateRequestV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.poolType = 0; + if (options.bytes === String) + object.poolIdentifier = ""; + else { + object.poolIdentifier = []; + if (options.bytes !== Array) + object.poolIdentifier = $util.newBuffer(object.poolIdentifier); + } + if (options.bytes === String) + object.key = ""; + else { + object.key = []; + if (options.bytes !== Array) + object.key = $util.newBuffer(object.key); + } + object.depth = 0; + if ($util.Long) { + var long = new $util.Long(0, 0, true); + object.checkpointHeight = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.checkpointHeight = options.longs === String ? "0" : 0; + } + if (message.poolType != null && message.hasOwnProperty("poolType")) + object.poolType = message.poolType; + if (message.poolIdentifier != null && message.hasOwnProperty("poolIdentifier")) + object.poolIdentifier = options.bytes === String ? $util.base64.encode(message.poolIdentifier, 0, message.poolIdentifier.length) : options.bytes === Array ? Array.prototype.slice.call(message.poolIdentifier) : message.poolIdentifier; + if (message.key != null && message.hasOwnProperty("key")) + object.key = options.bytes === String ? $util.base64.encode(message.key, 0, message.key.length) : options.bytes === Array ? Array.prototype.slice.call(message.key) : message.key; + if (message.depth != null && message.hasOwnProperty("depth")) + object.depth = message.depth; + if (message.checkpointHeight != null && message.hasOwnProperty("checkpointHeight")) + if (typeof message.checkpointHeight === "number") + object.checkpointHeight = options.longs === String ? String(message.checkpointHeight) : message.checkpointHeight; + else + object.checkpointHeight = options.longs === String ? $util.Long.prototype.toString.call(message.checkpointHeight) : options.longs === Number ? new $util.LongBits(message.checkpointHeight.low >>> 0, message.checkpointHeight.high >>> 0).toNumber(true) : message.checkpointHeight; + return object; + }; + + /** + * Converts this GetNullifiersBranchStateRequestV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @instance + * @returns {Object.} JSON object + */ + GetNullifiersBranchStateRequestV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetNullifiersBranchStateRequestV0; + })(); + + return GetNullifiersBranchStateRequest; + })(); + + v0.GetNullifiersBranchStateResponse = (function() { + + /** + * Properties of a GetNullifiersBranchStateResponse. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetNullifiersBranchStateResponse + * @property {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.IGetNullifiersBranchStateResponseV0|null} [v0] GetNullifiersBranchStateResponse v0 + */ + + /** + * Constructs a new GetNullifiersBranchStateResponse. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetNullifiersBranchStateResponse. + * @implements IGetNullifiersBranchStateResponse + * @constructor + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateResponse=} [properties] Properties to set + */ + function GetNullifiersBranchStateResponse(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetNullifiersBranchStateResponse v0. + * @member {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.IGetNullifiersBranchStateResponseV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @instance + */ + GetNullifiersBranchStateResponse.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetNullifiersBranchStateResponse version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @instance + */ + Object.defineProperty(GetNullifiersBranchStateResponse.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetNullifiersBranchStateResponse instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateResponse=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} GetNullifiersBranchStateResponse instance + */ + GetNullifiersBranchStateResponse.create = function create(properties) { + return new GetNullifiersBranchStateResponse(properties); + }; + + /** + * Encodes the specified GetNullifiersBranchStateResponse message. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateResponse} message GetNullifiersBranchStateResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersBranchStateResponse.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetNullifiersBranchStateResponse message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateResponse} message GetNullifiersBranchStateResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersBranchStateResponse.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetNullifiersBranchStateResponse message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} GetNullifiersBranchStateResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersBranchStateResponse.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetNullifiersBranchStateResponse message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} GetNullifiersBranchStateResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersBranchStateResponse.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetNullifiersBranchStateResponse message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetNullifiersBranchStateResponse.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetNullifiersBranchStateResponse message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} GetNullifiersBranchStateResponse + */ + GetNullifiersBranchStateResponse.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetNullifiersBranchStateResponse message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} message GetNullifiersBranchStateResponse + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetNullifiersBranchStateResponse.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetNullifiersBranchStateResponse to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @instance + * @returns {Object.} JSON object + */ + GetNullifiersBranchStateResponse.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 = (function() { + + /** + * Properties of a GetNullifiersBranchStateResponseV0. + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @interface IGetNullifiersBranchStateResponseV0 + * @property {Uint8Array|null} [merkProof] GetNullifiersBranchStateResponseV0 merkProof + */ + + /** + * Constructs a new GetNullifiersBranchStateResponseV0. + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @classdesc Represents a GetNullifiersBranchStateResponseV0. + * @implements IGetNullifiersBranchStateResponseV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.IGetNullifiersBranchStateResponseV0=} [properties] Properties to set + */ + function GetNullifiersBranchStateResponseV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetNullifiersBranchStateResponseV0 merkProof. + * @member {Uint8Array} merkProof + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @instance + */ + GetNullifiersBranchStateResponseV0.prototype.merkProof = $util.newBuffer([]); + + /** + * Creates a new GetNullifiersBranchStateResponseV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.IGetNullifiersBranchStateResponseV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} GetNullifiersBranchStateResponseV0 instance + */ + GetNullifiersBranchStateResponseV0.create = function create(properties) { + return new GetNullifiersBranchStateResponseV0(properties); + }; + + /** + * Encodes the specified GetNullifiersBranchStateResponseV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.IGetNullifiersBranchStateResponseV0} message GetNullifiersBranchStateResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersBranchStateResponseV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.merkProof != null && Object.hasOwnProperty.call(message, "merkProof")) + writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.merkProof); + return writer; + }; + + /** + * Encodes the specified GetNullifiersBranchStateResponseV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.IGetNullifiersBranchStateResponseV0} message GetNullifiersBranchStateResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersBranchStateResponseV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetNullifiersBranchStateResponseV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} GetNullifiersBranchStateResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersBranchStateResponseV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 2: + message.merkProof = reader.bytes(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetNullifiersBranchStateResponseV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} GetNullifiersBranchStateResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersBranchStateResponseV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetNullifiersBranchStateResponseV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetNullifiersBranchStateResponseV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.merkProof != null && message.hasOwnProperty("merkProof")) + if (!(message.merkProof && typeof message.merkProof.length === "number" || $util.isString(message.merkProof))) + return "merkProof: buffer expected"; + return null; + }; + + /** + * Creates a GetNullifiersBranchStateResponseV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} GetNullifiersBranchStateResponseV0 + */ + GetNullifiersBranchStateResponseV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0(); + if (object.merkProof != null) + if (typeof object.merkProof === "string") + $util.base64.decode(object.merkProof, message.merkProof = $util.newBuffer($util.base64.length(object.merkProof)), 0); + else if (object.merkProof.length >= 0) + message.merkProof = object.merkProof; + return message; + }; + + /** + * Creates a plain object from a GetNullifiersBranchStateResponseV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} message GetNullifiersBranchStateResponseV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetNullifiersBranchStateResponseV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + if (options.bytes === String) + object.merkProof = ""; + else { + object.merkProof = []; + if (options.bytes !== Array) + object.merkProof = $util.newBuffer(object.merkProof); + } + if (message.merkProof != null && message.hasOwnProperty("merkProof")) + object.merkProof = options.bytes === String ? $util.base64.encode(message.merkProof, 0, message.merkProof.length) : options.bytes === Array ? Array.prototype.slice.call(message.merkProof) : message.merkProof; + return object; + }; + + /** + * Converts this GetNullifiersBranchStateResponseV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @instance + * @returns {Object.} JSON object + */ + GetNullifiersBranchStateResponseV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetNullifiersBranchStateResponseV0; + })(); + + return GetNullifiersBranchStateResponse; + })(); + + v0.BlockNullifierChanges = (function() { + + /** + * Properties of a BlockNullifierChanges. + * @memberof org.dash.platform.dapi.v0 + * @interface IBlockNullifierChanges + * @property {number|Long|null} [blockHeight] BlockNullifierChanges blockHeight + * @property {Array.|null} [nullifiers] BlockNullifierChanges nullifiers + */ + + /** + * Constructs a new BlockNullifierChanges. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a BlockNullifierChanges. + * @implements IBlockNullifierChanges + * @constructor + * @param {org.dash.platform.dapi.v0.IBlockNullifierChanges=} [properties] Properties to set + */ + function BlockNullifierChanges(properties) { + this.nullifiers = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * BlockNullifierChanges blockHeight. + * @member {number|Long} blockHeight + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @instance + */ + BlockNullifierChanges.prototype.blockHeight = $util.Long ? $util.Long.fromBits(0,0,true) : 0; + + /** + * BlockNullifierChanges nullifiers. + * @member {Array.} nullifiers + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @instance + */ + BlockNullifierChanges.prototype.nullifiers = $util.emptyArray; + + /** + * Creates a new BlockNullifierChanges instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @static + * @param {org.dash.platform.dapi.v0.IBlockNullifierChanges=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.BlockNullifierChanges} BlockNullifierChanges instance + */ + BlockNullifierChanges.create = function create(properties) { + return new BlockNullifierChanges(properties); + }; + + /** + * Encodes the specified BlockNullifierChanges message. Does not implicitly {@link org.dash.platform.dapi.v0.BlockNullifierChanges.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @static + * @param {org.dash.platform.dapi.v0.IBlockNullifierChanges} message BlockNullifierChanges message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + BlockNullifierChanges.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.blockHeight != null && Object.hasOwnProperty.call(message, "blockHeight")) + writer.uint32(/* id 1, wireType 0 =*/8).uint64(message.blockHeight); + if (message.nullifiers != null && message.nullifiers.length) + for (var i = 0; i < message.nullifiers.length; ++i) + writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.nullifiers[i]); + return writer; + }; + + /** + * Encodes the specified BlockNullifierChanges message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.BlockNullifierChanges.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @static + * @param {org.dash.platform.dapi.v0.IBlockNullifierChanges} message BlockNullifierChanges message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + BlockNullifierChanges.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a BlockNullifierChanges message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.BlockNullifierChanges} BlockNullifierChanges + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + BlockNullifierChanges.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.BlockNullifierChanges(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.blockHeight = reader.uint64(); + break; + case 2: + if (!(message.nullifiers && message.nullifiers.length)) + message.nullifiers = []; + message.nullifiers.push(reader.bytes()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a BlockNullifierChanges message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.BlockNullifierChanges} BlockNullifierChanges + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + BlockNullifierChanges.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a BlockNullifierChanges message. + * @function verify + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + BlockNullifierChanges.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.blockHeight != null && message.hasOwnProperty("blockHeight")) + if (!$util.isInteger(message.blockHeight) && !(message.blockHeight && $util.isInteger(message.blockHeight.low) && $util.isInteger(message.blockHeight.high))) + return "blockHeight: integer|Long expected"; + if (message.nullifiers != null && message.hasOwnProperty("nullifiers")) { + if (!Array.isArray(message.nullifiers)) + return "nullifiers: array expected"; + for (var i = 0; i < message.nullifiers.length; ++i) + if (!(message.nullifiers[i] && typeof message.nullifiers[i].length === "number" || $util.isString(message.nullifiers[i]))) + return "nullifiers: buffer[] expected"; + } + return null; + }; + + /** + * Creates a BlockNullifierChanges message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.BlockNullifierChanges} BlockNullifierChanges + */ + BlockNullifierChanges.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.BlockNullifierChanges) + return object; + var message = new $root.org.dash.platform.dapi.v0.BlockNullifierChanges(); + if (object.blockHeight != null) + if ($util.Long) + (message.blockHeight = $util.Long.fromValue(object.blockHeight)).unsigned = true; + else if (typeof object.blockHeight === "string") + message.blockHeight = parseInt(object.blockHeight, 10); + else if (typeof object.blockHeight === "number") + message.blockHeight = object.blockHeight; + else if (typeof object.blockHeight === "object") + message.blockHeight = new $util.LongBits(object.blockHeight.low >>> 0, object.blockHeight.high >>> 0).toNumber(true); + if (object.nullifiers) { + if (!Array.isArray(object.nullifiers)) + throw TypeError(".org.dash.platform.dapi.v0.BlockNullifierChanges.nullifiers: array expected"); + message.nullifiers = []; + for (var i = 0; i < object.nullifiers.length; ++i) + if (typeof object.nullifiers[i] === "string") + $util.base64.decode(object.nullifiers[i], message.nullifiers[i] = $util.newBuffer($util.base64.length(object.nullifiers[i])), 0); + else if (object.nullifiers[i].length >= 0) + message.nullifiers[i] = object.nullifiers[i]; + } + return message; + }; + + /** + * Creates a plain object from a BlockNullifierChanges message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @static + * @param {org.dash.platform.dapi.v0.BlockNullifierChanges} message BlockNullifierChanges + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + BlockNullifierChanges.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.nullifiers = []; + if (options.defaults) + if ($util.Long) { + var long = new $util.Long(0, 0, true); + object.blockHeight = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.blockHeight = options.longs === String ? "0" : 0; + if (message.blockHeight != null && message.hasOwnProperty("blockHeight")) + if (typeof message.blockHeight === "number") + object.blockHeight = options.longs === String ? String(message.blockHeight) : message.blockHeight; + else + object.blockHeight = options.longs === String ? $util.Long.prototype.toString.call(message.blockHeight) : options.longs === Number ? new $util.LongBits(message.blockHeight.low >>> 0, message.blockHeight.high >>> 0).toNumber(true) : message.blockHeight; + if (message.nullifiers && message.nullifiers.length) { + object.nullifiers = []; + for (var j = 0; j < message.nullifiers.length; ++j) + object.nullifiers[j] = options.bytes === String ? $util.base64.encode(message.nullifiers[j], 0, message.nullifiers[j].length) : options.bytes === Array ? Array.prototype.slice.call(message.nullifiers[j]) : message.nullifiers[j]; + } + return object; + }; + + /** + * Converts this BlockNullifierChanges to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @instance + * @returns {Object.} JSON object + */ + BlockNullifierChanges.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return BlockNullifierChanges; + })(); + + v0.NullifierUpdateEntries = (function() { + + /** + * Properties of a NullifierUpdateEntries. + * @memberof org.dash.platform.dapi.v0 + * @interface INullifierUpdateEntries + * @property {Array.|null} [blockChanges] NullifierUpdateEntries blockChanges + */ + + /** + * Constructs a new NullifierUpdateEntries. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a NullifierUpdateEntries. + * @implements INullifierUpdateEntries + * @constructor + * @param {org.dash.platform.dapi.v0.INullifierUpdateEntries=} [properties] Properties to set + */ + function NullifierUpdateEntries(properties) { + this.blockChanges = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * NullifierUpdateEntries blockChanges. + * @member {Array.} blockChanges + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @instance + */ + NullifierUpdateEntries.prototype.blockChanges = $util.emptyArray; + + /** + * Creates a new NullifierUpdateEntries instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @static + * @param {org.dash.platform.dapi.v0.INullifierUpdateEntries=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.NullifierUpdateEntries} NullifierUpdateEntries instance + */ + NullifierUpdateEntries.create = function create(properties) { + return new NullifierUpdateEntries(properties); + }; + + /** + * Encodes the specified NullifierUpdateEntries message. Does not implicitly {@link org.dash.platform.dapi.v0.NullifierUpdateEntries.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @static + * @param {org.dash.platform.dapi.v0.INullifierUpdateEntries} message NullifierUpdateEntries message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + NullifierUpdateEntries.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.blockChanges != null && message.blockChanges.length) + for (var i = 0; i < message.blockChanges.length; ++i) + $root.org.dash.platform.dapi.v0.BlockNullifierChanges.encode(message.blockChanges[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified NullifierUpdateEntries message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.NullifierUpdateEntries.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @static + * @param {org.dash.platform.dapi.v0.INullifierUpdateEntries} message NullifierUpdateEntries message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + NullifierUpdateEntries.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a NullifierUpdateEntries message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.NullifierUpdateEntries} NullifierUpdateEntries + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + NullifierUpdateEntries.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.NullifierUpdateEntries(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (!(message.blockChanges && message.blockChanges.length)) + message.blockChanges = []; + message.blockChanges.push($root.org.dash.platform.dapi.v0.BlockNullifierChanges.decode(reader, reader.uint32())); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a NullifierUpdateEntries message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.NullifierUpdateEntries} NullifierUpdateEntries + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + NullifierUpdateEntries.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a NullifierUpdateEntries message. + * @function verify + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + NullifierUpdateEntries.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.blockChanges != null && message.hasOwnProperty("blockChanges")) { + if (!Array.isArray(message.blockChanges)) + return "blockChanges: array expected"; + for (var i = 0; i < message.blockChanges.length; ++i) { + var error = $root.org.dash.platform.dapi.v0.BlockNullifierChanges.verify(message.blockChanges[i]); + if (error) + return "blockChanges." + error; + } + } + return null; + }; + + /** + * Creates a NullifierUpdateEntries message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.NullifierUpdateEntries} NullifierUpdateEntries + */ + NullifierUpdateEntries.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.NullifierUpdateEntries) + return object; + var message = new $root.org.dash.platform.dapi.v0.NullifierUpdateEntries(); + if (object.blockChanges) { + if (!Array.isArray(object.blockChanges)) + throw TypeError(".org.dash.platform.dapi.v0.NullifierUpdateEntries.blockChanges: array expected"); + message.blockChanges = []; + for (var i = 0; i < object.blockChanges.length; ++i) { + if (typeof object.blockChanges[i] !== "object") + throw TypeError(".org.dash.platform.dapi.v0.NullifierUpdateEntries.blockChanges: object expected"); + message.blockChanges[i] = $root.org.dash.platform.dapi.v0.BlockNullifierChanges.fromObject(object.blockChanges[i]); + } + } + return message; + }; + + /** + * Creates a plain object from a NullifierUpdateEntries message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @static + * @param {org.dash.platform.dapi.v0.NullifierUpdateEntries} message NullifierUpdateEntries + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + NullifierUpdateEntries.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.blockChanges = []; + if (message.blockChanges && message.blockChanges.length) { + object.blockChanges = []; + for (var j = 0; j < message.blockChanges.length; ++j) + object.blockChanges[j] = $root.org.dash.platform.dapi.v0.BlockNullifierChanges.toObject(message.blockChanges[j], options); + } + return object; + }; + + /** + * Converts this NullifierUpdateEntries to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @instance + * @returns {Object.} JSON object + */ + NullifierUpdateEntries.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return NullifierUpdateEntries; + })(); + + v0.GetRecentNullifierChangesRequest = (function() { + + /** + * Properties of a GetRecentNullifierChangesRequest. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetRecentNullifierChangesRequest + * @property {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.IGetRecentNullifierChangesRequestV0|null} [v0] GetRecentNullifierChangesRequest v0 + */ + + /** + * Constructs a new GetRecentNullifierChangesRequest. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetRecentNullifierChangesRequest. + * @implements IGetRecentNullifierChangesRequest + * @constructor + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesRequest=} [properties] Properties to set + */ + function GetRecentNullifierChangesRequest(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetRecentNullifierChangesRequest v0. + * @member {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.IGetRecentNullifierChangesRequestV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @instance + */ + GetRecentNullifierChangesRequest.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetRecentNullifierChangesRequest version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @instance + */ + Object.defineProperty(GetRecentNullifierChangesRequest.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetRecentNullifierChangesRequest instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesRequest=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} GetRecentNullifierChangesRequest instance + */ + GetRecentNullifierChangesRequest.create = function create(properties) { + return new GetRecentNullifierChangesRequest(properties); + }; + + /** + * Encodes the specified GetRecentNullifierChangesRequest message. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesRequest} message GetRecentNullifierChangesRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentNullifierChangesRequest.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetRecentNullifierChangesRequest message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesRequest} message GetRecentNullifierChangesRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentNullifierChangesRequest.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetRecentNullifierChangesRequest message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} GetRecentNullifierChangesRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentNullifierChangesRequest.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetRecentNullifierChangesRequest message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} GetRecentNullifierChangesRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentNullifierChangesRequest.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetRecentNullifierChangesRequest message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetRecentNullifierChangesRequest.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetRecentNullifierChangesRequest message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} GetRecentNullifierChangesRequest + */ + GetRecentNullifierChangesRequest.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetRecentNullifierChangesRequest message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} message GetRecentNullifierChangesRequest + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetRecentNullifierChangesRequest.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetRecentNullifierChangesRequest to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @instance + * @returns {Object.} JSON object + */ + GetRecentNullifierChangesRequest.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 = (function() { + + /** + * Properties of a GetRecentNullifierChangesRequestV0. + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @interface IGetRecentNullifierChangesRequestV0 + * @property {number|Long|null} [startHeight] GetRecentNullifierChangesRequestV0 startHeight + * @property {boolean|null} [prove] GetRecentNullifierChangesRequestV0 prove + */ + + /** + * Constructs a new GetRecentNullifierChangesRequestV0. + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @classdesc Represents a GetRecentNullifierChangesRequestV0. + * @implements IGetRecentNullifierChangesRequestV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.IGetRecentNullifierChangesRequestV0=} [properties] Properties to set + */ + function GetRecentNullifierChangesRequestV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetRecentNullifierChangesRequestV0 startHeight. + * @member {number|Long} startHeight + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @instance + */ + GetRecentNullifierChangesRequestV0.prototype.startHeight = $util.Long ? $util.Long.fromBits(0,0,true) : 0; + + /** + * GetRecentNullifierChangesRequestV0 prove. + * @member {boolean} prove + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @instance + */ + GetRecentNullifierChangesRequestV0.prototype.prove = false; + + /** + * Creates a new GetRecentNullifierChangesRequestV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.IGetRecentNullifierChangesRequestV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} GetRecentNullifierChangesRequestV0 instance + */ + GetRecentNullifierChangesRequestV0.create = function create(properties) { + return new GetRecentNullifierChangesRequestV0(properties); + }; + + /** + * Encodes the specified GetRecentNullifierChangesRequestV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.IGetRecentNullifierChangesRequestV0} message GetRecentNullifierChangesRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentNullifierChangesRequestV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.startHeight != null && Object.hasOwnProperty.call(message, "startHeight")) + writer.uint32(/* id 1, wireType 0 =*/8).uint64(message.startHeight); + if (message.prove != null && Object.hasOwnProperty.call(message, "prove")) + writer.uint32(/* id 2, wireType 0 =*/16).bool(message.prove); + return writer; + }; + + /** + * Encodes the specified GetRecentNullifierChangesRequestV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.IGetRecentNullifierChangesRequestV0} message GetRecentNullifierChangesRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentNullifierChangesRequestV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetRecentNullifierChangesRequestV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} GetRecentNullifierChangesRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentNullifierChangesRequestV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.startHeight = reader.uint64(); + break; + case 2: + message.prove = reader.bool(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetRecentNullifierChangesRequestV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} GetRecentNullifierChangesRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentNullifierChangesRequestV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetRecentNullifierChangesRequestV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetRecentNullifierChangesRequestV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.startHeight != null && message.hasOwnProperty("startHeight")) + if (!$util.isInteger(message.startHeight) && !(message.startHeight && $util.isInteger(message.startHeight.low) && $util.isInteger(message.startHeight.high))) + return "startHeight: integer|Long expected"; + if (message.prove != null && message.hasOwnProperty("prove")) + if (typeof message.prove !== "boolean") + return "prove: boolean expected"; + return null; + }; + + /** + * Creates a GetRecentNullifierChangesRequestV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} GetRecentNullifierChangesRequestV0 + */ + GetRecentNullifierChangesRequestV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0(); + if (object.startHeight != null) + if ($util.Long) + (message.startHeight = $util.Long.fromValue(object.startHeight)).unsigned = true; + else if (typeof object.startHeight === "string") + message.startHeight = parseInt(object.startHeight, 10); + else if (typeof object.startHeight === "number") + message.startHeight = object.startHeight; + else if (typeof object.startHeight === "object") + message.startHeight = new $util.LongBits(object.startHeight.low >>> 0, object.startHeight.high >>> 0).toNumber(true); + if (object.prove != null) + message.prove = Boolean(object.prove); + return message; + }; + + /** + * Creates a plain object from a GetRecentNullifierChangesRequestV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} message GetRecentNullifierChangesRequestV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetRecentNullifierChangesRequestV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + if ($util.Long) { + var long = new $util.Long(0, 0, true); + object.startHeight = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.startHeight = options.longs === String ? "0" : 0; + object.prove = false; + } + if (message.startHeight != null && message.hasOwnProperty("startHeight")) + if (typeof message.startHeight === "number") + object.startHeight = options.longs === String ? String(message.startHeight) : message.startHeight; + else + object.startHeight = options.longs === String ? $util.Long.prototype.toString.call(message.startHeight) : options.longs === Number ? new $util.LongBits(message.startHeight.low >>> 0, message.startHeight.high >>> 0).toNumber(true) : message.startHeight; + if (message.prove != null && message.hasOwnProperty("prove")) + object.prove = message.prove; + return object; + }; + + /** + * Converts this GetRecentNullifierChangesRequestV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @instance + * @returns {Object.} JSON object + */ + GetRecentNullifierChangesRequestV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetRecentNullifierChangesRequestV0; + })(); + + return GetRecentNullifierChangesRequest; + })(); + + v0.GetRecentNullifierChangesResponse = (function() { + + /** + * Properties of a GetRecentNullifierChangesResponse. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetRecentNullifierChangesResponse + * @property {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.IGetRecentNullifierChangesResponseV0|null} [v0] GetRecentNullifierChangesResponse v0 + */ + + /** + * Constructs a new GetRecentNullifierChangesResponse. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetRecentNullifierChangesResponse. + * @implements IGetRecentNullifierChangesResponse + * @constructor + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesResponse=} [properties] Properties to set + */ + function GetRecentNullifierChangesResponse(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetRecentNullifierChangesResponse v0. + * @member {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.IGetRecentNullifierChangesResponseV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @instance + */ + GetRecentNullifierChangesResponse.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetRecentNullifierChangesResponse version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @instance + */ + Object.defineProperty(GetRecentNullifierChangesResponse.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetRecentNullifierChangesResponse instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesResponse=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} GetRecentNullifierChangesResponse instance + */ + GetRecentNullifierChangesResponse.create = function create(properties) { + return new GetRecentNullifierChangesResponse(properties); + }; + + /** + * Encodes the specified GetRecentNullifierChangesResponse message. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesResponse} message GetRecentNullifierChangesResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentNullifierChangesResponse.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetRecentNullifierChangesResponse message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesResponse} message GetRecentNullifierChangesResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentNullifierChangesResponse.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetRecentNullifierChangesResponse message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} GetRecentNullifierChangesResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentNullifierChangesResponse.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetRecentNullifierChangesResponse message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} GetRecentNullifierChangesResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentNullifierChangesResponse.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetRecentNullifierChangesResponse message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetRecentNullifierChangesResponse.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetRecentNullifierChangesResponse message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} GetRecentNullifierChangesResponse + */ + GetRecentNullifierChangesResponse.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetRecentNullifierChangesResponse message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} message GetRecentNullifierChangesResponse + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetRecentNullifierChangesResponse.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetRecentNullifierChangesResponse to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @instance + * @returns {Object.} JSON object + */ + GetRecentNullifierChangesResponse.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 = (function() { + + /** + * Properties of a GetRecentNullifierChangesResponseV0. + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @interface IGetRecentNullifierChangesResponseV0 + * @property {org.dash.platform.dapi.v0.INullifierUpdateEntries|null} [nullifierUpdateEntries] GetRecentNullifierChangesResponseV0 nullifierUpdateEntries + * @property {org.dash.platform.dapi.v0.IProof|null} [proof] GetRecentNullifierChangesResponseV0 proof + * @property {org.dash.platform.dapi.v0.IResponseMetadata|null} [metadata] GetRecentNullifierChangesResponseV0 metadata + */ + + /** + * Constructs a new GetRecentNullifierChangesResponseV0. + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @classdesc Represents a GetRecentNullifierChangesResponseV0. + * @implements IGetRecentNullifierChangesResponseV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.IGetRecentNullifierChangesResponseV0=} [properties] Properties to set + */ + function GetRecentNullifierChangesResponseV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetRecentNullifierChangesResponseV0 nullifierUpdateEntries. + * @member {org.dash.platform.dapi.v0.INullifierUpdateEntries|null|undefined} nullifierUpdateEntries + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @instance + */ + GetRecentNullifierChangesResponseV0.prototype.nullifierUpdateEntries = null; + + /** + * GetRecentNullifierChangesResponseV0 proof. + * @member {org.dash.platform.dapi.v0.IProof|null|undefined} proof + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @instance + */ + GetRecentNullifierChangesResponseV0.prototype.proof = null; + + /** + * GetRecentNullifierChangesResponseV0 metadata. + * @member {org.dash.platform.dapi.v0.IResponseMetadata|null|undefined} metadata + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @instance + */ + GetRecentNullifierChangesResponseV0.prototype.metadata = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetRecentNullifierChangesResponseV0 result. + * @member {"nullifierUpdateEntries"|"proof"|undefined} result + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @instance + */ + Object.defineProperty(GetRecentNullifierChangesResponseV0.prototype, "result", { + get: $util.oneOfGetter($oneOfFields = ["nullifierUpdateEntries", "proof"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetRecentNullifierChangesResponseV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.IGetRecentNullifierChangesResponseV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} GetRecentNullifierChangesResponseV0 instance + */ + GetRecentNullifierChangesResponseV0.create = function create(properties) { + return new GetRecentNullifierChangesResponseV0(properties); + }; + + /** + * Encodes the specified GetRecentNullifierChangesResponseV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.IGetRecentNullifierChangesResponseV0} message GetRecentNullifierChangesResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentNullifierChangesResponseV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.nullifierUpdateEntries != null && Object.hasOwnProperty.call(message, "nullifierUpdateEntries")) + $root.org.dash.platform.dapi.v0.NullifierUpdateEntries.encode(message.nullifierUpdateEntries, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + if (message.proof != null && Object.hasOwnProperty.call(message, "proof")) + $root.org.dash.platform.dapi.v0.Proof.encode(message.proof, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + if (message.metadata != null && Object.hasOwnProperty.call(message, "metadata")) + $root.org.dash.platform.dapi.v0.ResponseMetadata.encode(message.metadata, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetRecentNullifierChangesResponseV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.IGetRecentNullifierChangesResponseV0} message GetRecentNullifierChangesResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentNullifierChangesResponseV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetRecentNullifierChangesResponseV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} GetRecentNullifierChangesResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentNullifierChangesResponseV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.nullifierUpdateEntries = $root.org.dash.platform.dapi.v0.NullifierUpdateEntries.decode(reader, reader.uint32()); + break; + case 2: + message.proof = $root.org.dash.platform.dapi.v0.Proof.decode(reader, reader.uint32()); + break; + case 3: + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetRecentNullifierChangesResponseV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} GetRecentNullifierChangesResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentNullifierChangesResponseV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetRecentNullifierChangesResponseV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetRecentNullifierChangesResponseV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.nullifierUpdateEntries != null && message.hasOwnProperty("nullifierUpdateEntries")) { + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.NullifierUpdateEntries.verify(message.nullifierUpdateEntries); + if (error) + return "nullifierUpdateEntries." + error; + } + } + if (message.proof != null && message.hasOwnProperty("proof")) { + if (properties.result === 1) + return "result: multiple values"; + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.Proof.verify(message.proof); + if (error) + return "proof." + error; + } + } + if (message.metadata != null && message.hasOwnProperty("metadata")) { + var error = $root.org.dash.platform.dapi.v0.ResponseMetadata.verify(message.metadata); + if (error) + return "metadata." + error; + } + return null; + }; + + /** + * Creates a GetRecentNullifierChangesResponseV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} GetRecentNullifierChangesResponseV0 + */ + GetRecentNullifierChangesResponseV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0(); + if (object.nullifierUpdateEntries != null) { + if (typeof object.nullifierUpdateEntries !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.nullifierUpdateEntries: object expected"); + message.nullifierUpdateEntries = $root.org.dash.platform.dapi.v0.NullifierUpdateEntries.fromObject(object.nullifierUpdateEntries); + } + if (object.proof != null) { + if (typeof object.proof !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.proof: object expected"); + message.proof = $root.org.dash.platform.dapi.v0.Proof.fromObject(object.proof); + } + if (object.metadata != null) { + if (typeof object.metadata !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.metadata: object expected"); + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.fromObject(object.metadata); + } + return message; + }; + + /** + * Creates a plain object from a GetRecentNullifierChangesResponseV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} message GetRecentNullifierChangesResponseV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetRecentNullifierChangesResponseV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.metadata = null; + if (message.nullifierUpdateEntries != null && message.hasOwnProperty("nullifierUpdateEntries")) { + object.nullifierUpdateEntries = $root.org.dash.platform.dapi.v0.NullifierUpdateEntries.toObject(message.nullifierUpdateEntries, options); + if (options.oneofs) + object.result = "nullifierUpdateEntries"; + } + if (message.proof != null && message.hasOwnProperty("proof")) { + object.proof = $root.org.dash.platform.dapi.v0.Proof.toObject(message.proof, options); + if (options.oneofs) + object.result = "proof"; + } + if (message.metadata != null && message.hasOwnProperty("metadata")) + object.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.toObject(message.metadata, options); + return object; + }; + + /** + * Converts this GetRecentNullifierChangesResponseV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @instance + * @returns {Object.} JSON object + */ + GetRecentNullifierChangesResponseV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetRecentNullifierChangesResponseV0; + })(); + + return GetRecentNullifierChangesResponse; + })(); + + v0.CompactedBlockNullifierChanges = (function() { + + /** + * Properties of a CompactedBlockNullifierChanges. + * @memberof org.dash.platform.dapi.v0 + * @interface ICompactedBlockNullifierChanges + * @property {number|Long|null} [startBlockHeight] CompactedBlockNullifierChanges startBlockHeight + * @property {number|Long|null} [endBlockHeight] CompactedBlockNullifierChanges endBlockHeight + * @property {Array.|null} [nullifiers] CompactedBlockNullifierChanges nullifiers + */ + + /** + * Constructs a new CompactedBlockNullifierChanges. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a CompactedBlockNullifierChanges. + * @implements ICompactedBlockNullifierChanges + * @constructor + * @param {org.dash.platform.dapi.v0.ICompactedBlockNullifierChanges=} [properties] Properties to set + */ + function CompactedBlockNullifierChanges(properties) { + this.nullifiers = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * CompactedBlockNullifierChanges startBlockHeight. + * @member {number|Long} startBlockHeight + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @instance + */ + CompactedBlockNullifierChanges.prototype.startBlockHeight = $util.Long ? $util.Long.fromBits(0,0,true) : 0; + + /** + * CompactedBlockNullifierChanges endBlockHeight. + * @member {number|Long} endBlockHeight + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @instance + */ + CompactedBlockNullifierChanges.prototype.endBlockHeight = $util.Long ? $util.Long.fromBits(0,0,true) : 0; + + /** + * CompactedBlockNullifierChanges nullifiers. + * @member {Array.} nullifiers + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @instance + */ + CompactedBlockNullifierChanges.prototype.nullifiers = $util.emptyArray; + + /** + * Creates a new CompactedBlockNullifierChanges instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @static + * @param {org.dash.platform.dapi.v0.ICompactedBlockNullifierChanges=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} CompactedBlockNullifierChanges instance + */ + CompactedBlockNullifierChanges.create = function create(properties) { + return new CompactedBlockNullifierChanges(properties); + }; + + /** + * Encodes the specified CompactedBlockNullifierChanges message. Does not implicitly {@link org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @static + * @param {org.dash.platform.dapi.v0.ICompactedBlockNullifierChanges} message CompactedBlockNullifierChanges message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + CompactedBlockNullifierChanges.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.startBlockHeight != null && Object.hasOwnProperty.call(message, "startBlockHeight")) + writer.uint32(/* id 1, wireType 0 =*/8).uint64(message.startBlockHeight); + if (message.endBlockHeight != null && Object.hasOwnProperty.call(message, "endBlockHeight")) + writer.uint32(/* id 2, wireType 0 =*/16).uint64(message.endBlockHeight); + if (message.nullifiers != null && message.nullifiers.length) + for (var i = 0; i < message.nullifiers.length; ++i) + writer.uint32(/* id 3, wireType 2 =*/26).bytes(message.nullifiers[i]); + return writer; + }; + + /** + * Encodes the specified CompactedBlockNullifierChanges message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @static + * @param {org.dash.platform.dapi.v0.ICompactedBlockNullifierChanges} message CompactedBlockNullifierChanges message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + CompactedBlockNullifierChanges.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a CompactedBlockNullifierChanges message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} CompactedBlockNullifierChanges + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + CompactedBlockNullifierChanges.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.startBlockHeight = reader.uint64(); + break; + case 2: + message.endBlockHeight = reader.uint64(); + break; + case 3: + if (!(message.nullifiers && message.nullifiers.length)) + message.nullifiers = []; + message.nullifiers.push(reader.bytes()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a CompactedBlockNullifierChanges message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} CompactedBlockNullifierChanges + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + CompactedBlockNullifierChanges.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a CompactedBlockNullifierChanges message. + * @function verify + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + CompactedBlockNullifierChanges.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.startBlockHeight != null && message.hasOwnProperty("startBlockHeight")) + if (!$util.isInteger(message.startBlockHeight) && !(message.startBlockHeight && $util.isInteger(message.startBlockHeight.low) && $util.isInteger(message.startBlockHeight.high))) + return "startBlockHeight: integer|Long expected"; + if (message.endBlockHeight != null && message.hasOwnProperty("endBlockHeight")) + if (!$util.isInteger(message.endBlockHeight) && !(message.endBlockHeight && $util.isInteger(message.endBlockHeight.low) && $util.isInteger(message.endBlockHeight.high))) + return "endBlockHeight: integer|Long expected"; + if (message.nullifiers != null && message.hasOwnProperty("nullifiers")) { + if (!Array.isArray(message.nullifiers)) + return "nullifiers: array expected"; + for (var i = 0; i < message.nullifiers.length; ++i) + if (!(message.nullifiers[i] && typeof message.nullifiers[i].length === "number" || $util.isString(message.nullifiers[i]))) + return "nullifiers: buffer[] expected"; + } + return null; + }; + + /** + * Creates a CompactedBlockNullifierChanges message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} CompactedBlockNullifierChanges + */ + CompactedBlockNullifierChanges.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges) + return object; + var message = new $root.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges(); + if (object.startBlockHeight != null) + if ($util.Long) + (message.startBlockHeight = $util.Long.fromValue(object.startBlockHeight)).unsigned = true; + else if (typeof object.startBlockHeight === "string") + message.startBlockHeight = parseInt(object.startBlockHeight, 10); + else if (typeof object.startBlockHeight === "number") + message.startBlockHeight = object.startBlockHeight; + else if (typeof object.startBlockHeight === "object") + message.startBlockHeight = new $util.LongBits(object.startBlockHeight.low >>> 0, object.startBlockHeight.high >>> 0).toNumber(true); + if (object.endBlockHeight != null) + if ($util.Long) + (message.endBlockHeight = $util.Long.fromValue(object.endBlockHeight)).unsigned = true; + else if (typeof object.endBlockHeight === "string") + message.endBlockHeight = parseInt(object.endBlockHeight, 10); + else if (typeof object.endBlockHeight === "number") + message.endBlockHeight = object.endBlockHeight; + else if (typeof object.endBlockHeight === "object") + message.endBlockHeight = new $util.LongBits(object.endBlockHeight.low >>> 0, object.endBlockHeight.high >>> 0).toNumber(true); + if (object.nullifiers) { + if (!Array.isArray(object.nullifiers)) + throw TypeError(".org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.nullifiers: array expected"); + message.nullifiers = []; + for (var i = 0; i < object.nullifiers.length; ++i) + if (typeof object.nullifiers[i] === "string") + $util.base64.decode(object.nullifiers[i], message.nullifiers[i] = $util.newBuffer($util.base64.length(object.nullifiers[i])), 0); + else if (object.nullifiers[i].length >= 0) + message.nullifiers[i] = object.nullifiers[i]; + } + return message; + }; + + /** + * Creates a plain object from a CompactedBlockNullifierChanges message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @static + * @param {org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} message CompactedBlockNullifierChanges + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + CompactedBlockNullifierChanges.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.nullifiers = []; + if (options.defaults) { + if ($util.Long) { + var long = new $util.Long(0, 0, true); + object.startBlockHeight = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.startBlockHeight = options.longs === String ? "0" : 0; + if ($util.Long) { + var long = new $util.Long(0, 0, true); + object.endBlockHeight = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.endBlockHeight = options.longs === String ? "0" : 0; + } + if (message.startBlockHeight != null && message.hasOwnProperty("startBlockHeight")) + if (typeof message.startBlockHeight === "number") + object.startBlockHeight = options.longs === String ? String(message.startBlockHeight) : message.startBlockHeight; + else + object.startBlockHeight = options.longs === String ? $util.Long.prototype.toString.call(message.startBlockHeight) : options.longs === Number ? new $util.LongBits(message.startBlockHeight.low >>> 0, message.startBlockHeight.high >>> 0).toNumber(true) : message.startBlockHeight; + if (message.endBlockHeight != null && message.hasOwnProperty("endBlockHeight")) + if (typeof message.endBlockHeight === "number") + object.endBlockHeight = options.longs === String ? String(message.endBlockHeight) : message.endBlockHeight; + else + object.endBlockHeight = options.longs === String ? $util.Long.prototype.toString.call(message.endBlockHeight) : options.longs === Number ? new $util.LongBits(message.endBlockHeight.low >>> 0, message.endBlockHeight.high >>> 0).toNumber(true) : message.endBlockHeight; + if (message.nullifiers && message.nullifiers.length) { + object.nullifiers = []; + for (var j = 0; j < message.nullifiers.length; ++j) + object.nullifiers[j] = options.bytes === String ? $util.base64.encode(message.nullifiers[j], 0, message.nullifiers[j].length) : options.bytes === Array ? Array.prototype.slice.call(message.nullifiers[j]) : message.nullifiers[j]; + } + return object; + }; + + /** + * Converts this CompactedBlockNullifierChanges to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @instance + * @returns {Object.} JSON object + */ + CompactedBlockNullifierChanges.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return CompactedBlockNullifierChanges; + })(); + + v0.CompactedNullifierUpdateEntries = (function() { + + /** + * Properties of a CompactedNullifierUpdateEntries. + * @memberof org.dash.platform.dapi.v0 + * @interface ICompactedNullifierUpdateEntries + * @property {Array.|null} [compactedBlockChanges] CompactedNullifierUpdateEntries compactedBlockChanges + */ + + /** + * Constructs a new CompactedNullifierUpdateEntries. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a CompactedNullifierUpdateEntries. + * @implements ICompactedNullifierUpdateEntries + * @constructor + * @param {org.dash.platform.dapi.v0.ICompactedNullifierUpdateEntries=} [properties] Properties to set + */ + function CompactedNullifierUpdateEntries(properties) { + this.compactedBlockChanges = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * CompactedNullifierUpdateEntries compactedBlockChanges. + * @member {Array.} compactedBlockChanges + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @instance + */ + CompactedNullifierUpdateEntries.prototype.compactedBlockChanges = $util.emptyArray; + + /** + * Creates a new CompactedNullifierUpdateEntries instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @static + * @param {org.dash.platform.dapi.v0.ICompactedNullifierUpdateEntries=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} CompactedNullifierUpdateEntries instance + */ + CompactedNullifierUpdateEntries.create = function create(properties) { + return new CompactedNullifierUpdateEntries(properties); + }; + + /** + * Encodes the specified CompactedNullifierUpdateEntries message. Does not implicitly {@link org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @static + * @param {org.dash.platform.dapi.v0.ICompactedNullifierUpdateEntries} message CompactedNullifierUpdateEntries message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + CompactedNullifierUpdateEntries.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.compactedBlockChanges != null && message.compactedBlockChanges.length) + for (var i = 0; i < message.compactedBlockChanges.length; ++i) + $root.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.encode(message.compactedBlockChanges[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified CompactedNullifierUpdateEntries message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @static + * @param {org.dash.platform.dapi.v0.ICompactedNullifierUpdateEntries} message CompactedNullifierUpdateEntries message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + CompactedNullifierUpdateEntries.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a CompactedNullifierUpdateEntries message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} CompactedNullifierUpdateEntries + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + CompactedNullifierUpdateEntries.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (!(message.compactedBlockChanges && message.compactedBlockChanges.length)) + message.compactedBlockChanges = []; + message.compactedBlockChanges.push($root.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.decode(reader, reader.uint32())); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a CompactedNullifierUpdateEntries message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} CompactedNullifierUpdateEntries + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + CompactedNullifierUpdateEntries.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a CompactedNullifierUpdateEntries message. + * @function verify + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + CompactedNullifierUpdateEntries.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.compactedBlockChanges != null && message.hasOwnProperty("compactedBlockChanges")) { + if (!Array.isArray(message.compactedBlockChanges)) + return "compactedBlockChanges: array expected"; + for (var i = 0; i < message.compactedBlockChanges.length; ++i) { + var error = $root.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.verify(message.compactedBlockChanges[i]); + if (error) + return "compactedBlockChanges." + error; + } + } + return null; + }; + + /** + * Creates a CompactedNullifierUpdateEntries message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} CompactedNullifierUpdateEntries + */ + CompactedNullifierUpdateEntries.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries) + return object; + var message = new $root.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries(); + if (object.compactedBlockChanges) { + if (!Array.isArray(object.compactedBlockChanges)) + throw TypeError(".org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.compactedBlockChanges: array expected"); + message.compactedBlockChanges = []; + for (var i = 0; i < object.compactedBlockChanges.length; ++i) { + if (typeof object.compactedBlockChanges[i] !== "object") + throw TypeError(".org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.compactedBlockChanges: object expected"); + message.compactedBlockChanges[i] = $root.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.fromObject(object.compactedBlockChanges[i]); + } + } + return message; + }; + + /** + * Creates a plain object from a CompactedNullifierUpdateEntries message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @static + * @param {org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} message CompactedNullifierUpdateEntries + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + CompactedNullifierUpdateEntries.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.compactedBlockChanges = []; + if (message.compactedBlockChanges && message.compactedBlockChanges.length) { + object.compactedBlockChanges = []; + for (var j = 0; j < message.compactedBlockChanges.length; ++j) + object.compactedBlockChanges[j] = $root.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.toObject(message.compactedBlockChanges[j], options); + } + return object; + }; + + /** + * Converts this CompactedNullifierUpdateEntries to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @instance + * @returns {Object.} JSON object + */ + CompactedNullifierUpdateEntries.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return CompactedNullifierUpdateEntries; + })(); + + v0.GetRecentCompactedNullifierChangesRequest = (function() { + + /** + * Properties of a GetRecentCompactedNullifierChangesRequest. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetRecentCompactedNullifierChangesRequest + * @property {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.IGetRecentCompactedNullifierChangesRequestV0|null} [v0] GetRecentCompactedNullifierChangesRequest v0 + */ + + /** + * Constructs a new GetRecentCompactedNullifierChangesRequest. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetRecentCompactedNullifierChangesRequest. + * @implements IGetRecentCompactedNullifierChangesRequest + * @constructor + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesRequest=} [properties] Properties to set + */ + function GetRecentCompactedNullifierChangesRequest(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetRecentCompactedNullifierChangesRequest v0. + * @member {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.IGetRecentCompactedNullifierChangesRequestV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @instance + */ + GetRecentCompactedNullifierChangesRequest.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetRecentCompactedNullifierChangesRequest version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @instance + */ + Object.defineProperty(GetRecentCompactedNullifierChangesRequest.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetRecentCompactedNullifierChangesRequest instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesRequest=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} GetRecentCompactedNullifierChangesRequest instance + */ + GetRecentCompactedNullifierChangesRequest.create = function create(properties) { + return new GetRecentCompactedNullifierChangesRequest(properties); + }; + + /** + * Encodes the specified GetRecentCompactedNullifierChangesRequest message. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesRequest} message GetRecentCompactedNullifierChangesRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentCompactedNullifierChangesRequest.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetRecentCompactedNullifierChangesRequest message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesRequest} message GetRecentCompactedNullifierChangesRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentCompactedNullifierChangesRequest.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetRecentCompactedNullifierChangesRequest message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} GetRecentCompactedNullifierChangesRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentCompactedNullifierChangesRequest.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetRecentCompactedNullifierChangesRequest message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} GetRecentCompactedNullifierChangesRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentCompactedNullifierChangesRequest.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetRecentCompactedNullifierChangesRequest message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetRecentCompactedNullifierChangesRequest.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetRecentCompactedNullifierChangesRequest message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} GetRecentCompactedNullifierChangesRequest + */ + GetRecentCompactedNullifierChangesRequest.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetRecentCompactedNullifierChangesRequest message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} message GetRecentCompactedNullifierChangesRequest + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetRecentCompactedNullifierChangesRequest.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetRecentCompactedNullifierChangesRequest to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @instance + * @returns {Object.} JSON object + */ + GetRecentCompactedNullifierChangesRequest.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 = (function() { + + /** + * Properties of a GetRecentCompactedNullifierChangesRequestV0. + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @interface IGetRecentCompactedNullifierChangesRequestV0 + * @property {number|Long|null} [startBlockHeight] GetRecentCompactedNullifierChangesRequestV0 startBlockHeight + * @property {boolean|null} [prove] GetRecentCompactedNullifierChangesRequestV0 prove + */ + + /** + * Constructs a new GetRecentCompactedNullifierChangesRequestV0. + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @classdesc Represents a GetRecentCompactedNullifierChangesRequestV0. + * @implements IGetRecentCompactedNullifierChangesRequestV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.IGetRecentCompactedNullifierChangesRequestV0=} [properties] Properties to set + */ + function GetRecentCompactedNullifierChangesRequestV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetRecentCompactedNullifierChangesRequestV0 startBlockHeight. + * @member {number|Long} startBlockHeight + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @instance + */ + GetRecentCompactedNullifierChangesRequestV0.prototype.startBlockHeight = $util.Long ? $util.Long.fromBits(0,0,true) : 0; + + /** + * GetRecentCompactedNullifierChangesRequestV0 prove. + * @member {boolean} prove + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @instance + */ + GetRecentCompactedNullifierChangesRequestV0.prototype.prove = false; + + /** + * Creates a new GetRecentCompactedNullifierChangesRequestV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.IGetRecentCompactedNullifierChangesRequestV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} GetRecentCompactedNullifierChangesRequestV0 instance + */ + GetRecentCompactedNullifierChangesRequestV0.create = function create(properties) { + return new GetRecentCompactedNullifierChangesRequestV0(properties); + }; + + /** + * Encodes the specified GetRecentCompactedNullifierChangesRequestV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.IGetRecentCompactedNullifierChangesRequestV0} message GetRecentCompactedNullifierChangesRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentCompactedNullifierChangesRequestV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.startBlockHeight != null && Object.hasOwnProperty.call(message, "startBlockHeight")) + writer.uint32(/* id 1, wireType 0 =*/8).uint64(message.startBlockHeight); + if (message.prove != null && Object.hasOwnProperty.call(message, "prove")) + writer.uint32(/* id 2, wireType 0 =*/16).bool(message.prove); + return writer; + }; + + /** + * Encodes the specified GetRecentCompactedNullifierChangesRequestV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.IGetRecentCompactedNullifierChangesRequestV0} message GetRecentCompactedNullifierChangesRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentCompactedNullifierChangesRequestV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetRecentCompactedNullifierChangesRequestV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} GetRecentCompactedNullifierChangesRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentCompactedNullifierChangesRequestV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.startBlockHeight = reader.uint64(); + break; + case 2: + message.prove = reader.bool(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetRecentCompactedNullifierChangesRequestV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} GetRecentCompactedNullifierChangesRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentCompactedNullifierChangesRequestV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetRecentCompactedNullifierChangesRequestV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetRecentCompactedNullifierChangesRequestV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.startBlockHeight != null && message.hasOwnProperty("startBlockHeight")) + if (!$util.isInteger(message.startBlockHeight) && !(message.startBlockHeight && $util.isInteger(message.startBlockHeight.low) && $util.isInteger(message.startBlockHeight.high))) + return "startBlockHeight: integer|Long expected"; + if (message.prove != null && message.hasOwnProperty("prove")) + if (typeof message.prove !== "boolean") + return "prove: boolean expected"; + return null; + }; + + /** + * Creates a GetRecentCompactedNullifierChangesRequestV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} GetRecentCompactedNullifierChangesRequestV0 + */ + GetRecentCompactedNullifierChangesRequestV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0(); + if (object.startBlockHeight != null) + if ($util.Long) + (message.startBlockHeight = $util.Long.fromValue(object.startBlockHeight)).unsigned = true; + else if (typeof object.startBlockHeight === "string") + message.startBlockHeight = parseInt(object.startBlockHeight, 10); + else if (typeof object.startBlockHeight === "number") + message.startBlockHeight = object.startBlockHeight; + else if (typeof object.startBlockHeight === "object") + message.startBlockHeight = new $util.LongBits(object.startBlockHeight.low >>> 0, object.startBlockHeight.high >>> 0).toNumber(true); + if (object.prove != null) + message.prove = Boolean(object.prove); + return message; + }; + + /** + * Creates a plain object from a GetRecentCompactedNullifierChangesRequestV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} message GetRecentCompactedNullifierChangesRequestV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetRecentCompactedNullifierChangesRequestV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + if ($util.Long) { + var long = new $util.Long(0, 0, true); + object.startBlockHeight = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.startBlockHeight = options.longs === String ? "0" : 0; + object.prove = false; + } + if (message.startBlockHeight != null && message.hasOwnProperty("startBlockHeight")) + if (typeof message.startBlockHeight === "number") + object.startBlockHeight = options.longs === String ? String(message.startBlockHeight) : message.startBlockHeight; + else + object.startBlockHeight = options.longs === String ? $util.Long.prototype.toString.call(message.startBlockHeight) : options.longs === Number ? new $util.LongBits(message.startBlockHeight.low >>> 0, message.startBlockHeight.high >>> 0).toNumber(true) : message.startBlockHeight; + if (message.prove != null && message.hasOwnProperty("prove")) + object.prove = message.prove; + return object; + }; + + /** + * Converts this GetRecentCompactedNullifierChangesRequestV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @instance + * @returns {Object.} JSON object + */ + GetRecentCompactedNullifierChangesRequestV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetRecentCompactedNullifierChangesRequestV0; + })(); + + return GetRecentCompactedNullifierChangesRequest; + })(); + + v0.GetRecentCompactedNullifierChangesResponse = (function() { + + /** + * Properties of a GetRecentCompactedNullifierChangesResponse. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetRecentCompactedNullifierChangesResponse + * @property {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.IGetRecentCompactedNullifierChangesResponseV0|null} [v0] GetRecentCompactedNullifierChangesResponse v0 + */ + + /** + * Constructs a new GetRecentCompactedNullifierChangesResponse. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetRecentCompactedNullifierChangesResponse. + * @implements IGetRecentCompactedNullifierChangesResponse + * @constructor + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesResponse=} [properties] Properties to set + */ + function GetRecentCompactedNullifierChangesResponse(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetRecentCompactedNullifierChangesResponse v0. + * @member {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.IGetRecentCompactedNullifierChangesResponseV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @instance + */ + GetRecentCompactedNullifierChangesResponse.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetRecentCompactedNullifierChangesResponse version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @instance + */ + Object.defineProperty(GetRecentCompactedNullifierChangesResponse.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetRecentCompactedNullifierChangesResponse instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesResponse=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} GetRecentCompactedNullifierChangesResponse instance + */ + GetRecentCompactedNullifierChangesResponse.create = function create(properties) { + return new GetRecentCompactedNullifierChangesResponse(properties); + }; + + /** + * Encodes the specified GetRecentCompactedNullifierChangesResponse message. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesResponse} message GetRecentCompactedNullifierChangesResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentCompactedNullifierChangesResponse.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetRecentCompactedNullifierChangesResponse message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesResponse} message GetRecentCompactedNullifierChangesResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentCompactedNullifierChangesResponse.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetRecentCompactedNullifierChangesResponse message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} GetRecentCompactedNullifierChangesResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentCompactedNullifierChangesResponse.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetRecentCompactedNullifierChangesResponse message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} GetRecentCompactedNullifierChangesResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentCompactedNullifierChangesResponse.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetRecentCompactedNullifierChangesResponse message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetRecentCompactedNullifierChangesResponse.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetRecentCompactedNullifierChangesResponse message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} GetRecentCompactedNullifierChangesResponse + */ + GetRecentCompactedNullifierChangesResponse.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetRecentCompactedNullifierChangesResponse message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} message GetRecentCompactedNullifierChangesResponse + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetRecentCompactedNullifierChangesResponse.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetRecentCompactedNullifierChangesResponse to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @instance + * @returns {Object.} JSON object + */ + GetRecentCompactedNullifierChangesResponse.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 = (function() { + + /** + * Properties of a GetRecentCompactedNullifierChangesResponseV0. + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @interface IGetRecentCompactedNullifierChangesResponseV0 + * @property {org.dash.platform.dapi.v0.ICompactedNullifierUpdateEntries|null} [compactedNullifierUpdateEntries] GetRecentCompactedNullifierChangesResponseV0 compactedNullifierUpdateEntries + * @property {org.dash.platform.dapi.v0.IProof|null} [proof] GetRecentCompactedNullifierChangesResponseV0 proof + * @property {org.dash.platform.dapi.v0.IResponseMetadata|null} [metadata] GetRecentCompactedNullifierChangesResponseV0 metadata + */ + + /** + * Constructs a new GetRecentCompactedNullifierChangesResponseV0. + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @classdesc Represents a GetRecentCompactedNullifierChangesResponseV0. + * @implements IGetRecentCompactedNullifierChangesResponseV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.IGetRecentCompactedNullifierChangesResponseV0=} [properties] Properties to set + */ + function GetRecentCompactedNullifierChangesResponseV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetRecentCompactedNullifierChangesResponseV0 compactedNullifierUpdateEntries. + * @member {org.dash.platform.dapi.v0.ICompactedNullifierUpdateEntries|null|undefined} compactedNullifierUpdateEntries + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @instance + */ + GetRecentCompactedNullifierChangesResponseV0.prototype.compactedNullifierUpdateEntries = null; + + /** + * GetRecentCompactedNullifierChangesResponseV0 proof. + * @member {org.dash.platform.dapi.v0.IProof|null|undefined} proof + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @instance + */ + GetRecentCompactedNullifierChangesResponseV0.prototype.proof = null; + + /** + * GetRecentCompactedNullifierChangesResponseV0 metadata. + * @member {org.dash.platform.dapi.v0.IResponseMetadata|null|undefined} metadata + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @instance + */ + GetRecentCompactedNullifierChangesResponseV0.prototype.metadata = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetRecentCompactedNullifierChangesResponseV0 result. + * @member {"compactedNullifierUpdateEntries"|"proof"|undefined} result + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @instance + */ + Object.defineProperty(GetRecentCompactedNullifierChangesResponseV0.prototype, "result", { + get: $util.oneOfGetter($oneOfFields = ["compactedNullifierUpdateEntries", "proof"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetRecentCompactedNullifierChangesResponseV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.IGetRecentCompactedNullifierChangesResponseV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} GetRecentCompactedNullifierChangesResponseV0 instance + */ + GetRecentCompactedNullifierChangesResponseV0.create = function create(properties) { + return new GetRecentCompactedNullifierChangesResponseV0(properties); + }; + + /** + * Encodes the specified GetRecentCompactedNullifierChangesResponseV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.IGetRecentCompactedNullifierChangesResponseV0} message GetRecentCompactedNullifierChangesResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentCompactedNullifierChangesResponseV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.compactedNullifierUpdateEntries != null && Object.hasOwnProperty.call(message, "compactedNullifierUpdateEntries")) + $root.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.encode(message.compactedNullifierUpdateEntries, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + if (message.proof != null && Object.hasOwnProperty.call(message, "proof")) + $root.org.dash.platform.dapi.v0.Proof.encode(message.proof, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + if (message.metadata != null && Object.hasOwnProperty.call(message, "metadata")) + $root.org.dash.platform.dapi.v0.ResponseMetadata.encode(message.metadata, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetRecentCompactedNullifierChangesResponseV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.IGetRecentCompactedNullifierChangesResponseV0} message GetRecentCompactedNullifierChangesResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentCompactedNullifierChangesResponseV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetRecentCompactedNullifierChangesResponseV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} GetRecentCompactedNullifierChangesResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentCompactedNullifierChangesResponseV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.compactedNullifierUpdateEntries = $root.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.decode(reader, reader.uint32()); + break; + case 2: + message.proof = $root.org.dash.platform.dapi.v0.Proof.decode(reader, reader.uint32()); + break; + case 3: + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetRecentCompactedNullifierChangesResponseV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} GetRecentCompactedNullifierChangesResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentCompactedNullifierChangesResponseV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetRecentCompactedNullifierChangesResponseV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetRecentCompactedNullifierChangesResponseV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.compactedNullifierUpdateEntries != null && message.hasOwnProperty("compactedNullifierUpdateEntries")) { + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.verify(message.compactedNullifierUpdateEntries); + if (error) + return "compactedNullifierUpdateEntries." + error; + } + } + if (message.proof != null && message.hasOwnProperty("proof")) { + if (properties.result === 1) + return "result: multiple values"; + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.Proof.verify(message.proof); + if (error) + return "proof." + error; + } + } + if (message.metadata != null && message.hasOwnProperty("metadata")) { + var error = $root.org.dash.platform.dapi.v0.ResponseMetadata.verify(message.metadata); + if (error) + return "metadata." + error; + } + return null; + }; + + /** + * Creates a GetRecentCompactedNullifierChangesResponseV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} GetRecentCompactedNullifierChangesResponseV0 + */ + GetRecentCompactedNullifierChangesResponseV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0(); + if (object.compactedNullifierUpdateEntries != null) { + if (typeof object.compactedNullifierUpdateEntries !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.compactedNullifierUpdateEntries: object expected"); + message.compactedNullifierUpdateEntries = $root.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.fromObject(object.compactedNullifierUpdateEntries); + } + if (object.proof != null) { + if (typeof object.proof !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.proof: object expected"); + message.proof = $root.org.dash.platform.dapi.v0.Proof.fromObject(object.proof); + } + if (object.metadata != null) { + if (typeof object.metadata !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.metadata: object expected"); + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.fromObject(object.metadata); + } + return message; + }; + + /** + * Creates a plain object from a GetRecentCompactedNullifierChangesResponseV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} message GetRecentCompactedNullifierChangesResponseV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetRecentCompactedNullifierChangesResponseV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.metadata = null; + if (message.compactedNullifierUpdateEntries != null && message.hasOwnProperty("compactedNullifierUpdateEntries")) { + object.compactedNullifierUpdateEntries = $root.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.toObject(message.compactedNullifierUpdateEntries, options); + if (options.oneofs) + object.result = "compactedNullifierUpdateEntries"; + } + if (message.proof != null && message.hasOwnProperty("proof")) { + object.proof = $root.org.dash.platform.dapi.v0.Proof.toObject(message.proof, options); + if (options.oneofs) + object.result = "proof"; + } + if (message.metadata != null && message.hasOwnProperty("metadata")) + object.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.toObject(message.metadata, options); + return object; + }; + + /** + * Converts this GetRecentCompactedNullifierChangesResponseV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @instance + * @returns {Object.} JSON object + */ + GetRecentCompactedNullifierChangesResponseV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetRecentCompactedNullifierChangesResponseV0; + })(); + + return GetRecentCompactedNullifierChangesResponse; + })(); + return v0; })(); diff --git a/packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java b/packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java index 5edefc94451..340d53a9e55 100644 --- a/packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java +++ b/packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java @@ -1782,6 +1782,130 @@ org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedNullifiersResponse> getG return getGetShieldedNullifiersMethod; } + private static volatile io.grpc.MethodDescriptor getGetNullifiersTrunkStateMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "getNullifiersTrunkState", + requestType = org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersTrunkStateRequest.class, + responseType = org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersTrunkStateResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getGetNullifiersTrunkStateMethod() { + io.grpc.MethodDescriptor getGetNullifiersTrunkStateMethod; + if ((getGetNullifiersTrunkStateMethod = PlatformGrpc.getGetNullifiersTrunkStateMethod) == null) { + synchronized (PlatformGrpc.class) { + if ((getGetNullifiersTrunkStateMethod = PlatformGrpc.getGetNullifiersTrunkStateMethod) == null) { + PlatformGrpc.getGetNullifiersTrunkStateMethod = getGetNullifiersTrunkStateMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "getNullifiersTrunkState")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersTrunkStateRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersTrunkStateResponse.getDefaultInstance())) + .setSchemaDescriptor(new PlatformMethodDescriptorSupplier("getNullifiersTrunkState")) + .build(); + } + } + } + return getGetNullifiersTrunkStateMethod; + } + + private static volatile io.grpc.MethodDescriptor getGetNullifiersBranchStateMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "getNullifiersBranchState", + requestType = org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersBranchStateRequest.class, + responseType = org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersBranchStateResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getGetNullifiersBranchStateMethod() { + io.grpc.MethodDescriptor getGetNullifiersBranchStateMethod; + if ((getGetNullifiersBranchStateMethod = PlatformGrpc.getGetNullifiersBranchStateMethod) == null) { + synchronized (PlatformGrpc.class) { + if ((getGetNullifiersBranchStateMethod = PlatformGrpc.getGetNullifiersBranchStateMethod) == null) { + PlatformGrpc.getGetNullifiersBranchStateMethod = getGetNullifiersBranchStateMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "getNullifiersBranchState")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersBranchStateRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersBranchStateResponse.getDefaultInstance())) + .setSchemaDescriptor(new PlatformMethodDescriptorSupplier("getNullifiersBranchState")) + .build(); + } + } + } + return getGetNullifiersBranchStateMethod; + } + + private static volatile io.grpc.MethodDescriptor getGetRecentNullifierChangesMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "getRecentNullifierChanges", + requestType = org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentNullifierChangesRequest.class, + responseType = org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentNullifierChangesResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getGetRecentNullifierChangesMethod() { + io.grpc.MethodDescriptor getGetRecentNullifierChangesMethod; + if ((getGetRecentNullifierChangesMethod = PlatformGrpc.getGetRecentNullifierChangesMethod) == null) { + synchronized (PlatformGrpc.class) { + if ((getGetRecentNullifierChangesMethod = PlatformGrpc.getGetRecentNullifierChangesMethod) == null) { + PlatformGrpc.getGetRecentNullifierChangesMethod = getGetRecentNullifierChangesMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "getRecentNullifierChanges")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentNullifierChangesRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentNullifierChangesResponse.getDefaultInstance())) + .setSchemaDescriptor(new PlatformMethodDescriptorSupplier("getRecentNullifierChanges")) + .build(); + } + } + } + return getGetRecentNullifierChangesMethod; + } + + private static volatile io.grpc.MethodDescriptor getGetRecentCompactedNullifierChangesMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "getRecentCompactedNullifierChanges", + requestType = org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentCompactedNullifierChangesRequest.class, + responseType = org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentCompactedNullifierChangesResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getGetRecentCompactedNullifierChangesMethod() { + io.grpc.MethodDescriptor getGetRecentCompactedNullifierChangesMethod; + if ((getGetRecentCompactedNullifierChangesMethod = PlatformGrpc.getGetRecentCompactedNullifierChangesMethod) == null) { + synchronized (PlatformGrpc.class) { + if ((getGetRecentCompactedNullifierChangesMethod = PlatformGrpc.getGetRecentCompactedNullifierChangesMethod) == null) { + PlatformGrpc.getGetRecentCompactedNullifierChangesMethod = getGetRecentCompactedNullifierChangesMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "getRecentCompactedNullifierChanges")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentCompactedNullifierChangesRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentCompactedNullifierChangesResponse.getDefaultInstance())) + .setSchemaDescriptor(new PlatformMethodDescriptorSupplier("getRecentCompactedNullifierChanges")) + .build(); + } + } + } + return getGetRecentCompactedNullifierChangesMethod; + } + /** * Creates a new async stub that supports all call types for the service */ @@ -2244,6 +2368,34 @@ public void getShieldedNullifiers(org.dash.platform.dapi.v0.PlatformOuterClass.G io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetShieldedNullifiersMethod(), responseObserver); } + /** + */ + public void getNullifiersTrunkState(org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersTrunkStateRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetNullifiersTrunkStateMethod(), responseObserver); + } + + /** + */ + public void getNullifiersBranchState(org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersBranchStateRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetNullifiersBranchStateMethod(), responseObserver); + } + + /** + */ + public void getRecentNullifierChanges(org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentNullifierChangesRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetRecentNullifierChangesMethod(), responseObserver); + } + + /** + */ + public void getRecentCompactedNullifierChanges(org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentCompactedNullifierChangesRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall(getGetRecentCompactedNullifierChangesMethod(), responseObserver); + } + @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() { return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) .addMethod( @@ -2645,6 +2797,34 @@ public void getShieldedNullifiers(org.dash.platform.dapi.v0.PlatformOuterClass.G org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedNullifiersRequest, org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedNullifiersResponse>( this, METHODID_GET_SHIELDED_NULLIFIERS))) + .addMethod( + getGetNullifiersTrunkStateMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersTrunkStateRequest, + org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersTrunkStateResponse>( + this, METHODID_GET_NULLIFIERS_TRUNK_STATE))) + .addMethod( + getGetNullifiersBranchStateMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersBranchStateRequest, + org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersBranchStateResponse>( + this, METHODID_GET_NULLIFIERS_BRANCH_STATE))) + .addMethod( + getGetRecentNullifierChangesMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentNullifierChangesRequest, + org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentNullifierChangesResponse>( + this, METHODID_GET_RECENT_NULLIFIER_CHANGES))) + .addMethod( + getGetRecentCompactedNullifierChangesMethod(), + io.grpc.stub.ServerCalls.asyncUnaryCall( + new MethodHandlers< + org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentCompactedNullifierChangesRequest, + org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentCompactedNullifierChangesResponse>( + this, METHODID_GET_RECENT_COMPACTED_NULLIFIER_CHANGES))) .build(); } } @@ -3133,6 +3313,38 @@ public void getShieldedNullifiers(org.dash.platform.dapi.v0.PlatformOuterClass.G io.grpc.stub.ClientCalls.asyncUnaryCall( getChannel().newCall(getGetShieldedNullifiersMethod(), getCallOptions()), request, responseObserver); } + + /** + */ + public void getNullifiersTrunkState(org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersTrunkStateRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getGetNullifiersTrunkStateMethod(), getCallOptions()), request, responseObserver); + } + + /** + */ + public void getNullifiersBranchState(org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersBranchStateRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getGetNullifiersBranchStateMethod(), getCallOptions()), request, responseObserver); + } + + /** + */ + public void getRecentNullifierChanges(org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentNullifierChangesRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getGetRecentNullifierChangesMethod(), getCallOptions()), request, responseObserver); + } + + /** + */ + public void getRecentCompactedNullifierChanges(org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentCompactedNullifierChangesRequest request, + io.grpc.stub.StreamObserver responseObserver) { + io.grpc.stub.ClientCalls.asyncUnaryCall( + getChannel().newCall(getGetRecentCompactedNullifierChangesMethod(), getCallOptions()), request, responseObserver); + } } /** @@ -3562,6 +3774,34 @@ public org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedNullifiersRespons return io.grpc.stub.ClientCalls.blockingUnaryCall( getChannel(), getGetShieldedNullifiersMethod(), getCallOptions(), request); } + + /** + */ + public org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersTrunkStateResponse getNullifiersTrunkState(org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersTrunkStateRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getGetNullifiersTrunkStateMethod(), getCallOptions(), request); + } + + /** + */ + public org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersBranchStateResponse getNullifiersBranchState(org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersBranchStateRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getGetNullifiersBranchStateMethod(), getCallOptions(), request); + } + + /** + */ + public org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentNullifierChangesResponse getRecentNullifierChanges(org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentNullifierChangesRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getGetRecentNullifierChangesMethod(), getCallOptions(), request); + } + + /** + */ + public org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentCompactedNullifierChangesResponse getRecentCompactedNullifierChanges(org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentCompactedNullifierChangesRequest request) { + return io.grpc.stub.ClientCalls.blockingUnaryCall( + getChannel(), getGetRecentCompactedNullifierChangesMethod(), getCallOptions(), request); + } } /** @@ -4048,6 +4288,38 @@ public com.google.common.util.concurrent.ListenableFuture getNullifiersTrunkState( + org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersTrunkStateRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getGetNullifiersTrunkStateMethod(), getCallOptions()), request); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture getNullifiersBranchState( + org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersBranchStateRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getGetNullifiersBranchStateMethod(), getCallOptions()), request); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture getRecentNullifierChanges( + org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentNullifierChangesRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getGetRecentNullifierChangesMethod(), getCallOptions()), request); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture getRecentCompactedNullifierChanges( + org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentCompactedNullifierChangesRequest request) { + return io.grpc.stub.ClientCalls.futureUnaryCall( + getChannel().newCall(getGetRecentCompactedNullifierChangesMethod(), getCallOptions()), request); + } } private static final int METHODID_BROADCAST_STATE_TRANSITION = 0; @@ -4107,6 +4379,10 @@ public com.google.common.util.concurrent.ListenableFuture implements io.grpc.stub.ServerCalls.UnaryMethod, @@ -4353,6 +4629,22 @@ public void invoke(Req request, io.grpc.stub.StreamObserver responseObserv serviceImpl.getShieldedNullifiers((org.dash.platform.dapi.v0.PlatformOuterClass.GetShieldedNullifiersRequest) request, (io.grpc.stub.StreamObserver) responseObserver); break; + case METHODID_GET_NULLIFIERS_TRUNK_STATE: + serviceImpl.getNullifiersTrunkState((org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersTrunkStateRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_GET_NULLIFIERS_BRANCH_STATE: + serviceImpl.getNullifiersBranchState((org.dash.platform.dapi.v0.PlatformOuterClass.GetNullifiersBranchStateRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_GET_RECENT_NULLIFIER_CHANGES: + serviceImpl.getRecentNullifierChanges((org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentNullifierChangesRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_GET_RECENT_COMPACTED_NULLIFIER_CHANGES: + serviceImpl.getRecentCompactedNullifierChanges((org.dash.platform.dapi.v0.PlatformOuterClass.GetRecentCompactedNullifierChangesRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; default: throw new AssertionError(); } @@ -4471,6 +4763,10 @@ public static io.grpc.ServiceDescriptor getServiceDescriptor() { .addMethod(getGetShieldedAnchorsMethod()) .addMethod(getGetShieldedPoolStateMethod()) .addMethod(getGetShieldedNullifiersMethod()) + .addMethod(getGetNullifiersTrunkStateMethod()) + .addMethod(getGetNullifiersBranchStateMethod()) + .addMethod(getGetRecentNullifierChangesMethod()) + .addMethod(getGetRecentCompactedNullifierChangesMethod()) .build(); } } diff --git a/packages/dapi-grpc/clients/platform/v0/nodejs/platform_pbjs.js b/packages/dapi-grpc/clients/platform/v0/nodejs/platform_pbjs.js index aa940b9324f..efcf9934c54 100644 --- a/packages/dapi-grpc/clients/platform/v0/nodejs/platform_pbjs.js +++ b/packages/dapi-grpc/clients/platform/v0/nodejs/platform_pbjs.js @@ -1967,6 +1967,138 @@ $root.org = (function() { * @variation 2 */ + /** + * Callback as used by {@link org.dash.platform.dapi.v0.Platform#getNullifiersTrunkState}. + * @memberof org.dash.platform.dapi.v0.Platform + * @typedef getNullifiersTrunkStateCallback + * @type {function} + * @param {Error|null} error Error, if any + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} [response] GetNullifiersTrunkStateResponse + */ + + /** + * Calls getNullifiersTrunkState. + * @function getNullifiersTrunkState + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateRequest} request GetNullifiersTrunkStateRequest message or plain object + * @param {org.dash.platform.dapi.v0.Platform.getNullifiersTrunkStateCallback} callback Node-style callback called with the error, if any, and GetNullifiersTrunkStateResponse + * @returns {undefined} + * @variation 1 + */ + Object.defineProperty(Platform.prototype.getNullifiersTrunkState = function getNullifiersTrunkState(request, callback) { + return this.rpcCall(getNullifiersTrunkState, $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest, $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse, request, callback); + }, "name", { value: "getNullifiersTrunkState" }); + + /** + * Calls getNullifiersTrunkState. + * @function getNullifiersTrunkState + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateRequest} request GetNullifiersTrunkStateRequest message or plain object + * @returns {Promise} Promise + * @variation 2 + */ + + /** + * Callback as used by {@link org.dash.platform.dapi.v0.Platform#getNullifiersBranchState}. + * @memberof org.dash.platform.dapi.v0.Platform + * @typedef getNullifiersBranchStateCallback + * @type {function} + * @param {Error|null} error Error, if any + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} [response] GetNullifiersBranchStateResponse + */ + + /** + * Calls getNullifiersBranchState. + * @function getNullifiersBranchState + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateRequest} request GetNullifiersBranchStateRequest message or plain object + * @param {org.dash.platform.dapi.v0.Platform.getNullifiersBranchStateCallback} callback Node-style callback called with the error, if any, and GetNullifiersBranchStateResponse + * @returns {undefined} + * @variation 1 + */ + Object.defineProperty(Platform.prototype.getNullifiersBranchState = function getNullifiersBranchState(request, callback) { + return this.rpcCall(getNullifiersBranchState, $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest, $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse, request, callback); + }, "name", { value: "getNullifiersBranchState" }); + + /** + * Calls getNullifiersBranchState. + * @function getNullifiersBranchState + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateRequest} request GetNullifiersBranchStateRequest message or plain object + * @returns {Promise} Promise + * @variation 2 + */ + + /** + * Callback as used by {@link org.dash.platform.dapi.v0.Platform#getRecentNullifierChanges}. + * @memberof org.dash.platform.dapi.v0.Platform + * @typedef getRecentNullifierChangesCallback + * @type {function} + * @param {Error|null} error Error, if any + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} [response] GetRecentNullifierChangesResponse + */ + + /** + * Calls getRecentNullifierChanges. + * @function getRecentNullifierChanges + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesRequest} request GetRecentNullifierChangesRequest message or plain object + * @param {org.dash.platform.dapi.v0.Platform.getRecentNullifierChangesCallback} callback Node-style callback called with the error, if any, and GetRecentNullifierChangesResponse + * @returns {undefined} + * @variation 1 + */ + Object.defineProperty(Platform.prototype.getRecentNullifierChanges = function getRecentNullifierChanges(request, callback) { + return this.rpcCall(getRecentNullifierChanges, $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest, $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse, request, callback); + }, "name", { value: "getRecentNullifierChanges" }); + + /** + * Calls getRecentNullifierChanges. + * @function getRecentNullifierChanges + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesRequest} request GetRecentNullifierChangesRequest message or plain object + * @returns {Promise} Promise + * @variation 2 + */ + + /** + * Callback as used by {@link org.dash.platform.dapi.v0.Platform#getRecentCompactedNullifierChanges}. + * @memberof org.dash.platform.dapi.v0.Platform + * @typedef getRecentCompactedNullifierChangesCallback + * @type {function} + * @param {Error|null} error Error, if any + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} [response] GetRecentCompactedNullifierChangesResponse + */ + + /** + * Calls getRecentCompactedNullifierChanges. + * @function getRecentCompactedNullifierChanges + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesRequest} request GetRecentCompactedNullifierChangesRequest message or plain object + * @param {org.dash.platform.dapi.v0.Platform.getRecentCompactedNullifierChangesCallback} callback Node-style callback called with the error, if any, and GetRecentCompactedNullifierChangesResponse + * @returns {undefined} + * @variation 1 + */ + Object.defineProperty(Platform.prototype.getRecentCompactedNullifierChanges = function getRecentCompactedNullifierChanges(request, callback) { + return this.rpcCall(getRecentCompactedNullifierChanges, $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest, $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse, request, callback); + }, "name", { value: "getRecentCompactedNullifierChanges" }); + + /** + * Calls getRecentCompactedNullifierChanges. + * @function getRecentCompactedNullifierChanges + * @memberof org.dash.platform.dapi.v0.Platform + * @instance + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesRequest} request GetRecentCompactedNullifierChangesRequest message or plain object + * @returns {Promise} Promise + * @variation 2 + */ + return Platform; })(); @@ -86999,6 +87131,4570 @@ $root.org = (function() { return GetShieldedNullifiersResponse; })(); + v0.GetNullifiersTrunkStateRequest = (function() { + + /** + * Properties of a GetNullifiersTrunkStateRequest. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetNullifiersTrunkStateRequest + * @property {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.IGetNullifiersTrunkStateRequestV0|null} [v0] GetNullifiersTrunkStateRequest v0 + */ + + /** + * Constructs a new GetNullifiersTrunkStateRequest. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetNullifiersTrunkStateRequest. + * @implements IGetNullifiersTrunkStateRequest + * @constructor + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateRequest=} [properties] Properties to set + */ + function GetNullifiersTrunkStateRequest(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetNullifiersTrunkStateRequest v0. + * @member {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.IGetNullifiersTrunkStateRequestV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @instance + */ + GetNullifiersTrunkStateRequest.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetNullifiersTrunkStateRequest version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @instance + */ + Object.defineProperty(GetNullifiersTrunkStateRequest.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetNullifiersTrunkStateRequest instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateRequest=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} GetNullifiersTrunkStateRequest instance + */ + GetNullifiersTrunkStateRequest.create = function create(properties) { + return new GetNullifiersTrunkStateRequest(properties); + }; + + /** + * Encodes the specified GetNullifiersTrunkStateRequest message. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateRequest} message GetNullifiersTrunkStateRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersTrunkStateRequest.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetNullifiersTrunkStateRequest message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateRequest} message GetNullifiersTrunkStateRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersTrunkStateRequest.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetNullifiersTrunkStateRequest message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} GetNullifiersTrunkStateRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersTrunkStateRequest.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetNullifiersTrunkStateRequest message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} GetNullifiersTrunkStateRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersTrunkStateRequest.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetNullifiersTrunkStateRequest message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetNullifiersTrunkStateRequest.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetNullifiersTrunkStateRequest message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} GetNullifiersTrunkStateRequest + */ + GetNullifiersTrunkStateRequest.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetNullifiersTrunkStateRequest message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} message GetNullifiersTrunkStateRequest + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetNullifiersTrunkStateRequest.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetNullifiersTrunkStateRequest to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @instance + * @returns {Object.} JSON object + */ + GetNullifiersTrunkStateRequest.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 = (function() { + + /** + * Properties of a GetNullifiersTrunkStateRequestV0. + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @interface IGetNullifiersTrunkStateRequestV0 + * @property {number|null} [poolType] GetNullifiersTrunkStateRequestV0 poolType + * @property {Uint8Array|null} [poolIdentifier] GetNullifiersTrunkStateRequestV0 poolIdentifier + */ + + /** + * Constructs a new GetNullifiersTrunkStateRequestV0. + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest + * @classdesc Represents a GetNullifiersTrunkStateRequestV0. + * @implements IGetNullifiersTrunkStateRequestV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.IGetNullifiersTrunkStateRequestV0=} [properties] Properties to set + */ + function GetNullifiersTrunkStateRequestV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetNullifiersTrunkStateRequestV0 poolType. + * @member {number} poolType + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @instance + */ + GetNullifiersTrunkStateRequestV0.prototype.poolType = 0; + + /** + * GetNullifiersTrunkStateRequestV0 poolIdentifier. + * @member {Uint8Array} poolIdentifier + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @instance + */ + GetNullifiersTrunkStateRequestV0.prototype.poolIdentifier = $util.newBuffer([]); + + /** + * Creates a new GetNullifiersTrunkStateRequestV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.IGetNullifiersTrunkStateRequestV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} GetNullifiersTrunkStateRequestV0 instance + */ + GetNullifiersTrunkStateRequestV0.create = function create(properties) { + return new GetNullifiersTrunkStateRequestV0(properties); + }; + + /** + * Encodes the specified GetNullifiersTrunkStateRequestV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.IGetNullifiersTrunkStateRequestV0} message GetNullifiersTrunkStateRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersTrunkStateRequestV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.poolType != null && Object.hasOwnProperty.call(message, "poolType")) + writer.uint32(/* id 1, wireType 0 =*/8).uint32(message.poolType); + if (message.poolIdentifier != null && Object.hasOwnProperty.call(message, "poolIdentifier")) + writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.poolIdentifier); + return writer; + }; + + /** + * Encodes the specified GetNullifiersTrunkStateRequestV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.IGetNullifiersTrunkStateRequestV0} message GetNullifiersTrunkStateRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersTrunkStateRequestV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetNullifiersTrunkStateRequestV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} GetNullifiersTrunkStateRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersTrunkStateRequestV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.poolType = reader.uint32(); + break; + case 2: + message.poolIdentifier = reader.bytes(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetNullifiersTrunkStateRequestV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} GetNullifiersTrunkStateRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersTrunkStateRequestV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetNullifiersTrunkStateRequestV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetNullifiersTrunkStateRequestV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.poolType != null && message.hasOwnProperty("poolType")) + if (!$util.isInteger(message.poolType)) + return "poolType: integer expected"; + if (message.poolIdentifier != null && message.hasOwnProperty("poolIdentifier")) + if (!(message.poolIdentifier && typeof message.poolIdentifier.length === "number" || $util.isString(message.poolIdentifier))) + return "poolIdentifier: buffer expected"; + return null; + }; + + /** + * Creates a GetNullifiersTrunkStateRequestV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} GetNullifiersTrunkStateRequestV0 + */ + GetNullifiersTrunkStateRequestV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0(); + if (object.poolType != null) + message.poolType = object.poolType >>> 0; + if (object.poolIdentifier != null) + if (typeof object.poolIdentifier === "string") + $util.base64.decode(object.poolIdentifier, message.poolIdentifier = $util.newBuffer($util.base64.length(object.poolIdentifier)), 0); + else if (object.poolIdentifier.length >= 0) + message.poolIdentifier = object.poolIdentifier; + return message; + }; + + /** + * Creates a plain object from a GetNullifiersTrunkStateRequestV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} message GetNullifiersTrunkStateRequestV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetNullifiersTrunkStateRequestV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.poolType = 0; + if (options.bytes === String) + object.poolIdentifier = ""; + else { + object.poolIdentifier = []; + if (options.bytes !== Array) + object.poolIdentifier = $util.newBuffer(object.poolIdentifier); + } + } + if (message.poolType != null && message.hasOwnProperty("poolType")) + object.poolType = message.poolType; + if (message.poolIdentifier != null && message.hasOwnProperty("poolIdentifier")) + object.poolIdentifier = options.bytes === String ? $util.base64.encode(message.poolIdentifier, 0, message.poolIdentifier.length) : options.bytes === Array ? Array.prototype.slice.call(message.poolIdentifier) : message.poolIdentifier; + return object; + }; + + /** + * Converts this GetNullifiersTrunkStateRequestV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 + * @instance + * @returns {Object.} JSON object + */ + GetNullifiersTrunkStateRequestV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetNullifiersTrunkStateRequestV0; + })(); + + return GetNullifiersTrunkStateRequest; + })(); + + v0.GetNullifiersTrunkStateResponse = (function() { + + /** + * Properties of a GetNullifiersTrunkStateResponse. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetNullifiersTrunkStateResponse + * @property {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.IGetNullifiersTrunkStateResponseV0|null} [v0] GetNullifiersTrunkStateResponse v0 + */ + + /** + * Constructs a new GetNullifiersTrunkStateResponse. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetNullifiersTrunkStateResponse. + * @implements IGetNullifiersTrunkStateResponse + * @constructor + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateResponse=} [properties] Properties to set + */ + function GetNullifiersTrunkStateResponse(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetNullifiersTrunkStateResponse v0. + * @member {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.IGetNullifiersTrunkStateResponseV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @instance + */ + GetNullifiersTrunkStateResponse.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetNullifiersTrunkStateResponse version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @instance + */ + Object.defineProperty(GetNullifiersTrunkStateResponse.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetNullifiersTrunkStateResponse instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateResponse=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} GetNullifiersTrunkStateResponse instance + */ + GetNullifiersTrunkStateResponse.create = function create(properties) { + return new GetNullifiersTrunkStateResponse(properties); + }; + + /** + * Encodes the specified GetNullifiersTrunkStateResponse message. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateResponse} message GetNullifiersTrunkStateResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersTrunkStateResponse.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetNullifiersTrunkStateResponse message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersTrunkStateResponse} message GetNullifiersTrunkStateResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersTrunkStateResponse.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetNullifiersTrunkStateResponse message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} GetNullifiersTrunkStateResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersTrunkStateResponse.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetNullifiersTrunkStateResponse message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} GetNullifiersTrunkStateResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersTrunkStateResponse.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetNullifiersTrunkStateResponse message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetNullifiersTrunkStateResponse.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetNullifiersTrunkStateResponse message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} GetNullifiersTrunkStateResponse + */ + GetNullifiersTrunkStateResponse.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetNullifiersTrunkStateResponse message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} message GetNullifiersTrunkStateResponse + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetNullifiersTrunkStateResponse.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetNullifiersTrunkStateResponse to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @instance + * @returns {Object.} JSON object + */ + GetNullifiersTrunkStateResponse.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 = (function() { + + /** + * Properties of a GetNullifiersTrunkStateResponseV0. + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @interface IGetNullifiersTrunkStateResponseV0 + * @property {org.dash.platform.dapi.v0.IProof|null} [proof] GetNullifiersTrunkStateResponseV0 proof + * @property {org.dash.platform.dapi.v0.IResponseMetadata|null} [metadata] GetNullifiersTrunkStateResponseV0 metadata + */ + + /** + * Constructs a new GetNullifiersTrunkStateResponseV0. + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse + * @classdesc Represents a GetNullifiersTrunkStateResponseV0. + * @implements IGetNullifiersTrunkStateResponseV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.IGetNullifiersTrunkStateResponseV0=} [properties] Properties to set + */ + function GetNullifiersTrunkStateResponseV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetNullifiersTrunkStateResponseV0 proof. + * @member {org.dash.platform.dapi.v0.IProof|null|undefined} proof + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @instance + */ + GetNullifiersTrunkStateResponseV0.prototype.proof = null; + + /** + * GetNullifiersTrunkStateResponseV0 metadata. + * @member {org.dash.platform.dapi.v0.IResponseMetadata|null|undefined} metadata + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @instance + */ + GetNullifiersTrunkStateResponseV0.prototype.metadata = null; + + /** + * Creates a new GetNullifiersTrunkStateResponseV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.IGetNullifiersTrunkStateResponseV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} GetNullifiersTrunkStateResponseV0 instance + */ + GetNullifiersTrunkStateResponseV0.create = function create(properties) { + return new GetNullifiersTrunkStateResponseV0(properties); + }; + + /** + * Encodes the specified GetNullifiersTrunkStateResponseV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.IGetNullifiersTrunkStateResponseV0} message GetNullifiersTrunkStateResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersTrunkStateResponseV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.proof != null && Object.hasOwnProperty.call(message, "proof")) + $root.org.dash.platform.dapi.v0.Proof.encode(message.proof, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + if (message.metadata != null && Object.hasOwnProperty.call(message, "metadata")) + $root.org.dash.platform.dapi.v0.ResponseMetadata.encode(message.metadata, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetNullifiersTrunkStateResponseV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.IGetNullifiersTrunkStateResponseV0} message GetNullifiersTrunkStateResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersTrunkStateResponseV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetNullifiersTrunkStateResponseV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} GetNullifiersTrunkStateResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersTrunkStateResponseV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 2: + message.proof = $root.org.dash.platform.dapi.v0.Proof.decode(reader, reader.uint32()); + break; + case 3: + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetNullifiersTrunkStateResponseV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} GetNullifiersTrunkStateResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersTrunkStateResponseV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetNullifiersTrunkStateResponseV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetNullifiersTrunkStateResponseV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.proof != null && message.hasOwnProperty("proof")) { + var error = $root.org.dash.platform.dapi.v0.Proof.verify(message.proof); + if (error) + return "proof." + error; + } + if (message.metadata != null && message.hasOwnProperty("metadata")) { + var error = $root.org.dash.platform.dapi.v0.ResponseMetadata.verify(message.metadata); + if (error) + return "metadata." + error; + } + return null; + }; + + /** + * Creates a GetNullifiersTrunkStateResponseV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} GetNullifiersTrunkStateResponseV0 + */ + GetNullifiersTrunkStateResponseV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0(); + if (object.proof != null) { + if (typeof object.proof !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.proof: object expected"); + message.proof = $root.org.dash.platform.dapi.v0.Proof.fromObject(object.proof); + } + if (object.metadata != null) { + if (typeof object.metadata !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.metadata: object expected"); + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.fromObject(object.metadata); + } + return message; + }; + + /** + * Creates a plain object from a GetNullifiersTrunkStateResponseV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} message GetNullifiersTrunkStateResponseV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetNullifiersTrunkStateResponseV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.proof = null; + object.metadata = null; + } + if (message.proof != null && message.hasOwnProperty("proof")) + object.proof = $root.org.dash.platform.dapi.v0.Proof.toObject(message.proof, options); + if (message.metadata != null && message.hasOwnProperty("metadata")) + object.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.toObject(message.metadata, options); + return object; + }; + + /** + * Converts this GetNullifiersTrunkStateResponseV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 + * @instance + * @returns {Object.} JSON object + */ + GetNullifiersTrunkStateResponseV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetNullifiersTrunkStateResponseV0; + })(); + + return GetNullifiersTrunkStateResponse; + })(); + + v0.GetNullifiersBranchStateRequest = (function() { + + /** + * Properties of a GetNullifiersBranchStateRequest. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetNullifiersBranchStateRequest + * @property {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.IGetNullifiersBranchStateRequestV0|null} [v0] GetNullifiersBranchStateRequest v0 + */ + + /** + * Constructs a new GetNullifiersBranchStateRequest. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetNullifiersBranchStateRequest. + * @implements IGetNullifiersBranchStateRequest + * @constructor + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateRequest=} [properties] Properties to set + */ + function GetNullifiersBranchStateRequest(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetNullifiersBranchStateRequest v0. + * @member {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.IGetNullifiersBranchStateRequestV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @instance + */ + GetNullifiersBranchStateRequest.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetNullifiersBranchStateRequest version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @instance + */ + Object.defineProperty(GetNullifiersBranchStateRequest.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetNullifiersBranchStateRequest instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateRequest=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} GetNullifiersBranchStateRequest instance + */ + GetNullifiersBranchStateRequest.create = function create(properties) { + return new GetNullifiersBranchStateRequest(properties); + }; + + /** + * Encodes the specified GetNullifiersBranchStateRequest message. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateRequest} message GetNullifiersBranchStateRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersBranchStateRequest.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetNullifiersBranchStateRequest message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateRequest} message GetNullifiersBranchStateRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersBranchStateRequest.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetNullifiersBranchStateRequest message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} GetNullifiersBranchStateRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersBranchStateRequest.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetNullifiersBranchStateRequest message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} GetNullifiersBranchStateRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersBranchStateRequest.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetNullifiersBranchStateRequest message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetNullifiersBranchStateRequest.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetNullifiersBranchStateRequest message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} GetNullifiersBranchStateRequest + */ + GetNullifiersBranchStateRequest.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetNullifiersBranchStateRequest message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} message GetNullifiersBranchStateRequest + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetNullifiersBranchStateRequest.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetNullifiersBranchStateRequest to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @instance + * @returns {Object.} JSON object + */ + GetNullifiersBranchStateRequest.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 = (function() { + + /** + * Properties of a GetNullifiersBranchStateRequestV0. + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @interface IGetNullifiersBranchStateRequestV0 + * @property {number|null} [poolType] GetNullifiersBranchStateRequestV0 poolType + * @property {Uint8Array|null} [poolIdentifier] GetNullifiersBranchStateRequestV0 poolIdentifier + * @property {Uint8Array|null} [key] GetNullifiersBranchStateRequestV0 key + * @property {number|null} [depth] GetNullifiersBranchStateRequestV0 depth + * @property {number|Long|null} [checkpointHeight] GetNullifiersBranchStateRequestV0 checkpointHeight + */ + + /** + * Constructs a new GetNullifiersBranchStateRequestV0. + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest + * @classdesc Represents a GetNullifiersBranchStateRequestV0. + * @implements IGetNullifiersBranchStateRequestV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.IGetNullifiersBranchStateRequestV0=} [properties] Properties to set + */ + function GetNullifiersBranchStateRequestV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetNullifiersBranchStateRequestV0 poolType. + * @member {number} poolType + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @instance + */ + GetNullifiersBranchStateRequestV0.prototype.poolType = 0; + + /** + * GetNullifiersBranchStateRequestV0 poolIdentifier. + * @member {Uint8Array} poolIdentifier + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @instance + */ + GetNullifiersBranchStateRequestV0.prototype.poolIdentifier = $util.newBuffer([]); + + /** + * GetNullifiersBranchStateRequestV0 key. + * @member {Uint8Array} key + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @instance + */ + GetNullifiersBranchStateRequestV0.prototype.key = $util.newBuffer([]); + + /** + * GetNullifiersBranchStateRequestV0 depth. + * @member {number} depth + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @instance + */ + GetNullifiersBranchStateRequestV0.prototype.depth = 0; + + /** + * GetNullifiersBranchStateRequestV0 checkpointHeight. + * @member {number|Long} checkpointHeight + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @instance + */ + GetNullifiersBranchStateRequestV0.prototype.checkpointHeight = $util.Long ? $util.Long.fromBits(0,0,true) : 0; + + /** + * Creates a new GetNullifiersBranchStateRequestV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.IGetNullifiersBranchStateRequestV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} GetNullifiersBranchStateRequestV0 instance + */ + GetNullifiersBranchStateRequestV0.create = function create(properties) { + return new GetNullifiersBranchStateRequestV0(properties); + }; + + /** + * Encodes the specified GetNullifiersBranchStateRequestV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.IGetNullifiersBranchStateRequestV0} message GetNullifiersBranchStateRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersBranchStateRequestV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.poolType != null && Object.hasOwnProperty.call(message, "poolType")) + writer.uint32(/* id 1, wireType 0 =*/8).uint32(message.poolType); + if (message.poolIdentifier != null && Object.hasOwnProperty.call(message, "poolIdentifier")) + writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.poolIdentifier); + if (message.key != null && Object.hasOwnProperty.call(message, "key")) + writer.uint32(/* id 3, wireType 2 =*/26).bytes(message.key); + if (message.depth != null && Object.hasOwnProperty.call(message, "depth")) + writer.uint32(/* id 4, wireType 0 =*/32).uint32(message.depth); + if (message.checkpointHeight != null && Object.hasOwnProperty.call(message, "checkpointHeight")) + writer.uint32(/* id 5, wireType 0 =*/40).uint64(message.checkpointHeight); + return writer; + }; + + /** + * Encodes the specified GetNullifiersBranchStateRequestV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.IGetNullifiersBranchStateRequestV0} message GetNullifiersBranchStateRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersBranchStateRequestV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetNullifiersBranchStateRequestV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} GetNullifiersBranchStateRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersBranchStateRequestV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.poolType = reader.uint32(); + break; + case 2: + message.poolIdentifier = reader.bytes(); + break; + case 3: + message.key = reader.bytes(); + break; + case 4: + message.depth = reader.uint32(); + break; + case 5: + message.checkpointHeight = reader.uint64(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetNullifiersBranchStateRequestV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} GetNullifiersBranchStateRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersBranchStateRequestV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetNullifiersBranchStateRequestV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetNullifiersBranchStateRequestV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.poolType != null && message.hasOwnProperty("poolType")) + if (!$util.isInteger(message.poolType)) + return "poolType: integer expected"; + if (message.poolIdentifier != null && message.hasOwnProperty("poolIdentifier")) + if (!(message.poolIdentifier && typeof message.poolIdentifier.length === "number" || $util.isString(message.poolIdentifier))) + return "poolIdentifier: buffer expected"; + if (message.key != null && message.hasOwnProperty("key")) + if (!(message.key && typeof message.key.length === "number" || $util.isString(message.key))) + return "key: buffer expected"; + if (message.depth != null && message.hasOwnProperty("depth")) + if (!$util.isInteger(message.depth)) + return "depth: integer expected"; + if (message.checkpointHeight != null && message.hasOwnProperty("checkpointHeight")) + if (!$util.isInteger(message.checkpointHeight) && !(message.checkpointHeight && $util.isInteger(message.checkpointHeight.low) && $util.isInteger(message.checkpointHeight.high))) + return "checkpointHeight: integer|Long expected"; + return null; + }; + + /** + * Creates a GetNullifiersBranchStateRequestV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} GetNullifiersBranchStateRequestV0 + */ + GetNullifiersBranchStateRequestV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0(); + if (object.poolType != null) + message.poolType = object.poolType >>> 0; + if (object.poolIdentifier != null) + if (typeof object.poolIdentifier === "string") + $util.base64.decode(object.poolIdentifier, message.poolIdentifier = $util.newBuffer($util.base64.length(object.poolIdentifier)), 0); + else if (object.poolIdentifier.length >= 0) + message.poolIdentifier = object.poolIdentifier; + if (object.key != null) + if (typeof object.key === "string") + $util.base64.decode(object.key, message.key = $util.newBuffer($util.base64.length(object.key)), 0); + else if (object.key.length >= 0) + message.key = object.key; + if (object.depth != null) + message.depth = object.depth >>> 0; + if (object.checkpointHeight != null) + if ($util.Long) + (message.checkpointHeight = $util.Long.fromValue(object.checkpointHeight)).unsigned = true; + else if (typeof object.checkpointHeight === "string") + message.checkpointHeight = parseInt(object.checkpointHeight, 10); + else if (typeof object.checkpointHeight === "number") + message.checkpointHeight = object.checkpointHeight; + else if (typeof object.checkpointHeight === "object") + message.checkpointHeight = new $util.LongBits(object.checkpointHeight.low >>> 0, object.checkpointHeight.high >>> 0).toNumber(true); + return message; + }; + + /** + * Creates a plain object from a GetNullifiersBranchStateRequestV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} message GetNullifiersBranchStateRequestV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetNullifiersBranchStateRequestV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + object.poolType = 0; + if (options.bytes === String) + object.poolIdentifier = ""; + else { + object.poolIdentifier = []; + if (options.bytes !== Array) + object.poolIdentifier = $util.newBuffer(object.poolIdentifier); + } + if (options.bytes === String) + object.key = ""; + else { + object.key = []; + if (options.bytes !== Array) + object.key = $util.newBuffer(object.key); + } + object.depth = 0; + if ($util.Long) { + var long = new $util.Long(0, 0, true); + object.checkpointHeight = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.checkpointHeight = options.longs === String ? "0" : 0; + } + if (message.poolType != null && message.hasOwnProperty("poolType")) + object.poolType = message.poolType; + if (message.poolIdentifier != null && message.hasOwnProperty("poolIdentifier")) + object.poolIdentifier = options.bytes === String ? $util.base64.encode(message.poolIdentifier, 0, message.poolIdentifier.length) : options.bytes === Array ? Array.prototype.slice.call(message.poolIdentifier) : message.poolIdentifier; + if (message.key != null && message.hasOwnProperty("key")) + object.key = options.bytes === String ? $util.base64.encode(message.key, 0, message.key.length) : options.bytes === Array ? Array.prototype.slice.call(message.key) : message.key; + if (message.depth != null && message.hasOwnProperty("depth")) + object.depth = message.depth; + if (message.checkpointHeight != null && message.hasOwnProperty("checkpointHeight")) + if (typeof message.checkpointHeight === "number") + object.checkpointHeight = options.longs === String ? String(message.checkpointHeight) : message.checkpointHeight; + else + object.checkpointHeight = options.longs === String ? $util.Long.prototype.toString.call(message.checkpointHeight) : options.longs === Number ? new $util.LongBits(message.checkpointHeight.low >>> 0, message.checkpointHeight.high >>> 0).toNumber(true) : message.checkpointHeight; + return object; + }; + + /** + * Converts this GetNullifiersBranchStateRequestV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 + * @instance + * @returns {Object.} JSON object + */ + GetNullifiersBranchStateRequestV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetNullifiersBranchStateRequestV0; + })(); + + return GetNullifiersBranchStateRequest; + })(); + + v0.GetNullifiersBranchStateResponse = (function() { + + /** + * Properties of a GetNullifiersBranchStateResponse. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetNullifiersBranchStateResponse + * @property {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.IGetNullifiersBranchStateResponseV0|null} [v0] GetNullifiersBranchStateResponse v0 + */ + + /** + * Constructs a new GetNullifiersBranchStateResponse. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetNullifiersBranchStateResponse. + * @implements IGetNullifiersBranchStateResponse + * @constructor + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateResponse=} [properties] Properties to set + */ + function GetNullifiersBranchStateResponse(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetNullifiersBranchStateResponse v0. + * @member {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.IGetNullifiersBranchStateResponseV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @instance + */ + GetNullifiersBranchStateResponse.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetNullifiersBranchStateResponse version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @instance + */ + Object.defineProperty(GetNullifiersBranchStateResponse.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetNullifiersBranchStateResponse instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateResponse=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} GetNullifiersBranchStateResponse instance + */ + GetNullifiersBranchStateResponse.create = function create(properties) { + return new GetNullifiersBranchStateResponse(properties); + }; + + /** + * Encodes the specified GetNullifiersBranchStateResponse message. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateResponse} message GetNullifiersBranchStateResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersBranchStateResponse.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetNullifiersBranchStateResponse message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetNullifiersBranchStateResponse} message GetNullifiersBranchStateResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersBranchStateResponse.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetNullifiersBranchStateResponse message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} GetNullifiersBranchStateResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersBranchStateResponse.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetNullifiersBranchStateResponse message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} GetNullifiersBranchStateResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersBranchStateResponse.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetNullifiersBranchStateResponse message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetNullifiersBranchStateResponse.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetNullifiersBranchStateResponse message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} GetNullifiersBranchStateResponse + */ + GetNullifiersBranchStateResponse.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetNullifiersBranchStateResponse message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} message GetNullifiersBranchStateResponse + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetNullifiersBranchStateResponse.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetNullifiersBranchStateResponse to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @instance + * @returns {Object.} JSON object + */ + GetNullifiersBranchStateResponse.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 = (function() { + + /** + * Properties of a GetNullifiersBranchStateResponseV0. + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @interface IGetNullifiersBranchStateResponseV0 + * @property {Uint8Array|null} [merkProof] GetNullifiersBranchStateResponseV0 merkProof + */ + + /** + * Constructs a new GetNullifiersBranchStateResponseV0. + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse + * @classdesc Represents a GetNullifiersBranchStateResponseV0. + * @implements IGetNullifiersBranchStateResponseV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.IGetNullifiersBranchStateResponseV0=} [properties] Properties to set + */ + function GetNullifiersBranchStateResponseV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetNullifiersBranchStateResponseV0 merkProof. + * @member {Uint8Array} merkProof + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @instance + */ + GetNullifiersBranchStateResponseV0.prototype.merkProof = $util.newBuffer([]); + + /** + * Creates a new GetNullifiersBranchStateResponseV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.IGetNullifiersBranchStateResponseV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} GetNullifiersBranchStateResponseV0 instance + */ + GetNullifiersBranchStateResponseV0.create = function create(properties) { + return new GetNullifiersBranchStateResponseV0(properties); + }; + + /** + * Encodes the specified GetNullifiersBranchStateResponseV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.IGetNullifiersBranchStateResponseV0} message GetNullifiersBranchStateResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersBranchStateResponseV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.merkProof != null && Object.hasOwnProperty.call(message, "merkProof")) + writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.merkProof); + return writer; + }; + + /** + * Encodes the specified GetNullifiersBranchStateResponseV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.IGetNullifiersBranchStateResponseV0} message GetNullifiersBranchStateResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetNullifiersBranchStateResponseV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetNullifiersBranchStateResponseV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} GetNullifiersBranchStateResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersBranchStateResponseV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 2: + message.merkProof = reader.bytes(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetNullifiersBranchStateResponseV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} GetNullifiersBranchStateResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetNullifiersBranchStateResponseV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetNullifiersBranchStateResponseV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetNullifiersBranchStateResponseV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.merkProof != null && message.hasOwnProperty("merkProof")) + if (!(message.merkProof && typeof message.merkProof.length === "number" || $util.isString(message.merkProof))) + return "merkProof: buffer expected"; + return null; + }; + + /** + * Creates a GetNullifiersBranchStateResponseV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} GetNullifiersBranchStateResponseV0 + */ + GetNullifiersBranchStateResponseV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0(); + if (object.merkProof != null) + if (typeof object.merkProof === "string") + $util.base64.decode(object.merkProof, message.merkProof = $util.newBuffer($util.base64.length(object.merkProof)), 0); + else if (object.merkProof.length >= 0) + message.merkProof = object.merkProof; + return message; + }; + + /** + * Creates a plain object from a GetNullifiersBranchStateResponseV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} message GetNullifiersBranchStateResponseV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetNullifiersBranchStateResponseV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + if (options.bytes === String) + object.merkProof = ""; + else { + object.merkProof = []; + if (options.bytes !== Array) + object.merkProof = $util.newBuffer(object.merkProof); + } + if (message.merkProof != null && message.hasOwnProperty("merkProof")) + object.merkProof = options.bytes === String ? $util.base64.encode(message.merkProof, 0, message.merkProof.length) : options.bytes === Array ? Array.prototype.slice.call(message.merkProof) : message.merkProof; + return object; + }; + + /** + * Converts this GetNullifiersBranchStateResponseV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 + * @instance + * @returns {Object.} JSON object + */ + GetNullifiersBranchStateResponseV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetNullifiersBranchStateResponseV0; + })(); + + return GetNullifiersBranchStateResponse; + })(); + + v0.BlockNullifierChanges = (function() { + + /** + * Properties of a BlockNullifierChanges. + * @memberof org.dash.platform.dapi.v0 + * @interface IBlockNullifierChanges + * @property {number|Long|null} [blockHeight] BlockNullifierChanges blockHeight + * @property {Array.|null} [nullifiers] BlockNullifierChanges nullifiers + */ + + /** + * Constructs a new BlockNullifierChanges. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a BlockNullifierChanges. + * @implements IBlockNullifierChanges + * @constructor + * @param {org.dash.platform.dapi.v0.IBlockNullifierChanges=} [properties] Properties to set + */ + function BlockNullifierChanges(properties) { + this.nullifiers = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * BlockNullifierChanges blockHeight. + * @member {number|Long} blockHeight + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @instance + */ + BlockNullifierChanges.prototype.blockHeight = $util.Long ? $util.Long.fromBits(0,0,true) : 0; + + /** + * BlockNullifierChanges nullifiers. + * @member {Array.} nullifiers + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @instance + */ + BlockNullifierChanges.prototype.nullifiers = $util.emptyArray; + + /** + * Creates a new BlockNullifierChanges instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @static + * @param {org.dash.platform.dapi.v0.IBlockNullifierChanges=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.BlockNullifierChanges} BlockNullifierChanges instance + */ + BlockNullifierChanges.create = function create(properties) { + return new BlockNullifierChanges(properties); + }; + + /** + * Encodes the specified BlockNullifierChanges message. Does not implicitly {@link org.dash.platform.dapi.v0.BlockNullifierChanges.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @static + * @param {org.dash.platform.dapi.v0.IBlockNullifierChanges} message BlockNullifierChanges message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + BlockNullifierChanges.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.blockHeight != null && Object.hasOwnProperty.call(message, "blockHeight")) + writer.uint32(/* id 1, wireType 0 =*/8).uint64(message.blockHeight); + if (message.nullifiers != null && message.nullifiers.length) + for (var i = 0; i < message.nullifiers.length; ++i) + writer.uint32(/* id 2, wireType 2 =*/18).bytes(message.nullifiers[i]); + return writer; + }; + + /** + * Encodes the specified BlockNullifierChanges message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.BlockNullifierChanges.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @static + * @param {org.dash.platform.dapi.v0.IBlockNullifierChanges} message BlockNullifierChanges message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + BlockNullifierChanges.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a BlockNullifierChanges message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.BlockNullifierChanges} BlockNullifierChanges + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + BlockNullifierChanges.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.BlockNullifierChanges(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.blockHeight = reader.uint64(); + break; + case 2: + if (!(message.nullifiers && message.nullifiers.length)) + message.nullifiers = []; + message.nullifiers.push(reader.bytes()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a BlockNullifierChanges message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.BlockNullifierChanges} BlockNullifierChanges + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + BlockNullifierChanges.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a BlockNullifierChanges message. + * @function verify + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + BlockNullifierChanges.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.blockHeight != null && message.hasOwnProperty("blockHeight")) + if (!$util.isInteger(message.blockHeight) && !(message.blockHeight && $util.isInteger(message.blockHeight.low) && $util.isInteger(message.blockHeight.high))) + return "blockHeight: integer|Long expected"; + if (message.nullifiers != null && message.hasOwnProperty("nullifiers")) { + if (!Array.isArray(message.nullifiers)) + return "nullifiers: array expected"; + for (var i = 0; i < message.nullifiers.length; ++i) + if (!(message.nullifiers[i] && typeof message.nullifiers[i].length === "number" || $util.isString(message.nullifiers[i]))) + return "nullifiers: buffer[] expected"; + } + return null; + }; + + /** + * Creates a BlockNullifierChanges message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.BlockNullifierChanges} BlockNullifierChanges + */ + BlockNullifierChanges.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.BlockNullifierChanges) + return object; + var message = new $root.org.dash.platform.dapi.v0.BlockNullifierChanges(); + if (object.blockHeight != null) + if ($util.Long) + (message.blockHeight = $util.Long.fromValue(object.blockHeight)).unsigned = true; + else if (typeof object.blockHeight === "string") + message.blockHeight = parseInt(object.blockHeight, 10); + else if (typeof object.blockHeight === "number") + message.blockHeight = object.blockHeight; + else if (typeof object.blockHeight === "object") + message.blockHeight = new $util.LongBits(object.blockHeight.low >>> 0, object.blockHeight.high >>> 0).toNumber(true); + if (object.nullifiers) { + if (!Array.isArray(object.nullifiers)) + throw TypeError(".org.dash.platform.dapi.v0.BlockNullifierChanges.nullifiers: array expected"); + message.nullifiers = []; + for (var i = 0; i < object.nullifiers.length; ++i) + if (typeof object.nullifiers[i] === "string") + $util.base64.decode(object.nullifiers[i], message.nullifiers[i] = $util.newBuffer($util.base64.length(object.nullifiers[i])), 0); + else if (object.nullifiers[i].length >= 0) + message.nullifiers[i] = object.nullifiers[i]; + } + return message; + }; + + /** + * Creates a plain object from a BlockNullifierChanges message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @static + * @param {org.dash.platform.dapi.v0.BlockNullifierChanges} message BlockNullifierChanges + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + BlockNullifierChanges.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.nullifiers = []; + if (options.defaults) + if ($util.Long) { + var long = new $util.Long(0, 0, true); + object.blockHeight = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.blockHeight = options.longs === String ? "0" : 0; + if (message.blockHeight != null && message.hasOwnProperty("blockHeight")) + if (typeof message.blockHeight === "number") + object.blockHeight = options.longs === String ? String(message.blockHeight) : message.blockHeight; + else + object.blockHeight = options.longs === String ? $util.Long.prototype.toString.call(message.blockHeight) : options.longs === Number ? new $util.LongBits(message.blockHeight.low >>> 0, message.blockHeight.high >>> 0).toNumber(true) : message.blockHeight; + if (message.nullifiers && message.nullifiers.length) { + object.nullifiers = []; + for (var j = 0; j < message.nullifiers.length; ++j) + object.nullifiers[j] = options.bytes === String ? $util.base64.encode(message.nullifiers[j], 0, message.nullifiers[j].length) : options.bytes === Array ? Array.prototype.slice.call(message.nullifiers[j]) : message.nullifiers[j]; + } + return object; + }; + + /** + * Converts this BlockNullifierChanges to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.BlockNullifierChanges + * @instance + * @returns {Object.} JSON object + */ + BlockNullifierChanges.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return BlockNullifierChanges; + })(); + + v0.NullifierUpdateEntries = (function() { + + /** + * Properties of a NullifierUpdateEntries. + * @memberof org.dash.platform.dapi.v0 + * @interface INullifierUpdateEntries + * @property {Array.|null} [blockChanges] NullifierUpdateEntries blockChanges + */ + + /** + * Constructs a new NullifierUpdateEntries. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a NullifierUpdateEntries. + * @implements INullifierUpdateEntries + * @constructor + * @param {org.dash.platform.dapi.v0.INullifierUpdateEntries=} [properties] Properties to set + */ + function NullifierUpdateEntries(properties) { + this.blockChanges = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * NullifierUpdateEntries blockChanges. + * @member {Array.} blockChanges + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @instance + */ + NullifierUpdateEntries.prototype.blockChanges = $util.emptyArray; + + /** + * Creates a new NullifierUpdateEntries instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @static + * @param {org.dash.platform.dapi.v0.INullifierUpdateEntries=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.NullifierUpdateEntries} NullifierUpdateEntries instance + */ + NullifierUpdateEntries.create = function create(properties) { + return new NullifierUpdateEntries(properties); + }; + + /** + * Encodes the specified NullifierUpdateEntries message. Does not implicitly {@link org.dash.platform.dapi.v0.NullifierUpdateEntries.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @static + * @param {org.dash.platform.dapi.v0.INullifierUpdateEntries} message NullifierUpdateEntries message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + NullifierUpdateEntries.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.blockChanges != null && message.blockChanges.length) + for (var i = 0; i < message.blockChanges.length; ++i) + $root.org.dash.platform.dapi.v0.BlockNullifierChanges.encode(message.blockChanges[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified NullifierUpdateEntries message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.NullifierUpdateEntries.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @static + * @param {org.dash.platform.dapi.v0.INullifierUpdateEntries} message NullifierUpdateEntries message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + NullifierUpdateEntries.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a NullifierUpdateEntries message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.NullifierUpdateEntries} NullifierUpdateEntries + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + NullifierUpdateEntries.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.NullifierUpdateEntries(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (!(message.blockChanges && message.blockChanges.length)) + message.blockChanges = []; + message.blockChanges.push($root.org.dash.platform.dapi.v0.BlockNullifierChanges.decode(reader, reader.uint32())); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a NullifierUpdateEntries message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.NullifierUpdateEntries} NullifierUpdateEntries + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + NullifierUpdateEntries.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a NullifierUpdateEntries message. + * @function verify + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + NullifierUpdateEntries.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.blockChanges != null && message.hasOwnProperty("blockChanges")) { + if (!Array.isArray(message.blockChanges)) + return "blockChanges: array expected"; + for (var i = 0; i < message.blockChanges.length; ++i) { + var error = $root.org.dash.platform.dapi.v0.BlockNullifierChanges.verify(message.blockChanges[i]); + if (error) + return "blockChanges." + error; + } + } + return null; + }; + + /** + * Creates a NullifierUpdateEntries message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.NullifierUpdateEntries} NullifierUpdateEntries + */ + NullifierUpdateEntries.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.NullifierUpdateEntries) + return object; + var message = new $root.org.dash.platform.dapi.v0.NullifierUpdateEntries(); + if (object.blockChanges) { + if (!Array.isArray(object.blockChanges)) + throw TypeError(".org.dash.platform.dapi.v0.NullifierUpdateEntries.blockChanges: array expected"); + message.blockChanges = []; + for (var i = 0; i < object.blockChanges.length; ++i) { + if (typeof object.blockChanges[i] !== "object") + throw TypeError(".org.dash.platform.dapi.v0.NullifierUpdateEntries.blockChanges: object expected"); + message.blockChanges[i] = $root.org.dash.platform.dapi.v0.BlockNullifierChanges.fromObject(object.blockChanges[i]); + } + } + return message; + }; + + /** + * Creates a plain object from a NullifierUpdateEntries message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @static + * @param {org.dash.platform.dapi.v0.NullifierUpdateEntries} message NullifierUpdateEntries + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + NullifierUpdateEntries.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.blockChanges = []; + if (message.blockChanges && message.blockChanges.length) { + object.blockChanges = []; + for (var j = 0; j < message.blockChanges.length; ++j) + object.blockChanges[j] = $root.org.dash.platform.dapi.v0.BlockNullifierChanges.toObject(message.blockChanges[j], options); + } + return object; + }; + + /** + * Converts this NullifierUpdateEntries to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.NullifierUpdateEntries + * @instance + * @returns {Object.} JSON object + */ + NullifierUpdateEntries.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return NullifierUpdateEntries; + })(); + + v0.GetRecentNullifierChangesRequest = (function() { + + /** + * Properties of a GetRecentNullifierChangesRequest. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetRecentNullifierChangesRequest + * @property {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.IGetRecentNullifierChangesRequestV0|null} [v0] GetRecentNullifierChangesRequest v0 + */ + + /** + * Constructs a new GetRecentNullifierChangesRequest. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetRecentNullifierChangesRequest. + * @implements IGetRecentNullifierChangesRequest + * @constructor + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesRequest=} [properties] Properties to set + */ + function GetRecentNullifierChangesRequest(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetRecentNullifierChangesRequest v0. + * @member {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.IGetRecentNullifierChangesRequestV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @instance + */ + GetRecentNullifierChangesRequest.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetRecentNullifierChangesRequest version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @instance + */ + Object.defineProperty(GetRecentNullifierChangesRequest.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetRecentNullifierChangesRequest instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesRequest=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} GetRecentNullifierChangesRequest instance + */ + GetRecentNullifierChangesRequest.create = function create(properties) { + return new GetRecentNullifierChangesRequest(properties); + }; + + /** + * Encodes the specified GetRecentNullifierChangesRequest message. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesRequest} message GetRecentNullifierChangesRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentNullifierChangesRequest.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetRecentNullifierChangesRequest message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesRequest} message GetRecentNullifierChangesRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentNullifierChangesRequest.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetRecentNullifierChangesRequest message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} GetRecentNullifierChangesRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentNullifierChangesRequest.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetRecentNullifierChangesRequest message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} GetRecentNullifierChangesRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentNullifierChangesRequest.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetRecentNullifierChangesRequest message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetRecentNullifierChangesRequest.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetRecentNullifierChangesRequest message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} GetRecentNullifierChangesRequest + */ + GetRecentNullifierChangesRequest.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetRecentNullifierChangesRequest message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} message GetRecentNullifierChangesRequest + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetRecentNullifierChangesRequest.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetRecentNullifierChangesRequest to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @instance + * @returns {Object.} JSON object + */ + GetRecentNullifierChangesRequest.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 = (function() { + + /** + * Properties of a GetRecentNullifierChangesRequestV0. + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @interface IGetRecentNullifierChangesRequestV0 + * @property {number|Long|null} [startHeight] GetRecentNullifierChangesRequestV0 startHeight + * @property {boolean|null} [prove] GetRecentNullifierChangesRequestV0 prove + */ + + /** + * Constructs a new GetRecentNullifierChangesRequestV0. + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest + * @classdesc Represents a GetRecentNullifierChangesRequestV0. + * @implements IGetRecentNullifierChangesRequestV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.IGetRecentNullifierChangesRequestV0=} [properties] Properties to set + */ + function GetRecentNullifierChangesRequestV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetRecentNullifierChangesRequestV0 startHeight. + * @member {number|Long} startHeight + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @instance + */ + GetRecentNullifierChangesRequestV0.prototype.startHeight = $util.Long ? $util.Long.fromBits(0,0,true) : 0; + + /** + * GetRecentNullifierChangesRequestV0 prove. + * @member {boolean} prove + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @instance + */ + GetRecentNullifierChangesRequestV0.prototype.prove = false; + + /** + * Creates a new GetRecentNullifierChangesRequestV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.IGetRecentNullifierChangesRequestV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} GetRecentNullifierChangesRequestV0 instance + */ + GetRecentNullifierChangesRequestV0.create = function create(properties) { + return new GetRecentNullifierChangesRequestV0(properties); + }; + + /** + * Encodes the specified GetRecentNullifierChangesRequestV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.IGetRecentNullifierChangesRequestV0} message GetRecentNullifierChangesRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentNullifierChangesRequestV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.startHeight != null && Object.hasOwnProperty.call(message, "startHeight")) + writer.uint32(/* id 1, wireType 0 =*/8).uint64(message.startHeight); + if (message.prove != null && Object.hasOwnProperty.call(message, "prove")) + writer.uint32(/* id 2, wireType 0 =*/16).bool(message.prove); + return writer; + }; + + /** + * Encodes the specified GetRecentNullifierChangesRequestV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.IGetRecentNullifierChangesRequestV0} message GetRecentNullifierChangesRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentNullifierChangesRequestV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetRecentNullifierChangesRequestV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} GetRecentNullifierChangesRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentNullifierChangesRequestV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.startHeight = reader.uint64(); + break; + case 2: + message.prove = reader.bool(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetRecentNullifierChangesRequestV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} GetRecentNullifierChangesRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentNullifierChangesRequestV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetRecentNullifierChangesRequestV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetRecentNullifierChangesRequestV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.startHeight != null && message.hasOwnProperty("startHeight")) + if (!$util.isInteger(message.startHeight) && !(message.startHeight && $util.isInteger(message.startHeight.low) && $util.isInteger(message.startHeight.high))) + return "startHeight: integer|Long expected"; + if (message.prove != null && message.hasOwnProperty("prove")) + if (typeof message.prove !== "boolean") + return "prove: boolean expected"; + return null; + }; + + /** + * Creates a GetRecentNullifierChangesRequestV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} GetRecentNullifierChangesRequestV0 + */ + GetRecentNullifierChangesRequestV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0(); + if (object.startHeight != null) + if ($util.Long) + (message.startHeight = $util.Long.fromValue(object.startHeight)).unsigned = true; + else if (typeof object.startHeight === "string") + message.startHeight = parseInt(object.startHeight, 10); + else if (typeof object.startHeight === "number") + message.startHeight = object.startHeight; + else if (typeof object.startHeight === "object") + message.startHeight = new $util.LongBits(object.startHeight.low >>> 0, object.startHeight.high >>> 0).toNumber(true); + if (object.prove != null) + message.prove = Boolean(object.prove); + return message; + }; + + /** + * Creates a plain object from a GetRecentNullifierChangesRequestV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} message GetRecentNullifierChangesRequestV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetRecentNullifierChangesRequestV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + if ($util.Long) { + var long = new $util.Long(0, 0, true); + object.startHeight = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.startHeight = options.longs === String ? "0" : 0; + object.prove = false; + } + if (message.startHeight != null && message.hasOwnProperty("startHeight")) + if (typeof message.startHeight === "number") + object.startHeight = options.longs === String ? String(message.startHeight) : message.startHeight; + else + object.startHeight = options.longs === String ? $util.Long.prototype.toString.call(message.startHeight) : options.longs === Number ? new $util.LongBits(message.startHeight.low >>> 0, message.startHeight.high >>> 0).toNumber(true) : message.startHeight; + if (message.prove != null && message.hasOwnProperty("prove")) + object.prove = message.prove; + return object; + }; + + /** + * Converts this GetRecentNullifierChangesRequestV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 + * @instance + * @returns {Object.} JSON object + */ + GetRecentNullifierChangesRequestV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetRecentNullifierChangesRequestV0; + })(); + + return GetRecentNullifierChangesRequest; + })(); + + v0.GetRecentNullifierChangesResponse = (function() { + + /** + * Properties of a GetRecentNullifierChangesResponse. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetRecentNullifierChangesResponse + * @property {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.IGetRecentNullifierChangesResponseV0|null} [v0] GetRecentNullifierChangesResponse v0 + */ + + /** + * Constructs a new GetRecentNullifierChangesResponse. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetRecentNullifierChangesResponse. + * @implements IGetRecentNullifierChangesResponse + * @constructor + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesResponse=} [properties] Properties to set + */ + function GetRecentNullifierChangesResponse(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetRecentNullifierChangesResponse v0. + * @member {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.IGetRecentNullifierChangesResponseV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @instance + */ + GetRecentNullifierChangesResponse.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetRecentNullifierChangesResponse version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @instance + */ + Object.defineProperty(GetRecentNullifierChangesResponse.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetRecentNullifierChangesResponse instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesResponse=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} GetRecentNullifierChangesResponse instance + */ + GetRecentNullifierChangesResponse.create = function create(properties) { + return new GetRecentNullifierChangesResponse(properties); + }; + + /** + * Encodes the specified GetRecentNullifierChangesResponse message. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesResponse} message GetRecentNullifierChangesResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentNullifierChangesResponse.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetRecentNullifierChangesResponse message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentNullifierChangesResponse} message GetRecentNullifierChangesResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentNullifierChangesResponse.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetRecentNullifierChangesResponse message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} GetRecentNullifierChangesResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentNullifierChangesResponse.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetRecentNullifierChangesResponse message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} GetRecentNullifierChangesResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentNullifierChangesResponse.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetRecentNullifierChangesResponse message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetRecentNullifierChangesResponse.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetRecentNullifierChangesResponse message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} GetRecentNullifierChangesResponse + */ + GetRecentNullifierChangesResponse.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetRecentNullifierChangesResponse message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} message GetRecentNullifierChangesResponse + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetRecentNullifierChangesResponse.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetRecentNullifierChangesResponse to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @instance + * @returns {Object.} JSON object + */ + GetRecentNullifierChangesResponse.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 = (function() { + + /** + * Properties of a GetRecentNullifierChangesResponseV0. + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @interface IGetRecentNullifierChangesResponseV0 + * @property {org.dash.platform.dapi.v0.INullifierUpdateEntries|null} [nullifierUpdateEntries] GetRecentNullifierChangesResponseV0 nullifierUpdateEntries + * @property {org.dash.platform.dapi.v0.IProof|null} [proof] GetRecentNullifierChangesResponseV0 proof + * @property {org.dash.platform.dapi.v0.IResponseMetadata|null} [metadata] GetRecentNullifierChangesResponseV0 metadata + */ + + /** + * Constructs a new GetRecentNullifierChangesResponseV0. + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse + * @classdesc Represents a GetRecentNullifierChangesResponseV0. + * @implements IGetRecentNullifierChangesResponseV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.IGetRecentNullifierChangesResponseV0=} [properties] Properties to set + */ + function GetRecentNullifierChangesResponseV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetRecentNullifierChangesResponseV0 nullifierUpdateEntries. + * @member {org.dash.platform.dapi.v0.INullifierUpdateEntries|null|undefined} nullifierUpdateEntries + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @instance + */ + GetRecentNullifierChangesResponseV0.prototype.nullifierUpdateEntries = null; + + /** + * GetRecentNullifierChangesResponseV0 proof. + * @member {org.dash.platform.dapi.v0.IProof|null|undefined} proof + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @instance + */ + GetRecentNullifierChangesResponseV0.prototype.proof = null; + + /** + * GetRecentNullifierChangesResponseV0 metadata. + * @member {org.dash.platform.dapi.v0.IResponseMetadata|null|undefined} metadata + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @instance + */ + GetRecentNullifierChangesResponseV0.prototype.metadata = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetRecentNullifierChangesResponseV0 result. + * @member {"nullifierUpdateEntries"|"proof"|undefined} result + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @instance + */ + Object.defineProperty(GetRecentNullifierChangesResponseV0.prototype, "result", { + get: $util.oneOfGetter($oneOfFields = ["nullifierUpdateEntries", "proof"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetRecentNullifierChangesResponseV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.IGetRecentNullifierChangesResponseV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} GetRecentNullifierChangesResponseV0 instance + */ + GetRecentNullifierChangesResponseV0.create = function create(properties) { + return new GetRecentNullifierChangesResponseV0(properties); + }; + + /** + * Encodes the specified GetRecentNullifierChangesResponseV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.IGetRecentNullifierChangesResponseV0} message GetRecentNullifierChangesResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentNullifierChangesResponseV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.nullifierUpdateEntries != null && Object.hasOwnProperty.call(message, "nullifierUpdateEntries")) + $root.org.dash.platform.dapi.v0.NullifierUpdateEntries.encode(message.nullifierUpdateEntries, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + if (message.proof != null && Object.hasOwnProperty.call(message, "proof")) + $root.org.dash.platform.dapi.v0.Proof.encode(message.proof, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + if (message.metadata != null && Object.hasOwnProperty.call(message, "metadata")) + $root.org.dash.platform.dapi.v0.ResponseMetadata.encode(message.metadata, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetRecentNullifierChangesResponseV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.IGetRecentNullifierChangesResponseV0} message GetRecentNullifierChangesResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentNullifierChangesResponseV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetRecentNullifierChangesResponseV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} GetRecentNullifierChangesResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentNullifierChangesResponseV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.nullifierUpdateEntries = $root.org.dash.platform.dapi.v0.NullifierUpdateEntries.decode(reader, reader.uint32()); + break; + case 2: + message.proof = $root.org.dash.platform.dapi.v0.Proof.decode(reader, reader.uint32()); + break; + case 3: + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetRecentNullifierChangesResponseV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} GetRecentNullifierChangesResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentNullifierChangesResponseV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetRecentNullifierChangesResponseV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetRecentNullifierChangesResponseV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.nullifierUpdateEntries != null && message.hasOwnProperty("nullifierUpdateEntries")) { + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.NullifierUpdateEntries.verify(message.nullifierUpdateEntries); + if (error) + return "nullifierUpdateEntries." + error; + } + } + if (message.proof != null && message.hasOwnProperty("proof")) { + if (properties.result === 1) + return "result: multiple values"; + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.Proof.verify(message.proof); + if (error) + return "proof." + error; + } + } + if (message.metadata != null && message.hasOwnProperty("metadata")) { + var error = $root.org.dash.platform.dapi.v0.ResponseMetadata.verify(message.metadata); + if (error) + return "metadata." + error; + } + return null; + }; + + /** + * Creates a GetRecentNullifierChangesResponseV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} GetRecentNullifierChangesResponseV0 + */ + GetRecentNullifierChangesResponseV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0(); + if (object.nullifierUpdateEntries != null) { + if (typeof object.nullifierUpdateEntries !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.nullifierUpdateEntries: object expected"); + message.nullifierUpdateEntries = $root.org.dash.platform.dapi.v0.NullifierUpdateEntries.fromObject(object.nullifierUpdateEntries); + } + if (object.proof != null) { + if (typeof object.proof !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.proof: object expected"); + message.proof = $root.org.dash.platform.dapi.v0.Proof.fromObject(object.proof); + } + if (object.metadata != null) { + if (typeof object.metadata !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.metadata: object expected"); + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.fromObject(object.metadata); + } + return message; + }; + + /** + * Creates a plain object from a GetRecentNullifierChangesResponseV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} message GetRecentNullifierChangesResponseV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetRecentNullifierChangesResponseV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.metadata = null; + if (message.nullifierUpdateEntries != null && message.hasOwnProperty("nullifierUpdateEntries")) { + object.nullifierUpdateEntries = $root.org.dash.platform.dapi.v0.NullifierUpdateEntries.toObject(message.nullifierUpdateEntries, options); + if (options.oneofs) + object.result = "nullifierUpdateEntries"; + } + if (message.proof != null && message.hasOwnProperty("proof")) { + object.proof = $root.org.dash.platform.dapi.v0.Proof.toObject(message.proof, options); + if (options.oneofs) + object.result = "proof"; + } + if (message.metadata != null && message.hasOwnProperty("metadata")) + object.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.toObject(message.metadata, options); + return object; + }; + + /** + * Converts this GetRecentNullifierChangesResponseV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 + * @instance + * @returns {Object.} JSON object + */ + GetRecentNullifierChangesResponseV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetRecentNullifierChangesResponseV0; + })(); + + return GetRecentNullifierChangesResponse; + })(); + + v0.CompactedBlockNullifierChanges = (function() { + + /** + * Properties of a CompactedBlockNullifierChanges. + * @memberof org.dash.platform.dapi.v0 + * @interface ICompactedBlockNullifierChanges + * @property {number|Long|null} [startBlockHeight] CompactedBlockNullifierChanges startBlockHeight + * @property {number|Long|null} [endBlockHeight] CompactedBlockNullifierChanges endBlockHeight + * @property {Array.|null} [nullifiers] CompactedBlockNullifierChanges nullifiers + */ + + /** + * Constructs a new CompactedBlockNullifierChanges. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a CompactedBlockNullifierChanges. + * @implements ICompactedBlockNullifierChanges + * @constructor + * @param {org.dash.platform.dapi.v0.ICompactedBlockNullifierChanges=} [properties] Properties to set + */ + function CompactedBlockNullifierChanges(properties) { + this.nullifiers = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * CompactedBlockNullifierChanges startBlockHeight. + * @member {number|Long} startBlockHeight + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @instance + */ + CompactedBlockNullifierChanges.prototype.startBlockHeight = $util.Long ? $util.Long.fromBits(0,0,true) : 0; + + /** + * CompactedBlockNullifierChanges endBlockHeight. + * @member {number|Long} endBlockHeight + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @instance + */ + CompactedBlockNullifierChanges.prototype.endBlockHeight = $util.Long ? $util.Long.fromBits(0,0,true) : 0; + + /** + * CompactedBlockNullifierChanges nullifiers. + * @member {Array.} nullifiers + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @instance + */ + CompactedBlockNullifierChanges.prototype.nullifiers = $util.emptyArray; + + /** + * Creates a new CompactedBlockNullifierChanges instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @static + * @param {org.dash.platform.dapi.v0.ICompactedBlockNullifierChanges=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} CompactedBlockNullifierChanges instance + */ + CompactedBlockNullifierChanges.create = function create(properties) { + return new CompactedBlockNullifierChanges(properties); + }; + + /** + * Encodes the specified CompactedBlockNullifierChanges message. Does not implicitly {@link org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @static + * @param {org.dash.platform.dapi.v0.ICompactedBlockNullifierChanges} message CompactedBlockNullifierChanges message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + CompactedBlockNullifierChanges.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.startBlockHeight != null && Object.hasOwnProperty.call(message, "startBlockHeight")) + writer.uint32(/* id 1, wireType 0 =*/8).uint64(message.startBlockHeight); + if (message.endBlockHeight != null && Object.hasOwnProperty.call(message, "endBlockHeight")) + writer.uint32(/* id 2, wireType 0 =*/16).uint64(message.endBlockHeight); + if (message.nullifiers != null && message.nullifiers.length) + for (var i = 0; i < message.nullifiers.length; ++i) + writer.uint32(/* id 3, wireType 2 =*/26).bytes(message.nullifiers[i]); + return writer; + }; + + /** + * Encodes the specified CompactedBlockNullifierChanges message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @static + * @param {org.dash.platform.dapi.v0.ICompactedBlockNullifierChanges} message CompactedBlockNullifierChanges message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + CompactedBlockNullifierChanges.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a CompactedBlockNullifierChanges message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} CompactedBlockNullifierChanges + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + CompactedBlockNullifierChanges.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.startBlockHeight = reader.uint64(); + break; + case 2: + message.endBlockHeight = reader.uint64(); + break; + case 3: + if (!(message.nullifiers && message.nullifiers.length)) + message.nullifiers = []; + message.nullifiers.push(reader.bytes()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a CompactedBlockNullifierChanges message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} CompactedBlockNullifierChanges + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + CompactedBlockNullifierChanges.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a CompactedBlockNullifierChanges message. + * @function verify + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + CompactedBlockNullifierChanges.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.startBlockHeight != null && message.hasOwnProperty("startBlockHeight")) + if (!$util.isInteger(message.startBlockHeight) && !(message.startBlockHeight && $util.isInteger(message.startBlockHeight.low) && $util.isInteger(message.startBlockHeight.high))) + return "startBlockHeight: integer|Long expected"; + if (message.endBlockHeight != null && message.hasOwnProperty("endBlockHeight")) + if (!$util.isInteger(message.endBlockHeight) && !(message.endBlockHeight && $util.isInteger(message.endBlockHeight.low) && $util.isInteger(message.endBlockHeight.high))) + return "endBlockHeight: integer|Long expected"; + if (message.nullifiers != null && message.hasOwnProperty("nullifiers")) { + if (!Array.isArray(message.nullifiers)) + return "nullifiers: array expected"; + for (var i = 0; i < message.nullifiers.length; ++i) + if (!(message.nullifiers[i] && typeof message.nullifiers[i].length === "number" || $util.isString(message.nullifiers[i]))) + return "nullifiers: buffer[] expected"; + } + return null; + }; + + /** + * Creates a CompactedBlockNullifierChanges message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} CompactedBlockNullifierChanges + */ + CompactedBlockNullifierChanges.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges) + return object; + var message = new $root.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges(); + if (object.startBlockHeight != null) + if ($util.Long) + (message.startBlockHeight = $util.Long.fromValue(object.startBlockHeight)).unsigned = true; + else if (typeof object.startBlockHeight === "string") + message.startBlockHeight = parseInt(object.startBlockHeight, 10); + else if (typeof object.startBlockHeight === "number") + message.startBlockHeight = object.startBlockHeight; + else if (typeof object.startBlockHeight === "object") + message.startBlockHeight = new $util.LongBits(object.startBlockHeight.low >>> 0, object.startBlockHeight.high >>> 0).toNumber(true); + if (object.endBlockHeight != null) + if ($util.Long) + (message.endBlockHeight = $util.Long.fromValue(object.endBlockHeight)).unsigned = true; + else if (typeof object.endBlockHeight === "string") + message.endBlockHeight = parseInt(object.endBlockHeight, 10); + else if (typeof object.endBlockHeight === "number") + message.endBlockHeight = object.endBlockHeight; + else if (typeof object.endBlockHeight === "object") + message.endBlockHeight = new $util.LongBits(object.endBlockHeight.low >>> 0, object.endBlockHeight.high >>> 0).toNumber(true); + if (object.nullifiers) { + if (!Array.isArray(object.nullifiers)) + throw TypeError(".org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.nullifiers: array expected"); + message.nullifiers = []; + for (var i = 0; i < object.nullifiers.length; ++i) + if (typeof object.nullifiers[i] === "string") + $util.base64.decode(object.nullifiers[i], message.nullifiers[i] = $util.newBuffer($util.base64.length(object.nullifiers[i])), 0); + else if (object.nullifiers[i].length >= 0) + message.nullifiers[i] = object.nullifiers[i]; + } + return message; + }; + + /** + * Creates a plain object from a CompactedBlockNullifierChanges message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @static + * @param {org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} message CompactedBlockNullifierChanges + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + CompactedBlockNullifierChanges.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.nullifiers = []; + if (options.defaults) { + if ($util.Long) { + var long = new $util.Long(0, 0, true); + object.startBlockHeight = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.startBlockHeight = options.longs === String ? "0" : 0; + if ($util.Long) { + var long = new $util.Long(0, 0, true); + object.endBlockHeight = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.endBlockHeight = options.longs === String ? "0" : 0; + } + if (message.startBlockHeight != null && message.hasOwnProperty("startBlockHeight")) + if (typeof message.startBlockHeight === "number") + object.startBlockHeight = options.longs === String ? String(message.startBlockHeight) : message.startBlockHeight; + else + object.startBlockHeight = options.longs === String ? $util.Long.prototype.toString.call(message.startBlockHeight) : options.longs === Number ? new $util.LongBits(message.startBlockHeight.low >>> 0, message.startBlockHeight.high >>> 0).toNumber(true) : message.startBlockHeight; + if (message.endBlockHeight != null && message.hasOwnProperty("endBlockHeight")) + if (typeof message.endBlockHeight === "number") + object.endBlockHeight = options.longs === String ? String(message.endBlockHeight) : message.endBlockHeight; + else + object.endBlockHeight = options.longs === String ? $util.Long.prototype.toString.call(message.endBlockHeight) : options.longs === Number ? new $util.LongBits(message.endBlockHeight.low >>> 0, message.endBlockHeight.high >>> 0).toNumber(true) : message.endBlockHeight; + if (message.nullifiers && message.nullifiers.length) { + object.nullifiers = []; + for (var j = 0; j < message.nullifiers.length; ++j) + object.nullifiers[j] = options.bytes === String ? $util.base64.encode(message.nullifiers[j], 0, message.nullifiers[j].length) : options.bytes === Array ? Array.prototype.slice.call(message.nullifiers[j]) : message.nullifiers[j]; + } + return object; + }; + + /** + * Converts this CompactedBlockNullifierChanges to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.CompactedBlockNullifierChanges + * @instance + * @returns {Object.} JSON object + */ + CompactedBlockNullifierChanges.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return CompactedBlockNullifierChanges; + })(); + + v0.CompactedNullifierUpdateEntries = (function() { + + /** + * Properties of a CompactedNullifierUpdateEntries. + * @memberof org.dash.platform.dapi.v0 + * @interface ICompactedNullifierUpdateEntries + * @property {Array.|null} [compactedBlockChanges] CompactedNullifierUpdateEntries compactedBlockChanges + */ + + /** + * Constructs a new CompactedNullifierUpdateEntries. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a CompactedNullifierUpdateEntries. + * @implements ICompactedNullifierUpdateEntries + * @constructor + * @param {org.dash.platform.dapi.v0.ICompactedNullifierUpdateEntries=} [properties] Properties to set + */ + function CompactedNullifierUpdateEntries(properties) { + this.compactedBlockChanges = []; + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * CompactedNullifierUpdateEntries compactedBlockChanges. + * @member {Array.} compactedBlockChanges + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @instance + */ + CompactedNullifierUpdateEntries.prototype.compactedBlockChanges = $util.emptyArray; + + /** + * Creates a new CompactedNullifierUpdateEntries instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @static + * @param {org.dash.platform.dapi.v0.ICompactedNullifierUpdateEntries=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} CompactedNullifierUpdateEntries instance + */ + CompactedNullifierUpdateEntries.create = function create(properties) { + return new CompactedNullifierUpdateEntries(properties); + }; + + /** + * Encodes the specified CompactedNullifierUpdateEntries message. Does not implicitly {@link org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @static + * @param {org.dash.platform.dapi.v0.ICompactedNullifierUpdateEntries} message CompactedNullifierUpdateEntries message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + CompactedNullifierUpdateEntries.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.compactedBlockChanges != null && message.compactedBlockChanges.length) + for (var i = 0; i < message.compactedBlockChanges.length; ++i) + $root.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.encode(message.compactedBlockChanges[i], writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified CompactedNullifierUpdateEntries message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @static + * @param {org.dash.platform.dapi.v0.ICompactedNullifierUpdateEntries} message CompactedNullifierUpdateEntries message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + CompactedNullifierUpdateEntries.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a CompactedNullifierUpdateEntries message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} CompactedNullifierUpdateEntries + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + CompactedNullifierUpdateEntries.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + if (!(message.compactedBlockChanges && message.compactedBlockChanges.length)) + message.compactedBlockChanges = []; + message.compactedBlockChanges.push($root.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.decode(reader, reader.uint32())); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a CompactedNullifierUpdateEntries message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} CompactedNullifierUpdateEntries + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + CompactedNullifierUpdateEntries.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a CompactedNullifierUpdateEntries message. + * @function verify + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + CompactedNullifierUpdateEntries.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.compactedBlockChanges != null && message.hasOwnProperty("compactedBlockChanges")) { + if (!Array.isArray(message.compactedBlockChanges)) + return "compactedBlockChanges: array expected"; + for (var i = 0; i < message.compactedBlockChanges.length; ++i) { + var error = $root.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.verify(message.compactedBlockChanges[i]); + if (error) + return "compactedBlockChanges." + error; + } + } + return null; + }; + + /** + * Creates a CompactedNullifierUpdateEntries message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} CompactedNullifierUpdateEntries + */ + CompactedNullifierUpdateEntries.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries) + return object; + var message = new $root.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries(); + if (object.compactedBlockChanges) { + if (!Array.isArray(object.compactedBlockChanges)) + throw TypeError(".org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.compactedBlockChanges: array expected"); + message.compactedBlockChanges = []; + for (var i = 0; i < object.compactedBlockChanges.length; ++i) { + if (typeof object.compactedBlockChanges[i] !== "object") + throw TypeError(".org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.compactedBlockChanges: object expected"); + message.compactedBlockChanges[i] = $root.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.fromObject(object.compactedBlockChanges[i]); + } + } + return message; + }; + + /** + * Creates a plain object from a CompactedNullifierUpdateEntries message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @static + * @param {org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} message CompactedNullifierUpdateEntries + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + CompactedNullifierUpdateEntries.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.arrays || options.defaults) + object.compactedBlockChanges = []; + if (message.compactedBlockChanges && message.compactedBlockChanges.length) { + object.compactedBlockChanges = []; + for (var j = 0; j < message.compactedBlockChanges.length; ++j) + object.compactedBlockChanges[j] = $root.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.toObject(message.compactedBlockChanges[j], options); + } + return object; + }; + + /** + * Converts this CompactedNullifierUpdateEntries to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries + * @instance + * @returns {Object.} JSON object + */ + CompactedNullifierUpdateEntries.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return CompactedNullifierUpdateEntries; + })(); + + v0.GetRecentCompactedNullifierChangesRequest = (function() { + + /** + * Properties of a GetRecentCompactedNullifierChangesRequest. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetRecentCompactedNullifierChangesRequest + * @property {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.IGetRecentCompactedNullifierChangesRequestV0|null} [v0] GetRecentCompactedNullifierChangesRequest v0 + */ + + /** + * Constructs a new GetRecentCompactedNullifierChangesRequest. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetRecentCompactedNullifierChangesRequest. + * @implements IGetRecentCompactedNullifierChangesRequest + * @constructor + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesRequest=} [properties] Properties to set + */ + function GetRecentCompactedNullifierChangesRequest(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetRecentCompactedNullifierChangesRequest v0. + * @member {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.IGetRecentCompactedNullifierChangesRequestV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @instance + */ + GetRecentCompactedNullifierChangesRequest.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetRecentCompactedNullifierChangesRequest version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @instance + */ + Object.defineProperty(GetRecentCompactedNullifierChangesRequest.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetRecentCompactedNullifierChangesRequest instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesRequest=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} GetRecentCompactedNullifierChangesRequest instance + */ + GetRecentCompactedNullifierChangesRequest.create = function create(properties) { + return new GetRecentCompactedNullifierChangesRequest(properties); + }; + + /** + * Encodes the specified GetRecentCompactedNullifierChangesRequest message. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesRequest} message GetRecentCompactedNullifierChangesRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentCompactedNullifierChangesRequest.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetRecentCompactedNullifierChangesRequest message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesRequest} message GetRecentCompactedNullifierChangesRequest message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentCompactedNullifierChangesRequest.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetRecentCompactedNullifierChangesRequest message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} GetRecentCompactedNullifierChangesRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentCompactedNullifierChangesRequest.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetRecentCompactedNullifierChangesRequest message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} GetRecentCompactedNullifierChangesRequest + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentCompactedNullifierChangesRequest.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetRecentCompactedNullifierChangesRequest message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetRecentCompactedNullifierChangesRequest.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetRecentCompactedNullifierChangesRequest message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} GetRecentCompactedNullifierChangesRequest + */ + GetRecentCompactedNullifierChangesRequest.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetRecentCompactedNullifierChangesRequest message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} message GetRecentCompactedNullifierChangesRequest + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetRecentCompactedNullifierChangesRequest.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetRecentCompactedNullifierChangesRequest to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @instance + * @returns {Object.} JSON object + */ + GetRecentCompactedNullifierChangesRequest.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 = (function() { + + /** + * Properties of a GetRecentCompactedNullifierChangesRequestV0. + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @interface IGetRecentCompactedNullifierChangesRequestV0 + * @property {number|Long|null} [startBlockHeight] GetRecentCompactedNullifierChangesRequestV0 startBlockHeight + * @property {boolean|null} [prove] GetRecentCompactedNullifierChangesRequestV0 prove + */ + + /** + * Constructs a new GetRecentCompactedNullifierChangesRequestV0. + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest + * @classdesc Represents a GetRecentCompactedNullifierChangesRequestV0. + * @implements IGetRecentCompactedNullifierChangesRequestV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.IGetRecentCompactedNullifierChangesRequestV0=} [properties] Properties to set + */ + function GetRecentCompactedNullifierChangesRequestV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetRecentCompactedNullifierChangesRequestV0 startBlockHeight. + * @member {number|Long} startBlockHeight + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @instance + */ + GetRecentCompactedNullifierChangesRequestV0.prototype.startBlockHeight = $util.Long ? $util.Long.fromBits(0,0,true) : 0; + + /** + * GetRecentCompactedNullifierChangesRequestV0 prove. + * @member {boolean} prove + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @instance + */ + GetRecentCompactedNullifierChangesRequestV0.prototype.prove = false; + + /** + * Creates a new GetRecentCompactedNullifierChangesRequestV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.IGetRecentCompactedNullifierChangesRequestV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} GetRecentCompactedNullifierChangesRequestV0 instance + */ + GetRecentCompactedNullifierChangesRequestV0.create = function create(properties) { + return new GetRecentCompactedNullifierChangesRequestV0(properties); + }; + + /** + * Encodes the specified GetRecentCompactedNullifierChangesRequestV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.IGetRecentCompactedNullifierChangesRequestV0} message GetRecentCompactedNullifierChangesRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentCompactedNullifierChangesRequestV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.startBlockHeight != null && Object.hasOwnProperty.call(message, "startBlockHeight")) + writer.uint32(/* id 1, wireType 0 =*/8).uint64(message.startBlockHeight); + if (message.prove != null && Object.hasOwnProperty.call(message, "prove")) + writer.uint32(/* id 2, wireType 0 =*/16).bool(message.prove); + return writer; + }; + + /** + * Encodes the specified GetRecentCompactedNullifierChangesRequestV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.IGetRecentCompactedNullifierChangesRequestV0} message GetRecentCompactedNullifierChangesRequestV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentCompactedNullifierChangesRequestV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetRecentCompactedNullifierChangesRequestV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} GetRecentCompactedNullifierChangesRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentCompactedNullifierChangesRequestV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.startBlockHeight = reader.uint64(); + break; + case 2: + message.prove = reader.bool(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetRecentCompactedNullifierChangesRequestV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} GetRecentCompactedNullifierChangesRequestV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentCompactedNullifierChangesRequestV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetRecentCompactedNullifierChangesRequestV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetRecentCompactedNullifierChangesRequestV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + if (message.startBlockHeight != null && message.hasOwnProperty("startBlockHeight")) + if (!$util.isInteger(message.startBlockHeight) && !(message.startBlockHeight && $util.isInteger(message.startBlockHeight.low) && $util.isInteger(message.startBlockHeight.high))) + return "startBlockHeight: integer|Long expected"; + if (message.prove != null && message.hasOwnProperty("prove")) + if (typeof message.prove !== "boolean") + return "prove: boolean expected"; + return null; + }; + + /** + * Creates a GetRecentCompactedNullifierChangesRequestV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} GetRecentCompactedNullifierChangesRequestV0 + */ + GetRecentCompactedNullifierChangesRequestV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0(); + if (object.startBlockHeight != null) + if ($util.Long) + (message.startBlockHeight = $util.Long.fromValue(object.startBlockHeight)).unsigned = true; + else if (typeof object.startBlockHeight === "string") + message.startBlockHeight = parseInt(object.startBlockHeight, 10); + else if (typeof object.startBlockHeight === "number") + message.startBlockHeight = object.startBlockHeight; + else if (typeof object.startBlockHeight === "object") + message.startBlockHeight = new $util.LongBits(object.startBlockHeight.low >>> 0, object.startBlockHeight.high >>> 0).toNumber(true); + if (object.prove != null) + message.prove = Boolean(object.prove); + return message; + }; + + /** + * Creates a plain object from a GetRecentCompactedNullifierChangesRequestV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} message GetRecentCompactedNullifierChangesRequestV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetRecentCompactedNullifierChangesRequestV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) { + if ($util.Long) { + var long = new $util.Long(0, 0, true); + object.startBlockHeight = options.longs === String ? long.toString() : options.longs === Number ? long.toNumber() : long; + } else + object.startBlockHeight = options.longs === String ? "0" : 0; + object.prove = false; + } + if (message.startBlockHeight != null && message.hasOwnProperty("startBlockHeight")) + if (typeof message.startBlockHeight === "number") + object.startBlockHeight = options.longs === String ? String(message.startBlockHeight) : message.startBlockHeight; + else + object.startBlockHeight = options.longs === String ? $util.Long.prototype.toString.call(message.startBlockHeight) : options.longs === Number ? new $util.LongBits(message.startBlockHeight.low >>> 0, message.startBlockHeight.high >>> 0).toNumber(true) : message.startBlockHeight; + if (message.prove != null && message.hasOwnProperty("prove")) + object.prove = message.prove; + return object; + }; + + /** + * Converts this GetRecentCompactedNullifierChangesRequestV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 + * @instance + * @returns {Object.} JSON object + */ + GetRecentCompactedNullifierChangesRequestV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetRecentCompactedNullifierChangesRequestV0; + })(); + + return GetRecentCompactedNullifierChangesRequest; + })(); + + v0.GetRecentCompactedNullifierChangesResponse = (function() { + + /** + * Properties of a GetRecentCompactedNullifierChangesResponse. + * @memberof org.dash.platform.dapi.v0 + * @interface IGetRecentCompactedNullifierChangesResponse + * @property {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.IGetRecentCompactedNullifierChangesResponseV0|null} [v0] GetRecentCompactedNullifierChangesResponse v0 + */ + + /** + * Constructs a new GetRecentCompactedNullifierChangesResponse. + * @memberof org.dash.platform.dapi.v0 + * @classdesc Represents a GetRecentCompactedNullifierChangesResponse. + * @implements IGetRecentCompactedNullifierChangesResponse + * @constructor + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesResponse=} [properties] Properties to set + */ + function GetRecentCompactedNullifierChangesResponse(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetRecentCompactedNullifierChangesResponse v0. + * @member {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.IGetRecentCompactedNullifierChangesResponseV0|null|undefined} v0 + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @instance + */ + GetRecentCompactedNullifierChangesResponse.prototype.v0 = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetRecentCompactedNullifierChangesResponse version. + * @member {"v0"|undefined} version + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @instance + */ + Object.defineProperty(GetRecentCompactedNullifierChangesResponse.prototype, "version", { + get: $util.oneOfGetter($oneOfFields = ["v0"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetRecentCompactedNullifierChangesResponse instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesResponse=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} GetRecentCompactedNullifierChangesResponse instance + */ + GetRecentCompactedNullifierChangesResponse.create = function create(properties) { + return new GetRecentCompactedNullifierChangesResponse(properties); + }; + + /** + * Encodes the specified GetRecentCompactedNullifierChangesResponse message. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesResponse} message GetRecentCompactedNullifierChangesResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentCompactedNullifierChangesResponse.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.v0 != null && Object.hasOwnProperty.call(message, "v0")) + $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.encode(message.v0, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetRecentCompactedNullifierChangesResponse message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @static + * @param {org.dash.platform.dapi.v0.IGetRecentCompactedNullifierChangesResponse} message GetRecentCompactedNullifierChangesResponse message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentCompactedNullifierChangesResponse.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetRecentCompactedNullifierChangesResponse message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} GetRecentCompactedNullifierChangesResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentCompactedNullifierChangesResponse.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.v0 = $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetRecentCompactedNullifierChangesResponse message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} GetRecentCompactedNullifierChangesResponse + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentCompactedNullifierChangesResponse.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetRecentCompactedNullifierChangesResponse message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetRecentCompactedNullifierChangesResponse.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + properties.version = 1; + { + var error = $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.verify(message.v0); + if (error) + return "v0." + error; + } + } + return null; + }; + + /** + * Creates a GetRecentCompactedNullifierChangesResponse message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} GetRecentCompactedNullifierChangesResponse + */ + GetRecentCompactedNullifierChangesResponse.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse(); + if (object.v0 != null) { + if (typeof object.v0 !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.v0: object expected"); + message.v0 = $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.fromObject(object.v0); + } + return message; + }; + + /** + * Creates a plain object from a GetRecentCompactedNullifierChangesResponse message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} message GetRecentCompactedNullifierChangesResponse + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetRecentCompactedNullifierChangesResponse.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (message.v0 != null && message.hasOwnProperty("v0")) { + object.v0 = $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.toObject(message.v0, options); + if (options.oneofs) + object.version = "v0"; + } + return object; + }; + + /** + * Converts this GetRecentCompactedNullifierChangesResponse to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @instance + * @returns {Object.} JSON object + */ + GetRecentCompactedNullifierChangesResponse.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 = (function() { + + /** + * Properties of a GetRecentCompactedNullifierChangesResponseV0. + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @interface IGetRecentCompactedNullifierChangesResponseV0 + * @property {org.dash.platform.dapi.v0.ICompactedNullifierUpdateEntries|null} [compactedNullifierUpdateEntries] GetRecentCompactedNullifierChangesResponseV0 compactedNullifierUpdateEntries + * @property {org.dash.platform.dapi.v0.IProof|null} [proof] GetRecentCompactedNullifierChangesResponseV0 proof + * @property {org.dash.platform.dapi.v0.IResponseMetadata|null} [metadata] GetRecentCompactedNullifierChangesResponseV0 metadata + */ + + /** + * Constructs a new GetRecentCompactedNullifierChangesResponseV0. + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse + * @classdesc Represents a GetRecentCompactedNullifierChangesResponseV0. + * @implements IGetRecentCompactedNullifierChangesResponseV0 + * @constructor + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.IGetRecentCompactedNullifierChangesResponseV0=} [properties] Properties to set + */ + function GetRecentCompactedNullifierChangesResponseV0(properties) { + if (properties) + for (var keys = Object.keys(properties), i = 0; i < keys.length; ++i) + if (properties[keys[i]] != null) + this[keys[i]] = properties[keys[i]]; + } + + /** + * GetRecentCompactedNullifierChangesResponseV0 compactedNullifierUpdateEntries. + * @member {org.dash.platform.dapi.v0.ICompactedNullifierUpdateEntries|null|undefined} compactedNullifierUpdateEntries + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @instance + */ + GetRecentCompactedNullifierChangesResponseV0.prototype.compactedNullifierUpdateEntries = null; + + /** + * GetRecentCompactedNullifierChangesResponseV0 proof. + * @member {org.dash.platform.dapi.v0.IProof|null|undefined} proof + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @instance + */ + GetRecentCompactedNullifierChangesResponseV0.prototype.proof = null; + + /** + * GetRecentCompactedNullifierChangesResponseV0 metadata. + * @member {org.dash.platform.dapi.v0.IResponseMetadata|null|undefined} metadata + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @instance + */ + GetRecentCompactedNullifierChangesResponseV0.prototype.metadata = null; + + // OneOf field names bound to virtual getters and setters + var $oneOfFields; + + /** + * GetRecentCompactedNullifierChangesResponseV0 result. + * @member {"compactedNullifierUpdateEntries"|"proof"|undefined} result + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @instance + */ + Object.defineProperty(GetRecentCompactedNullifierChangesResponseV0.prototype, "result", { + get: $util.oneOfGetter($oneOfFields = ["compactedNullifierUpdateEntries", "proof"]), + set: $util.oneOfSetter($oneOfFields) + }); + + /** + * Creates a new GetRecentCompactedNullifierChangesResponseV0 instance using the specified properties. + * @function create + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.IGetRecentCompactedNullifierChangesResponseV0=} [properties] Properties to set + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} GetRecentCompactedNullifierChangesResponseV0 instance + */ + GetRecentCompactedNullifierChangesResponseV0.create = function create(properties) { + return new GetRecentCompactedNullifierChangesResponseV0(properties); + }; + + /** + * Encodes the specified GetRecentCompactedNullifierChangesResponseV0 message. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.verify|verify} messages. + * @function encode + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.IGetRecentCompactedNullifierChangesResponseV0} message GetRecentCompactedNullifierChangesResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentCompactedNullifierChangesResponseV0.encode = function encode(message, writer) { + if (!writer) + writer = $Writer.create(); + if (message.compactedNullifierUpdateEntries != null && Object.hasOwnProperty.call(message, "compactedNullifierUpdateEntries")) + $root.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.encode(message.compactedNullifierUpdateEntries, writer.uint32(/* id 1, wireType 2 =*/10).fork()).ldelim(); + if (message.proof != null && Object.hasOwnProperty.call(message, "proof")) + $root.org.dash.platform.dapi.v0.Proof.encode(message.proof, writer.uint32(/* id 2, wireType 2 =*/18).fork()).ldelim(); + if (message.metadata != null && Object.hasOwnProperty.call(message, "metadata")) + $root.org.dash.platform.dapi.v0.ResponseMetadata.encode(message.metadata, writer.uint32(/* id 3, wireType 2 =*/26).fork()).ldelim(); + return writer; + }; + + /** + * Encodes the specified GetRecentCompactedNullifierChangesResponseV0 message, length delimited. Does not implicitly {@link org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.verify|verify} messages. + * @function encodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.IGetRecentCompactedNullifierChangesResponseV0} message GetRecentCompactedNullifierChangesResponseV0 message or plain object to encode + * @param {$protobuf.Writer} [writer] Writer to encode to + * @returns {$protobuf.Writer} Writer + */ + GetRecentCompactedNullifierChangesResponseV0.encodeDelimited = function encodeDelimited(message, writer) { + return this.encode(message, writer).ldelim(); + }; + + /** + * Decodes a GetRecentCompactedNullifierChangesResponseV0 message from the specified reader or buffer. + * @function decode + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @param {number} [length] Message length if known beforehand + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} GetRecentCompactedNullifierChangesResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentCompactedNullifierChangesResponseV0.decode = function decode(reader, length) { + if (!(reader instanceof $Reader)) + reader = $Reader.create(reader); + var end = length === undefined ? reader.len : reader.pos + length, message = new $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0(); + while (reader.pos < end) { + var tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.compactedNullifierUpdateEntries = $root.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.decode(reader, reader.uint32()); + break; + case 2: + message.proof = $root.org.dash.platform.dapi.v0.Proof.decode(reader, reader.uint32()); + break; + case 3: + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.decode(reader, reader.uint32()); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }; + + /** + * Decodes a GetRecentCompactedNullifierChangesResponseV0 message from the specified reader or buffer, length delimited. + * @function decodeDelimited + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @static + * @param {$protobuf.Reader|Uint8Array} reader Reader or buffer to decode from + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} GetRecentCompactedNullifierChangesResponseV0 + * @throws {Error} If the payload is not a reader or valid buffer + * @throws {$protobuf.util.ProtocolError} If required fields are missing + */ + GetRecentCompactedNullifierChangesResponseV0.decodeDelimited = function decodeDelimited(reader) { + if (!(reader instanceof $Reader)) + reader = new $Reader(reader); + return this.decode(reader, reader.uint32()); + }; + + /** + * Verifies a GetRecentCompactedNullifierChangesResponseV0 message. + * @function verify + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @static + * @param {Object.} message Plain object to verify + * @returns {string|null} `null` if valid, otherwise the reason why it is not + */ + GetRecentCompactedNullifierChangesResponseV0.verify = function verify(message) { + if (typeof message !== "object" || message === null) + return "object expected"; + var properties = {}; + if (message.compactedNullifierUpdateEntries != null && message.hasOwnProperty("compactedNullifierUpdateEntries")) { + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.verify(message.compactedNullifierUpdateEntries); + if (error) + return "compactedNullifierUpdateEntries." + error; + } + } + if (message.proof != null && message.hasOwnProperty("proof")) { + if (properties.result === 1) + return "result: multiple values"; + properties.result = 1; + { + var error = $root.org.dash.platform.dapi.v0.Proof.verify(message.proof); + if (error) + return "proof." + error; + } + } + if (message.metadata != null && message.hasOwnProperty("metadata")) { + var error = $root.org.dash.platform.dapi.v0.ResponseMetadata.verify(message.metadata); + if (error) + return "metadata." + error; + } + return null; + }; + + /** + * Creates a GetRecentCompactedNullifierChangesResponseV0 message from a plain object. Also converts values to their respective internal types. + * @function fromObject + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @static + * @param {Object.} object Plain object + * @returns {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} GetRecentCompactedNullifierChangesResponseV0 + */ + GetRecentCompactedNullifierChangesResponseV0.fromObject = function fromObject(object) { + if (object instanceof $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0) + return object; + var message = new $root.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0(); + if (object.compactedNullifierUpdateEntries != null) { + if (typeof object.compactedNullifierUpdateEntries !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.compactedNullifierUpdateEntries: object expected"); + message.compactedNullifierUpdateEntries = $root.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.fromObject(object.compactedNullifierUpdateEntries); + } + if (object.proof != null) { + if (typeof object.proof !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.proof: object expected"); + message.proof = $root.org.dash.platform.dapi.v0.Proof.fromObject(object.proof); + } + if (object.metadata != null) { + if (typeof object.metadata !== "object") + throw TypeError(".org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.metadata: object expected"); + message.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.fromObject(object.metadata); + } + return message; + }; + + /** + * Creates a plain object from a GetRecentCompactedNullifierChangesResponseV0 message. Also converts values to other types if specified. + * @function toObject + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @static + * @param {org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} message GetRecentCompactedNullifierChangesResponseV0 + * @param {$protobuf.IConversionOptions} [options] Conversion options + * @returns {Object.} Plain object + */ + GetRecentCompactedNullifierChangesResponseV0.toObject = function toObject(message, options) { + if (!options) + options = {}; + var object = {}; + if (options.defaults) + object.metadata = null; + if (message.compactedNullifierUpdateEntries != null && message.hasOwnProperty("compactedNullifierUpdateEntries")) { + object.compactedNullifierUpdateEntries = $root.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.toObject(message.compactedNullifierUpdateEntries, options); + if (options.oneofs) + object.result = "compactedNullifierUpdateEntries"; + } + if (message.proof != null && message.hasOwnProperty("proof")) { + object.proof = $root.org.dash.platform.dapi.v0.Proof.toObject(message.proof, options); + if (options.oneofs) + object.result = "proof"; + } + if (message.metadata != null && message.hasOwnProperty("metadata")) + object.metadata = $root.org.dash.platform.dapi.v0.ResponseMetadata.toObject(message.metadata, options); + return object; + }; + + /** + * Converts this GetRecentCompactedNullifierChangesResponseV0 to JSON. + * @function toJSON + * @memberof org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 + * @instance + * @returns {Object.} JSON object + */ + GetRecentCompactedNullifierChangesResponseV0.prototype.toJSON = function toJSON() { + return this.constructor.toObject(this, $protobuf.util.toJSONOptions); + }; + + return GetRecentCompactedNullifierChangesResponseV0; + })(); + + return GetRecentCompactedNullifierChangesResponse; + })(); + return v0; })(); diff --git a/packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js b/packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js index b3961b34a2e..edc3c51e800 100644 --- a/packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js +++ b/packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js @@ -31,12 +31,15 @@ goog.exportSymbol('proto.org.dash.platform.dapi.v0.AllKeys', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.BalanceAndNonce', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockAddressBalanceChanges', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeightCreditEntry', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockNullifierChanges', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastStateTransitionRequest', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastStateTransitionResponse', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.CompactedAddressBalanceChange', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.CompactedAddressBalanceChange.OperationCase', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.CompactedAddressBalanceUpdateEntries', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.CompactedBlockAddressBalanceChanges', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetAddressInfoRequest', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetAddressInfoRequest.GetAddressInfoRequestV0', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetAddressInfoRequest.VersionCase', null, { proto }); @@ -371,6 +374,18 @@ goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenInfoEntry', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenInfos', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.VersionCase', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetPathElementsRequest', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetPathElementsRequest.GetPathElementsRequestV0', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetPathElementsRequest.VersionCase', null, { proto }); @@ -418,6 +433,20 @@ goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBala goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0.ResultCase', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.ResultCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.ResultCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.VersionCase', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.VersionCase', null, { proto }); @@ -546,6 +575,7 @@ goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse goog.exportSymbol('proto.org.dash.platform.dapi.v0.KeyPurpose', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.KeyRequestType', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.KeyRequestType.RequestCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.NullifierUpdateEntries', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.Proof', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.ResponseMetadata', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.SearchKey', null, { proto }); @@ -8078,6 +8108,426 @@ if (goog.DEBUG && !COMPILED) { */ proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.displayName = 'proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.displayName = 'proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.displayName = 'proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.displayName = 'proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.displayName = 'proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.displayName = 'proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.displayName = 'proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.displayName = 'proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.org.dash.platform.dapi.v0.BlockNullifierChanges.repeatedFields_, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.BlockNullifierChanges, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.BlockNullifierChanges.displayName = 'proto.org.dash.platform.dapi.v0.BlockNullifierChanges'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.repeatedFields_, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.NullifierUpdateEntries, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.displayName = 'proto.org.dash.platform.dapi.v0.NullifierUpdateEntries'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.displayName = 'proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.displayName = 'proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.displayName = 'proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.displayName = 'proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.repeatedFields_, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.displayName = 'proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.repeatedFields_, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.displayName = 'proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.displayName = 'proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.displayName = 'proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.displayName = 'proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.displayName = 'proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0'; +} @@ -84274,6 +84724,3900 @@ proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.prototype.hasV0 = }; + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest; + return proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.toObject = function(includeInstance, msg) { + var f, obj = { + poolType: jspb.Message.getFieldWithDefault(msg, 1, 0), + poolIdentifier: msg.getPoolIdentifier_asB64() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0; + return proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readUint32()); + msg.setPoolType(value); + break; + case 2: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setPoolIdentifier(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getPoolType(); + if (f !== 0) { + writer.writeUint32( + 1, + f + ); + } + f = message.getPoolIdentifier_asU8(); + if (f.length > 0) { + writer.writeBytes( + 2, + f + ); + } +}; + + +/** + * optional uint32 pool_type = 1; + * @return {number} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.prototype.getPoolType = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.prototype.setPoolType = function(value) { + return jspb.Message.setProto3IntField(this, 1, value); +}; + + +/** + * optional bytes pool_identifier = 2; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.prototype.getPoolIdentifier = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * optional bytes pool_identifier = 2; + * This is a type-conversion wrapper around `getPoolIdentifier()` + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.prototype.getPoolIdentifier_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getPoolIdentifier())); +}; + + +/** + * optional bytes pool_identifier = 2; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getPoolIdentifier()` + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.prototype.getPoolIdentifier_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getPoolIdentifier())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.prototype.setPoolIdentifier = function(value) { + return jspb.Message.setProto3BytesField(this, 2, value); +}; + + +/** + * optional GetNullifiersTrunkStateRequestV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} returns this +*/ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse; + return proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.toObject = function(includeInstance, msg) { + var f, obj = { + proof: (f = msg.getProof()) && proto.org.dash.platform.dapi.v0.Proof.toObject(includeInstance, f), + metadata: (f = msg.getMetadata()) && proto.org.dash.platform.dapi.v0.ResponseMetadata.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0; + return proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 2: + var value = new proto.org.dash.platform.dapi.v0.Proof; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.Proof.deserializeBinaryFromReader); + msg.setProof(value); + break; + case 3: + var value = new proto.org.dash.platform.dapi.v0.ResponseMetadata; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.ResponseMetadata.deserializeBinaryFromReader); + msg.setMetadata(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getProof(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.org.dash.platform.dapi.v0.Proof.serializeBinaryToWriter + ); + } + f = message.getMetadata(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.org.dash.platform.dapi.v0.ResponseMetadata.serializeBinaryToWriter + ); + } +}; + + +/** + * optional Proof proof = 2; + * @return {?proto.org.dash.platform.dapi.v0.Proof} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.getProof = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.Proof} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.Proof, 2)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.Proof|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.setProof = function(value) { + return jspb.Message.setWrapperField(this, 2, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.clearProof = function() { + return this.setProof(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.hasProof = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional ResponseMetadata metadata = 3; + * @return {?proto.org.dash.platform.dapi.v0.ResponseMetadata} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.getMetadata = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.ResponseMetadata} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.ResponseMetadata, 3)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.ResponseMetadata|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.setMetadata = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.clearMetadata = function() { + return this.setMetadata(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.hasMetadata = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional GetNullifiersTrunkStateResponseV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} returns this +*/ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest; + return proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.toObject = function(includeInstance, msg) { + var f, obj = { + poolType: jspb.Message.getFieldWithDefault(msg, 1, 0), + poolIdentifier: msg.getPoolIdentifier_asB64(), + key: msg.getKey_asB64(), + depth: jspb.Message.getFieldWithDefault(msg, 4, 0), + checkpointHeight: jspb.Message.getFieldWithDefault(msg, 5, 0) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0; + return proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readUint32()); + msg.setPoolType(value); + break; + case 2: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setPoolIdentifier(value); + break; + case 3: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setKey(value); + break; + case 4: + var value = /** @type {number} */ (reader.readUint32()); + msg.setDepth(value); + break; + case 5: + var value = /** @type {number} */ (reader.readUint64()); + msg.setCheckpointHeight(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getPoolType(); + if (f !== 0) { + writer.writeUint32( + 1, + f + ); + } + f = message.getPoolIdentifier_asU8(); + if (f.length > 0) { + writer.writeBytes( + 2, + f + ); + } + f = message.getKey_asU8(); + if (f.length > 0) { + writer.writeBytes( + 3, + f + ); + } + f = message.getDepth(); + if (f !== 0) { + writer.writeUint32( + 4, + f + ); + } + f = message.getCheckpointHeight(); + if (f !== 0) { + writer.writeUint64( + 5, + f + ); + } +}; + + +/** + * optional uint32 pool_type = 1; + * @return {number} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.getPoolType = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.setPoolType = function(value) { + return jspb.Message.setProto3IntField(this, 1, value); +}; + + +/** + * optional bytes pool_identifier = 2; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.getPoolIdentifier = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * optional bytes pool_identifier = 2; + * This is a type-conversion wrapper around `getPoolIdentifier()` + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.getPoolIdentifier_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getPoolIdentifier())); +}; + + +/** + * optional bytes pool_identifier = 2; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getPoolIdentifier()` + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.getPoolIdentifier_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getPoolIdentifier())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.setPoolIdentifier = function(value) { + return jspb.Message.setProto3BytesField(this, 2, value); +}; + + +/** + * optional bytes key = 3; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.getKey = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); +}; + + +/** + * optional bytes key = 3; + * This is a type-conversion wrapper around `getKey()` + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.getKey_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getKey())); +}; + + +/** + * optional bytes key = 3; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getKey()` + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.getKey_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getKey())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.setKey = function(value) { + return jspb.Message.setProto3BytesField(this, 3, value); +}; + + +/** + * optional uint32 depth = 4; + * @return {number} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.getDepth = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 4, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.setDepth = function(value) { + return jspb.Message.setProto3IntField(this, 4, value); +}; + + +/** + * optional uint64 checkpoint_height = 5; + * @return {number} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.getCheckpointHeight = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 5, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.setCheckpointHeight = function(value) { + return jspb.Message.setProto3IntField(this, 5, value); +}; + + +/** + * optional GetNullifiersBranchStateRequestV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} returns this +*/ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse; + return proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.toObject = function(includeInstance, msg) { + var f, obj = { + merkProof: msg.getMerkProof_asB64() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0; + return proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 2: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setMerkProof(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getMerkProof_asU8(); + if (f.length > 0) { + writer.writeBytes( + 2, + f + ); + } +}; + + +/** + * optional bytes merk_proof = 2; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.prototype.getMerkProof = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * optional bytes merk_proof = 2; + * This is a type-conversion wrapper around `getMerkProof()` + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.prototype.getMerkProof_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getMerkProof())); +}; + + +/** + * optional bytes merk_proof = 2; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getMerkProof()` + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.prototype.getMerkProof_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getMerkProof())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.prototype.setMerkProof = function(value) { + return jspb.Message.setProto3BytesField(this, 2, value); +}; + + +/** + * optional GetNullifiersBranchStateResponseV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} returns this +*/ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.repeatedFields_ = [2]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.BlockNullifierChanges.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.toObject = function(includeInstance, msg) { + var f, obj = { + blockHeight: jspb.Message.getFieldWithDefault(msg, 1, "0"), + nullifiersList: msg.getNullifiersList_asB64() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.BlockNullifierChanges; + return proto.org.dash.platform.dapi.v0.BlockNullifierChanges.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setBlockHeight(value); + break; + case 2: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.addNullifiers(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.BlockNullifierChanges.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getBlockHeight(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( + 1, + f + ); + } + f = message.getNullifiersList_asU8(); + if (f.length > 0) { + writer.writeRepeatedBytes( + 2, + f + ); + } +}; + + +/** + * optional uint64 block_height = 1; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.getBlockHeight = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} returns this + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.setBlockHeight = function(value) { + return jspb.Message.setProto3StringIntField(this, 1, value); +}; + + +/** + * repeated bytes nullifiers = 2; + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.getNullifiersList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 2)); +}; + + +/** + * repeated bytes nullifiers = 2; + * This is a type-conversion wrapper around `getNullifiersList()` + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.getNullifiersList_asB64 = function() { + return /** @type {!Array} */ (jspb.Message.bytesListAsB64( + this.getNullifiersList())); +}; + + +/** + * repeated bytes nullifiers = 2; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getNullifiersList()` + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.getNullifiersList_asU8 = function() { + return /** @type {!Array} */ (jspb.Message.bytesListAsU8( + this.getNullifiersList())); +}; + + +/** + * @param {!(Array|Array)} value + * @return {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} returns this + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.setNullifiersList = function(value) { + return jspb.Message.setField(this, 2, value || []); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @param {number=} opt_index + * @return {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} returns this + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.addNullifiers = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 2, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} returns this + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.clearNullifiersList = function() { + return this.setNullifiersList([]); +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.NullifierUpdateEntries} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.toObject = function(includeInstance, msg) { + var f, obj = { + blockChangesList: jspb.Message.toObjectList(msg.getBlockChangesList(), + proto.org.dash.platform.dapi.v0.BlockNullifierChanges.toObject, includeInstance) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.NullifierUpdateEntries} + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.NullifierUpdateEntries; + return proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.NullifierUpdateEntries} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.NullifierUpdateEntries} + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.BlockNullifierChanges; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.BlockNullifierChanges.deserializeBinaryFromReader); + msg.addBlockChanges(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.NullifierUpdateEntries} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getBlockChangesList(); + if (f.length > 0) { + writer.writeRepeatedMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.BlockNullifierChanges.serializeBinaryToWriter + ); + } +}; + + +/** + * repeated BlockNullifierChanges block_changes = 1; + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.prototype.getBlockChangesList = function() { + return /** @type{!Array} */ ( + jspb.Message.getRepeatedWrapperField(this, proto.org.dash.platform.dapi.v0.BlockNullifierChanges, 1)); +}; + + +/** + * @param {!Array} value + * @return {!proto.org.dash.platform.dapi.v0.NullifierUpdateEntries} returns this +*/ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.prototype.setBlockChangesList = function(value) { + return jspb.Message.setRepeatedWrapperField(this, 1, value); +}; + + +/** + * @param {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges=} opt_value + * @param {number=} opt_index + * @return {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.prototype.addBlockChanges = function(opt_value, opt_index) { + return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.org.dash.platform.dapi.v0.BlockNullifierChanges, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.org.dash.platform.dapi.v0.NullifierUpdateEntries} returns this + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.prototype.clearBlockChangesList = function() { + return this.setBlockChangesList([]); +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest; + return proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.toObject = function(includeInstance, msg) { + var f, obj = { + startHeight: jspb.Message.getFieldWithDefault(msg, 1, "0"), + prove: jspb.Message.getBooleanFieldWithDefault(msg, 2, false) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0; + return proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setStartHeight(value); + break; + case 2: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setProve(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getStartHeight(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( + 1, + f + ); + } + f = message.getProve(); + if (f) { + writer.writeBool( + 2, + f + ); + } +}; + + +/** + * optional uint64 start_height = 1; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.prototype.getStartHeight = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.prototype.setStartHeight = function(value) { + return jspb.Message.setProto3StringIntField(this, 1, value); +}; + + +/** + * optional bool prove = 2; + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.prototype.getProve = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 2, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.prototype.setProve = function(value) { + return jspb.Message.setProto3BooleanField(this, 2, value); +}; + + +/** + * optional GetRecentNullifierChangesRequestV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse; + return proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.serializeBinaryToWriter + ); + } +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.oneofGroups_ = [[1,2]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.ResultCase = { + RESULT_NOT_SET: 0, + NULLIFIER_UPDATE_ENTRIES: 1, + PROOF: 2 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.ResultCase} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.getResultCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.ResultCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.toObject = function(includeInstance, msg) { + var f, obj = { + nullifierUpdateEntries: (f = msg.getNullifierUpdateEntries()) && proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.toObject(includeInstance, f), + proof: (f = msg.getProof()) && proto.org.dash.platform.dapi.v0.Proof.toObject(includeInstance, f), + metadata: (f = msg.getMetadata()) && proto.org.dash.platform.dapi.v0.ResponseMetadata.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0; + return proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.NullifierUpdateEntries; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.deserializeBinaryFromReader); + msg.setNullifierUpdateEntries(value); + break; + case 2: + var value = new proto.org.dash.platform.dapi.v0.Proof; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.Proof.deserializeBinaryFromReader); + msg.setProof(value); + break; + case 3: + var value = new proto.org.dash.platform.dapi.v0.ResponseMetadata; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.ResponseMetadata.deserializeBinaryFromReader); + msg.setMetadata(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getNullifierUpdateEntries(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.serializeBinaryToWriter + ); + } + f = message.getProof(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.org.dash.platform.dapi.v0.Proof.serializeBinaryToWriter + ); + } + f = message.getMetadata(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.org.dash.platform.dapi.v0.ResponseMetadata.serializeBinaryToWriter + ); + } +}; + + +/** + * optional NullifierUpdateEntries nullifier_update_entries = 1; + * @return {?proto.org.dash.platform.dapi.v0.NullifierUpdateEntries} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.getNullifierUpdateEntries = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.NullifierUpdateEntries} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.NullifierUpdateEntries, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.NullifierUpdateEntries|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.setNullifierUpdateEntries = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.clearNullifierUpdateEntries = function() { + return this.setNullifierUpdateEntries(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.hasNullifierUpdateEntries = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional Proof proof = 2; + * @return {?proto.org.dash.platform.dapi.v0.Proof} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.getProof = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.Proof} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.Proof, 2)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.Proof|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.setProof = function(value) { + return jspb.Message.setOneofWrapperField(this, 2, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.clearProof = function() { + return this.setProof(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.hasProof = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional ResponseMetadata metadata = 3; + * @return {?proto.org.dash.platform.dapi.v0.ResponseMetadata} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.getMetadata = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.ResponseMetadata} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.ResponseMetadata, 3)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.ResponseMetadata|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.setMetadata = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.clearMetadata = function() { + return this.setMetadata(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.hasMetadata = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional GetRecentNullifierChangesResponseV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.repeatedFields_ = [3]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.toObject = function(includeInstance, msg) { + var f, obj = { + startBlockHeight: jspb.Message.getFieldWithDefault(msg, 1, "0"), + endBlockHeight: jspb.Message.getFieldWithDefault(msg, 2, "0"), + nullifiersList: msg.getNullifiersList_asB64() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges; + return proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setStartBlockHeight(value); + break; + case 2: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setEndBlockHeight(value); + break; + case 3: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.addNullifiers(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getStartBlockHeight(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( + 1, + f + ); + } + f = message.getEndBlockHeight(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( + 2, + f + ); + } + f = message.getNullifiersList_asU8(); + if (f.length > 0) { + writer.writeRepeatedBytes( + 3, + f + ); + } +}; + + +/** + * optional uint64 start_block_height = 1; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.getStartBlockHeight = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} returns this + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.setStartBlockHeight = function(value) { + return jspb.Message.setProto3StringIntField(this, 1, value); +}; + + +/** + * optional uint64 end_block_height = 2; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.getEndBlockHeight = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} returns this + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.setEndBlockHeight = function(value) { + return jspb.Message.setProto3StringIntField(this, 2, value); +}; + + +/** + * repeated bytes nullifiers = 3; + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.getNullifiersList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 3)); +}; + + +/** + * repeated bytes nullifiers = 3; + * This is a type-conversion wrapper around `getNullifiersList()` + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.getNullifiersList_asB64 = function() { + return /** @type {!Array} */ (jspb.Message.bytesListAsB64( + this.getNullifiersList())); +}; + + +/** + * repeated bytes nullifiers = 3; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getNullifiersList()` + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.getNullifiersList_asU8 = function() { + return /** @type {!Array} */ (jspb.Message.bytesListAsU8( + this.getNullifiersList())); +}; + + +/** + * @param {!(Array|Array)} value + * @return {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} returns this + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.setNullifiersList = function(value) { + return jspb.Message.setField(this, 3, value || []); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @param {number=} opt_index + * @return {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} returns this + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.addNullifiers = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 3, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} returns this + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.clearNullifiersList = function() { + return this.setNullifiersList([]); +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.toObject = function(includeInstance, msg) { + var f, obj = { + compactedBlockChangesList: jspb.Message.toObjectList(msg.getCompactedBlockChangesList(), + proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.toObject, includeInstance) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries; + return proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.deserializeBinaryFromReader); + msg.addCompactedBlockChanges(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getCompactedBlockChangesList(); + if (f.length > 0) { + writer.writeRepeatedMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.serializeBinaryToWriter + ); + } +}; + + +/** + * repeated CompactedBlockNullifierChanges compacted_block_changes = 1; + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.prototype.getCompactedBlockChangesList = function() { + return /** @type{!Array} */ ( + jspb.Message.getRepeatedWrapperField(this, proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges, 1)); +}; + + +/** + * @param {!Array} value + * @return {!proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} returns this +*/ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.prototype.setCompactedBlockChangesList = function(value) { + return jspb.Message.setRepeatedWrapperField(this, 1, value); +}; + + +/** + * @param {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges=} opt_value + * @param {number=} opt_index + * @return {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.prototype.addCompactedBlockChanges = function(opt_value, opt_index) { + return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} returns this + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.prototype.clearCompactedBlockChangesList = function() { + return this.setCompactedBlockChangesList([]); +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest; + return proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.toObject = function(includeInstance, msg) { + var f, obj = { + startBlockHeight: jspb.Message.getFieldWithDefault(msg, 1, "0"), + prove: jspb.Message.getBooleanFieldWithDefault(msg, 2, false) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0; + return proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setStartBlockHeight(value); + break; + case 2: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setProve(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getStartBlockHeight(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( + 1, + f + ); + } + f = message.getProve(); + if (f) { + writer.writeBool( + 2, + f + ); + } +}; + + +/** + * optional uint64 start_block_height = 1; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.prototype.getStartBlockHeight = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.prototype.setStartBlockHeight = function(value) { + return jspb.Message.setProto3StringIntField(this, 1, value); +}; + + +/** + * optional bool prove = 2; + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.prototype.getProve = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 2, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.prototype.setProve = function(value) { + return jspb.Message.setProto3BooleanField(this, 2, value); +}; + + +/** + * optional GetRecentCompactedNullifierChangesRequestV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse; + return proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.serializeBinaryToWriter + ); + } +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.oneofGroups_ = [[1,2]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.ResultCase = { + RESULT_NOT_SET: 0, + COMPACTED_NULLIFIER_UPDATE_ENTRIES: 1, + PROOF: 2 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.ResultCase} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.getResultCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.ResultCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.toObject = function(includeInstance, msg) { + var f, obj = { + compactedNullifierUpdateEntries: (f = msg.getCompactedNullifierUpdateEntries()) && proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.toObject(includeInstance, f), + proof: (f = msg.getProof()) && proto.org.dash.platform.dapi.v0.Proof.toObject(includeInstance, f), + metadata: (f = msg.getMetadata()) && proto.org.dash.platform.dapi.v0.ResponseMetadata.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0; + return proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.deserializeBinaryFromReader); + msg.setCompactedNullifierUpdateEntries(value); + break; + case 2: + var value = new proto.org.dash.platform.dapi.v0.Proof; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.Proof.deserializeBinaryFromReader); + msg.setProof(value); + break; + case 3: + var value = new proto.org.dash.platform.dapi.v0.ResponseMetadata; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.ResponseMetadata.deserializeBinaryFromReader); + msg.setMetadata(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getCompactedNullifierUpdateEntries(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.serializeBinaryToWriter + ); + } + f = message.getProof(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.org.dash.platform.dapi.v0.Proof.serializeBinaryToWriter + ); + } + f = message.getMetadata(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.org.dash.platform.dapi.v0.ResponseMetadata.serializeBinaryToWriter + ); + } +}; + + +/** + * optional CompactedNullifierUpdateEntries compacted_nullifier_update_entries = 1; + * @return {?proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.getCompactedNullifierUpdateEntries = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.setCompactedNullifierUpdateEntries = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.clearCompactedNullifierUpdateEntries = function() { + return this.setCompactedNullifierUpdateEntries(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.hasCompactedNullifierUpdateEntries = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional Proof proof = 2; + * @return {?proto.org.dash.platform.dapi.v0.Proof} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.getProof = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.Proof} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.Proof, 2)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.Proof|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.setProof = function(value) { + return jspb.Message.setOneofWrapperField(this, 2, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.clearProof = function() { + return this.setProof(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.hasProof = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional ResponseMetadata metadata = 3; + * @return {?proto.org.dash.platform.dapi.v0.ResponseMetadata} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.getMetadata = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.ResponseMetadata} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.ResponseMetadata, 3)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.ResponseMetadata|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.setMetadata = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.clearMetadata = function() { + return this.setMetadata(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.hasMetadata = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional GetRecentCompactedNullifierChangesResponseV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + /** * @enum {number} */ diff --git a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h index e24b1dbd7cf..ba8b705a009 100644 --- a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h +++ b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h @@ -36,9 +36,12 @@ CF_EXTERN_C_BEGIN @class BalanceAndNonce; @class BlockAddressBalanceChanges; @class BlockHeightCreditEntry; +@class BlockNullifierChanges; @class CompactedAddressBalanceChange; @class CompactedAddressBalanceUpdateEntries; @class CompactedBlockAddressBalanceChanges; +@class CompactedBlockNullifierChanges; +@class CompactedNullifierUpdateEntries; @class GPBBytesValue; @class GPBUInt32Value; @class GetAddressInfoRequest_GetAddressInfoRequestV0; @@ -187,6 +190,10 @@ CF_EXTERN_C_BEGIN @class GetIdentityTokenInfosResponse_GetIdentityTokenInfosResponseV0_TokenIdentityInfoEntry; @class GetIdentityTokenInfosResponse_GetIdentityTokenInfosResponseV0_TokenInfoEntry; @class GetIdentityTokenInfosResponse_GetIdentityTokenInfosResponseV0_TokenInfos; +@class GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0; +@class GetNullifiersBranchStateResponse_GetNullifiersBranchStateResponseV0; +@class GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0; +@class GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0; @class GetPathElementsRequest_GetPathElementsRequestV0; @class GetPathElementsResponse_GetPathElementsResponseV0; @class GetPathElementsResponse_GetPathElementsResponseV0_Elements; @@ -204,6 +211,10 @@ CF_EXTERN_C_BEGIN @class GetRecentAddressBalanceChangesResponse_GetRecentAddressBalanceChangesResponseV0; @class GetRecentCompactedAddressBalanceChangesRequest_GetRecentCompactedAddressBalanceChangesRequestV0; @class GetRecentCompactedAddressBalanceChangesResponse_GetRecentCompactedAddressBalanceChangesResponseV0; +@class GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0; +@class GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0; +@class GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0; +@class GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0; @class GetShieldedAnchorsRequest_GetShieldedAnchorsRequestV0; @class GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0; @class GetShieldedAnchorsResponse_GetShieldedAnchorsResponseV0_Anchors; @@ -264,6 +275,7 @@ CF_EXTERN_C_BEGIN @class GetVotePollsByEndDateResponse_GetVotePollsByEndDateResponseV0_SerializedVotePollsByTimestamp; @class GetVotePollsByEndDateResponse_GetVotePollsByEndDateResponseV0_SerializedVotePollsByTimestamps; @class KeyRequestType; +@class NullifierUpdateEntries; @class Proof; @class ResponseMetadata; @class SearchKey; @@ -9022,6 +9034,433 @@ GPB_FINAL @interface GetShieldedNullifiersResponse_GetShieldedNullifiersResponse @end +#pragma mark - GetNullifiersTrunkStateRequest + +typedef GPB_ENUM(GetNullifiersTrunkStateRequest_FieldNumber) { + GetNullifiersTrunkStateRequest_FieldNumber_V0 = 1, +}; + +typedef GPB_ENUM(GetNullifiersTrunkStateRequest_Version_OneOfCase) { + GetNullifiersTrunkStateRequest_Version_OneOfCase_GPBUnsetOneOfCase = 0, + GetNullifiersTrunkStateRequest_Version_OneOfCase_V0 = 1, +}; + +GPB_FINAL @interface GetNullifiersTrunkStateRequest : GPBMessage + +@property(nonatomic, readonly) GetNullifiersTrunkStateRequest_Version_OneOfCase versionOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0 *v0; + +@end + +/** + * Clears whatever value was set for the oneof 'version'. + **/ +void GetNullifiersTrunkStateRequest_ClearVersionOneOfCase(GetNullifiersTrunkStateRequest *message); + +#pragma mark - GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0 + +typedef GPB_ENUM(GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0_FieldNumber) { + GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0_FieldNumber_PoolType = 1, + GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0_FieldNumber_PoolIdentifier = 2, +}; + +GPB_FINAL @interface GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0 : GPBMessage + +/** ShieldedPoolType enum value (0=credit, 1=main token, 2=individual token) */ +@property(nonatomic, readwrite) uint32_t poolType; + +/** 32-byte Identifier, required for pool_type=2 */ +@property(nonatomic, readwrite, copy, null_resettable) NSData *poolIdentifier; + +@end + +#pragma mark - GetNullifiersTrunkStateResponse + +typedef GPB_ENUM(GetNullifiersTrunkStateResponse_FieldNumber) { + GetNullifiersTrunkStateResponse_FieldNumber_V0 = 1, +}; + +typedef GPB_ENUM(GetNullifiersTrunkStateResponse_Version_OneOfCase) { + GetNullifiersTrunkStateResponse_Version_OneOfCase_GPBUnsetOneOfCase = 0, + GetNullifiersTrunkStateResponse_Version_OneOfCase_V0 = 1, +}; + +GPB_FINAL @interface GetNullifiersTrunkStateResponse : GPBMessage + +@property(nonatomic, readonly) GetNullifiersTrunkStateResponse_Version_OneOfCase versionOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0 *v0; + +@end + +/** + * Clears whatever value was set for the oneof 'version'. + **/ +void GetNullifiersTrunkStateResponse_ClearVersionOneOfCase(GetNullifiersTrunkStateResponse *message); + +#pragma mark - GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0 + +typedef GPB_ENUM(GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0_FieldNumber) { + GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0_FieldNumber_Proof = 2, + GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0_FieldNumber_Metadata = 3, +}; + +GPB_FINAL @interface GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0 : GPBMessage + +@property(nonatomic, readwrite, strong, null_resettable) Proof *proof; +/** Test to see if @c proof has been set. */ +@property(nonatomic, readwrite) BOOL hasProof; + +@property(nonatomic, readwrite, strong, null_resettable) ResponseMetadata *metadata; +/** Test to see if @c metadata has been set. */ +@property(nonatomic, readwrite) BOOL hasMetadata; + +@end + +#pragma mark - GetNullifiersBranchStateRequest + +typedef GPB_ENUM(GetNullifiersBranchStateRequest_FieldNumber) { + GetNullifiersBranchStateRequest_FieldNumber_V0 = 1, +}; + +typedef GPB_ENUM(GetNullifiersBranchStateRequest_Version_OneOfCase) { + GetNullifiersBranchStateRequest_Version_OneOfCase_GPBUnsetOneOfCase = 0, + GetNullifiersBranchStateRequest_Version_OneOfCase_V0 = 1, +}; + +GPB_FINAL @interface GetNullifiersBranchStateRequest : GPBMessage + +@property(nonatomic, readonly) GetNullifiersBranchStateRequest_Version_OneOfCase versionOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0 *v0; + +@end + +/** + * Clears whatever value was set for the oneof 'version'. + **/ +void GetNullifiersBranchStateRequest_ClearVersionOneOfCase(GetNullifiersBranchStateRequest *message); + +#pragma mark - GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0 + +typedef GPB_ENUM(GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0_FieldNumber) { + GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0_FieldNumber_PoolType = 1, + GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0_FieldNumber_PoolIdentifier = 2, + GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0_FieldNumber_Key = 3, + GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0_FieldNumber_Depth = 4, + GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0_FieldNumber_CheckpointHeight = 5, +}; + +GPB_FINAL @interface GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0 : GPBMessage + +@property(nonatomic, readwrite) uint32_t poolType; + +@property(nonatomic, readwrite, copy, null_resettable) NSData *poolIdentifier; + +@property(nonatomic, readwrite, copy, null_resettable) NSData *key; + +@property(nonatomic, readwrite) uint32_t depth; + +@property(nonatomic, readwrite) uint64_t checkpointHeight; + +@end + +#pragma mark - GetNullifiersBranchStateResponse + +typedef GPB_ENUM(GetNullifiersBranchStateResponse_FieldNumber) { + GetNullifiersBranchStateResponse_FieldNumber_V0 = 1, +}; + +typedef GPB_ENUM(GetNullifiersBranchStateResponse_Version_OneOfCase) { + GetNullifiersBranchStateResponse_Version_OneOfCase_GPBUnsetOneOfCase = 0, + GetNullifiersBranchStateResponse_Version_OneOfCase_V0 = 1, +}; + +GPB_FINAL @interface GetNullifiersBranchStateResponse : GPBMessage + +@property(nonatomic, readonly) GetNullifiersBranchStateResponse_Version_OneOfCase versionOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetNullifiersBranchStateResponse_GetNullifiersBranchStateResponseV0 *v0; + +@end + +/** + * Clears whatever value was set for the oneof 'version'. + **/ +void GetNullifiersBranchStateResponse_ClearVersionOneOfCase(GetNullifiersBranchStateResponse *message); + +#pragma mark - GetNullifiersBranchStateResponse_GetNullifiersBranchStateResponseV0 + +typedef GPB_ENUM(GetNullifiersBranchStateResponse_GetNullifiersBranchStateResponseV0_FieldNumber) { + GetNullifiersBranchStateResponse_GetNullifiersBranchStateResponseV0_FieldNumber_MerkProof = 2, +}; + +GPB_FINAL @interface GetNullifiersBranchStateResponse_GetNullifiersBranchStateResponseV0 : GPBMessage + +@property(nonatomic, readwrite, copy, null_resettable) NSData *merkProof; + +@end + +#pragma mark - BlockNullifierChanges + +typedef GPB_ENUM(BlockNullifierChanges_FieldNumber) { + BlockNullifierChanges_FieldNumber_BlockHeight = 1, + BlockNullifierChanges_FieldNumber_NullifiersArray = 2, +}; + +GPB_FINAL @interface BlockNullifierChanges : GPBMessage + +@property(nonatomic, readwrite) uint64_t blockHeight; + +/** Each is 32 bytes */ +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *nullifiersArray; +/** The number of items in @c nullifiersArray without causing the array to be created. */ +@property(nonatomic, readonly) NSUInteger nullifiersArray_Count; + +@end + +#pragma mark - NullifierUpdateEntries + +typedef GPB_ENUM(NullifierUpdateEntries_FieldNumber) { + NullifierUpdateEntries_FieldNumber_BlockChangesArray = 1, +}; + +GPB_FINAL @interface NullifierUpdateEntries : GPBMessage + +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *blockChangesArray; +/** The number of items in @c blockChangesArray without causing the array to be created. */ +@property(nonatomic, readonly) NSUInteger blockChangesArray_Count; + +@end + +#pragma mark - GetRecentNullifierChangesRequest + +typedef GPB_ENUM(GetRecentNullifierChangesRequest_FieldNumber) { + GetRecentNullifierChangesRequest_FieldNumber_V0 = 1, +}; + +typedef GPB_ENUM(GetRecentNullifierChangesRequest_Version_OneOfCase) { + GetRecentNullifierChangesRequest_Version_OneOfCase_GPBUnsetOneOfCase = 0, + GetRecentNullifierChangesRequest_Version_OneOfCase_V0 = 1, +}; + +GPB_FINAL @interface GetRecentNullifierChangesRequest : GPBMessage + +@property(nonatomic, readonly) GetRecentNullifierChangesRequest_Version_OneOfCase versionOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0 *v0; + +@end + +/** + * Clears whatever value was set for the oneof 'version'. + **/ +void GetRecentNullifierChangesRequest_ClearVersionOneOfCase(GetRecentNullifierChangesRequest *message); + +#pragma mark - GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0 + +typedef GPB_ENUM(GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0_FieldNumber) { + GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0_FieldNumber_StartHeight = 1, + GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0_FieldNumber_Prove = 2, +}; + +GPB_FINAL @interface GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0 : GPBMessage + +@property(nonatomic, readwrite) uint64_t startHeight; + +@property(nonatomic, readwrite) BOOL prove; + +@end + +#pragma mark - GetRecentNullifierChangesResponse + +typedef GPB_ENUM(GetRecentNullifierChangesResponse_FieldNumber) { + GetRecentNullifierChangesResponse_FieldNumber_V0 = 1, +}; + +typedef GPB_ENUM(GetRecentNullifierChangesResponse_Version_OneOfCase) { + GetRecentNullifierChangesResponse_Version_OneOfCase_GPBUnsetOneOfCase = 0, + GetRecentNullifierChangesResponse_Version_OneOfCase_V0 = 1, +}; + +GPB_FINAL @interface GetRecentNullifierChangesResponse : GPBMessage + +@property(nonatomic, readonly) GetRecentNullifierChangesResponse_Version_OneOfCase versionOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0 *v0; + +@end + +/** + * Clears whatever value was set for the oneof 'version'. + **/ +void GetRecentNullifierChangesResponse_ClearVersionOneOfCase(GetRecentNullifierChangesResponse *message); + +#pragma mark - GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0 + +typedef GPB_ENUM(GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0_FieldNumber) { + GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0_FieldNumber_NullifierUpdateEntries = 1, + GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0_FieldNumber_Proof = 2, + GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0_FieldNumber_Metadata = 3, +}; + +typedef GPB_ENUM(GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0_Result_OneOfCase) { + GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0_Result_OneOfCase_GPBUnsetOneOfCase = 0, + GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0_Result_OneOfCase_NullifierUpdateEntries = 1, + GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0_Result_OneOfCase_Proof = 2, +}; + +GPB_FINAL @interface GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0 : GPBMessage + +@property(nonatomic, readonly) GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0_Result_OneOfCase resultOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) NullifierUpdateEntries *nullifierUpdateEntries; + +@property(nonatomic, readwrite, strong, null_resettable) Proof *proof; + +@property(nonatomic, readwrite, strong, null_resettable) ResponseMetadata *metadata; +/** Test to see if @c metadata has been set. */ +@property(nonatomic, readwrite) BOOL hasMetadata; + +@end + +/** + * Clears whatever value was set for the oneof 'result'. + **/ +void GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0_ClearResultOneOfCase(GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0 *message); + +#pragma mark - CompactedBlockNullifierChanges + +typedef GPB_ENUM(CompactedBlockNullifierChanges_FieldNumber) { + CompactedBlockNullifierChanges_FieldNumber_StartBlockHeight = 1, + CompactedBlockNullifierChanges_FieldNumber_EndBlockHeight = 2, + CompactedBlockNullifierChanges_FieldNumber_NullifiersArray = 3, +}; + +GPB_FINAL @interface CompactedBlockNullifierChanges : GPBMessage + +@property(nonatomic, readwrite) uint64_t startBlockHeight; + +@property(nonatomic, readwrite) uint64_t endBlockHeight; + +/** Each is 32 bytes */ +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *nullifiersArray; +/** The number of items in @c nullifiersArray without causing the array to be created. */ +@property(nonatomic, readonly) NSUInteger nullifiersArray_Count; + +@end + +#pragma mark - CompactedNullifierUpdateEntries + +typedef GPB_ENUM(CompactedNullifierUpdateEntries_FieldNumber) { + CompactedNullifierUpdateEntries_FieldNumber_CompactedBlockChangesArray = 1, +}; + +GPB_FINAL @interface CompactedNullifierUpdateEntries : GPBMessage + +@property(nonatomic, readwrite, strong, null_resettable) NSMutableArray *compactedBlockChangesArray; +/** The number of items in @c compactedBlockChangesArray without causing the array to be created. */ +@property(nonatomic, readonly) NSUInteger compactedBlockChangesArray_Count; + +@end + +#pragma mark - GetRecentCompactedNullifierChangesRequest + +typedef GPB_ENUM(GetRecentCompactedNullifierChangesRequest_FieldNumber) { + GetRecentCompactedNullifierChangesRequest_FieldNumber_V0 = 1, +}; + +typedef GPB_ENUM(GetRecentCompactedNullifierChangesRequest_Version_OneOfCase) { + GetRecentCompactedNullifierChangesRequest_Version_OneOfCase_GPBUnsetOneOfCase = 0, + GetRecentCompactedNullifierChangesRequest_Version_OneOfCase_V0 = 1, +}; + +GPB_FINAL @interface GetRecentCompactedNullifierChangesRequest : GPBMessage + +@property(nonatomic, readonly) GetRecentCompactedNullifierChangesRequest_Version_OneOfCase versionOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0 *v0; + +@end + +/** + * Clears whatever value was set for the oneof 'version'. + **/ +void GetRecentCompactedNullifierChangesRequest_ClearVersionOneOfCase(GetRecentCompactedNullifierChangesRequest *message); + +#pragma mark - GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0 + +typedef GPB_ENUM(GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0_FieldNumber) { + GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0_FieldNumber_StartBlockHeight = 1, + GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0_FieldNumber_Prove = 2, +}; + +GPB_FINAL @interface GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0 : GPBMessage + +@property(nonatomic, readwrite) uint64_t startBlockHeight; + +@property(nonatomic, readwrite) BOOL prove; + +@end + +#pragma mark - GetRecentCompactedNullifierChangesResponse + +typedef GPB_ENUM(GetRecentCompactedNullifierChangesResponse_FieldNumber) { + GetRecentCompactedNullifierChangesResponse_FieldNumber_V0 = 1, +}; + +typedef GPB_ENUM(GetRecentCompactedNullifierChangesResponse_Version_OneOfCase) { + GetRecentCompactedNullifierChangesResponse_Version_OneOfCase_GPBUnsetOneOfCase = 0, + GetRecentCompactedNullifierChangesResponse_Version_OneOfCase_V0 = 1, +}; + +GPB_FINAL @interface GetRecentCompactedNullifierChangesResponse : GPBMessage + +@property(nonatomic, readonly) GetRecentCompactedNullifierChangesResponse_Version_OneOfCase versionOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0 *v0; + +@end + +/** + * Clears whatever value was set for the oneof 'version'. + **/ +void GetRecentCompactedNullifierChangesResponse_ClearVersionOneOfCase(GetRecentCompactedNullifierChangesResponse *message); + +#pragma mark - GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0 + +typedef GPB_ENUM(GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0_FieldNumber) { + GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0_FieldNumber_CompactedNullifierUpdateEntries = 1, + GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0_FieldNumber_Proof = 2, + GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0_FieldNumber_Metadata = 3, +}; + +typedef GPB_ENUM(GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0_Result_OneOfCase) { + GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0_Result_OneOfCase_GPBUnsetOneOfCase = 0, + GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0_Result_OneOfCase_CompactedNullifierUpdateEntries = 1, + GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0_Result_OneOfCase_Proof = 2, +}; + +GPB_FINAL @interface GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0 : GPBMessage + +@property(nonatomic, readonly) GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0_Result_OneOfCase resultOneOfCase; + +@property(nonatomic, readwrite, strong, null_resettable) CompactedNullifierUpdateEntries *compactedNullifierUpdateEntries; + +@property(nonatomic, readwrite, strong, null_resettable) Proof *proof; + +@property(nonatomic, readwrite, strong, null_resettable) ResponseMetadata *metadata; +/** Test to see if @c metadata has been set. */ +@property(nonatomic, readwrite) BOOL hasMetadata; + +@end + +/** + * Clears whatever value was set for the oneof 'result'. + **/ +void GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0_ClearResultOneOfCase(GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0 *message); + NS_ASSUME_NONNULL_END CF_EXTERN_C_END diff --git a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m index 8fa10b4b980..e9c550c8bd0 100644 --- a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m +++ b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m @@ -36,9 +36,12 @@ GPBObjCClassDeclaration(BalanceAndNonce); GPBObjCClassDeclaration(BlockAddressBalanceChanges); GPBObjCClassDeclaration(BlockHeightCreditEntry); +GPBObjCClassDeclaration(BlockNullifierChanges); GPBObjCClassDeclaration(CompactedAddressBalanceChange); GPBObjCClassDeclaration(CompactedAddressBalanceUpdateEntries); GPBObjCClassDeclaration(CompactedBlockAddressBalanceChanges); +GPBObjCClassDeclaration(CompactedBlockNullifierChanges); +GPBObjCClassDeclaration(CompactedNullifierUpdateEntries); GPBObjCClassDeclaration(GPBBytesValue); GPBObjCClassDeclaration(GPBUInt32Value); GPBObjCClassDeclaration(GetAddressInfoRequest); @@ -258,6 +261,14 @@ GPBObjCClassDeclaration(GetIdentityTokenInfosResponse_GetIdentityTokenInfosResponseV0_TokenIdentityInfoEntry); GPBObjCClassDeclaration(GetIdentityTokenInfosResponse_GetIdentityTokenInfosResponseV0_TokenInfoEntry); GPBObjCClassDeclaration(GetIdentityTokenInfosResponse_GetIdentityTokenInfosResponseV0_TokenInfos); +GPBObjCClassDeclaration(GetNullifiersBranchStateRequest); +GPBObjCClassDeclaration(GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0); +GPBObjCClassDeclaration(GetNullifiersBranchStateResponse); +GPBObjCClassDeclaration(GetNullifiersBranchStateResponse_GetNullifiersBranchStateResponseV0); +GPBObjCClassDeclaration(GetNullifiersTrunkStateRequest); +GPBObjCClassDeclaration(GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0); +GPBObjCClassDeclaration(GetNullifiersTrunkStateResponse); +GPBObjCClassDeclaration(GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0); GPBObjCClassDeclaration(GetPathElementsRequest); GPBObjCClassDeclaration(GetPathElementsRequest_GetPathElementsRequestV0); GPBObjCClassDeclaration(GetPathElementsResponse); @@ -287,6 +298,14 @@ GPBObjCClassDeclaration(GetRecentCompactedAddressBalanceChangesRequest_GetRecentCompactedAddressBalanceChangesRequestV0); GPBObjCClassDeclaration(GetRecentCompactedAddressBalanceChangesResponse); GPBObjCClassDeclaration(GetRecentCompactedAddressBalanceChangesResponse_GetRecentCompactedAddressBalanceChangesResponseV0); +GPBObjCClassDeclaration(GetRecentCompactedNullifierChangesRequest); +GPBObjCClassDeclaration(GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0); +GPBObjCClassDeclaration(GetRecentCompactedNullifierChangesResponse); +GPBObjCClassDeclaration(GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0); +GPBObjCClassDeclaration(GetRecentNullifierChangesRequest); +GPBObjCClassDeclaration(GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0); +GPBObjCClassDeclaration(GetRecentNullifierChangesResponse); +GPBObjCClassDeclaration(GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0); GPBObjCClassDeclaration(GetShieldedAnchorsRequest); GPBObjCClassDeclaration(GetShieldedAnchorsRequest_GetShieldedAnchorsRequestV0); GPBObjCClassDeclaration(GetShieldedAnchorsResponse); @@ -373,6 +392,7 @@ GPBObjCClassDeclaration(GetVotePollsByEndDateResponse_GetVotePollsByEndDateResponseV0_SerializedVotePollsByTimestamp); GPBObjCClassDeclaration(GetVotePollsByEndDateResponse_GetVotePollsByEndDateResponseV0_SerializedVotePollsByTimestamps); GPBObjCClassDeclaration(KeyRequestType); +GPBObjCClassDeclaration(NullifierUpdateEntries); GPBObjCClassDeclaration(Proof); GPBObjCClassDeclaration(ResponseMetadata); GPBObjCClassDeclaration(SearchKey); @@ -23536,6 +23556,1197 @@ + (GPBDescriptor *)descriptor { @end +#pragma mark - GetNullifiersTrunkStateRequest + +@implementation GetNullifiersTrunkStateRequest + +@dynamic versionOneOfCase; +@dynamic v0; + +typedef struct GetNullifiersTrunkStateRequest__storage_ { + uint32_t _has_storage_[2]; + GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0 *v0; +} GetNullifiersTrunkStateRequest__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "v0", + .dataTypeSpecific.clazz = GPBObjCClass(GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0), + .number = GetNullifiersTrunkStateRequest_FieldNumber_V0, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetNullifiersTrunkStateRequest__storage_, v0), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetNullifiersTrunkStateRequest class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetNullifiersTrunkStateRequest__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "version", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetNullifiersTrunkStateRequest_ClearVersionOneOfCase(GetNullifiersTrunkStateRequest *message) { + GPBDescriptor *descriptor = [GetNullifiersTrunkStateRequest descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0 + +@implementation GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0 + +@dynamic poolType; +@dynamic poolIdentifier; + +typedef struct GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0__storage_ { + uint32_t _has_storage_[1]; + uint32_t poolType; + NSData *poolIdentifier; +} GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "poolType", + .dataTypeSpecific.clazz = Nil, + .number = GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0_FieldNumber_PoolType, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0__storage_, poolType), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeUInt32, + }, + { + .name = "poolIdentifier", + .dataTypeSpecific.clazz = Nil, + .number = GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0_FieldNumber_PoolIdentifier, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0__storage_, poolIdentifier), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeBytes, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0 class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetNullifiersTrunkStateRequest_GetNullifiersTrunkStateRequestV0__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetNullifiersTrunkStateRequest)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GetNullifiersTrunkStateResponse + +@implementation GetNullifiersTrunkStateResponse + +@dynamic versionOneOfCase; +@dynamic v0; + +typedef struct GetNullifiersTrunkStateResponse__storage_ { + uint32_t _has_storage_[2]; + GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0 *v0; +} GetNullifiersTrunkStateResponse__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "v0", + .dataTypeSpecific.clazz = GPBObjCClass(GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0), + .number = GetNullifiersTrunkStateResponse_FieldNumber_V0, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetNullifiersTrunkStateResponse__storage_, v0), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetNullifiersTrunkStateResponse class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetNullifiersTrunkStateResponse__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "version", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetNullifiersTrunkStateResponse_ClearVersionOneOfCase(GetNullifiersTrunkStateResponse *message) { + GPBDescriptor *descriptor = [GetNullifiersTrunkStateResponse descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0 + +@implementation GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0 + +@dynamic hasProof, proof; +@dynamic hasMetadata, metadata; + +typedef struct GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0__storage_ { + uint32_t _has_storage_[1]; + Proof *proof; + ResponseMetadata *metadata; +} GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "proof", + .dataTypeSpecific.clazz = GPBObjCClass(Proof), + .number = GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0_FieldNumber_Proof, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0__storage_, proof), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + { + .name = "metadata", + .dataTypeSpecific.clazz = GPBObjCClass(ResponseMetadata), + .number = GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0_FieldNumber_Metadata, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0__storage_, metadata), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0 class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetNullifiersTrunkStateResponse_GetNullifiersTrunkStateResponseV0__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetNullifiersTrunkStateResponse)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GetNullifiersBranchStateRequest + +@implementation GetNullifiersBranchStateRequest + +@dynamic versionOneOfCase; +@dynamic v0; + +typedef struct GetNullifiersBranchStateRequest__storage_ { + uint32_t _has_storage_[2]; + GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0 *v0; +} GetNullifiersBranchStateRequest__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "v0", + .dataTypeSpecific.clazz = GPBObjCClass(GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0), + .number = GetNullifiersBranchStateRequest_FieldNumber_V0, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetNullifiersBranchStateRequest__storage_, v0), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetNullifiersBranchStateRequest class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetNullifiersBranchStateRequest__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "version", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetNullifiersBranchStateRequest_ClearVersionOneOfCase(GetNullifiersBranchStateRequest *message) { + GPBDescriptor *descriptor = [GetNullifiersBranchStateRequest descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0 + +@implementation GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0 + +@dynamic poolType; +@dynamic poolIdentifier; +@dynamic key; +@dynamic depth; +@dynamic checkpointHeight; + +typedef struct GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0__storage_ { + uint32_t _has_storage_[1]; + uint32_t poolType; + uint32_t depth; + NSData *poolIdentifier; + NSData *key; + uint64_t checkpointHeight; +} GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "poolType", + .dataTypeSpecific.clazz = Nil, + .number = GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0_FieldNumber_PoolType, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0__storage_, poolType), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeUInt32, + }, + { + .name = "poolIdentifier", + .dataTypeSpecific.clazz = Nil, + .number = GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0_FieldNumber_PoolIdentifier, + .hasIndex = 1, + .offset = (uint32_t)offsetof(GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0__storage_, poolIdentifier), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeBytes, + }, + { + .name = "key", + .dataTypeSpecific.clazz = Nil, + .number = GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0_FieldNumber_Key, + .hasIndex = 2, + .offset = (uint32_t)offsetof(GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0__storage_, key), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeBytes, + }, + { + .name = "depth", + .dataTypeSpecific.clazz = Nil, + .number = GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0_FieldNumber_Depth, + .hasIndex = 3, + .offset = (uint32_t)offsetof(GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0__storage_, depth), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeUInt32, + }, + { + .name = "checkpointHeight", + .dataTypeSpecific.clazz = Nil, + .number = GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0_FieldNumber_CheckpointHeight, + .hasIndex = 4, + .offset = (uint32_t)offsetof(GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0__storage_, checkpointHeight), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeUInt64, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0 class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetNullifiersBranchStateRequest_GetNullifiersBranchStateRequestV0__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetNullifiersBranchStateRequest)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GetNullifiersBranchStateResponse + +@implementation GetNullifiersBranchStateResponse + +@dynamic versionOneOfCase; +@dynamic v0; + +typedef struct GetNullifiersBranchStateResponse__storage_ { + uint32_t _has_storage_[2]; + GetNullifiersBranchStateResponse_GetNullifiersBranchStateResponseV0 *v0; +} GetNullifiersBranchStateResponse__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "v0", + .dataTypeSpecific.clazz = GPBObjCClass(GetNullifiersBranchStateResponse_GetNullifiersBranchStateResponseV0), + .number = GetNullifiersBranchStateResponse_FieldNumber_V0, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetNullifiersBranchStateResponse__storage_, v0), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetNullifiersBranchStateResponse class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetNullifiersBranchStateResponse__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "version", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetNullifiersBranchStateResponse_ClearVersionOneOfCase(GetNullifiersBranchStateResponse *message) { + GPBDescriptor *descriptor = [GetNullifiersBranchStateResponse descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetNullifiersBranchStateResponse_GetNullifiersBranchStateResponseV0 + +@implementation GetNullifiersBranchStateResponse_GetNullifiersBranchStateResponseV0 + +@dynamic merkProof; + +typedef struct GetNullifiersBranchStateResponse_GetNullifiersBranchStateResponseV0__storage_ { + uint32_t _has_storage_[1]; + NSData *merkProof; +} GetNullifiersBranchStateResponse_GetNullifiersBranchStateResponseV0__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "merkProof", + .dataTypeSpecific.clazz = Nil, + .number = GetNullifiersBranchStateResponse_GetNullifiersBranchStateResponseV0_FieldNumber_MerkProof, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GetNullifiersBranchStateResponse_GetNullifiersBranchStateResponseV0__storage_, merkProof), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeBytes, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetNullifiersBranchStateResponse_GetNullifiersBranchStateResponseV0 class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetNullifiersBranchStateResponse_GetNullifiersBranchStateResponseV0__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetNullifiersBranchStateResponse)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - BlockNullifierChanges + +@implementation BlockNullifierChanges + +@dynamic blockHeight; +@dynamic nullifiersArray, nullifiersArray_Count; + +typedef struct BlockNullifierChanges__storage_ { + uint32_t _has_storage_[1]; + NSMutableArray *nullifiersArray; + uint64_t blockHeight; +} BlockNullifierChanges__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "blockHeight", + .dataTypeSpecific.clazz = Nil, + .number = BlockNullifierChanges_FieldNumber_BlockHeight, + .hasIndex = 0, + .offset = (uint32_t)offsetof(BlockNullifierChanges__storage_, blockHeight), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeUInt64, + }, + { + .name = "nullifiersArray", + .dataTypeSpecific.clazz = Nil, + .number = BlockNullifierChanges_FieldNumber_NullifiersArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(BlockNullifierChanges__storage_, nullifiersArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeBytes, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[BlockNullifierChanges class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(BlockNullifierChanges__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - NullifierUpdateEntries + +@implementation NullifierUpdateEntries + +@dynamic blockChangesArray, blockChangesArray_Count; + +typedef struct NullifierUpdateEntries__storage_ { + uint32_t _has_storage_[1]; + NSMutableArray *blockChangesArray; +} NullifierUpdateEntries__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "blockChangesArray", + .dataTypeSpecific.clazz = GPBObjCClass(BlockNullifierChanges), + .number = NullifierUpdateEntries_FieldNumber_BlockChangesArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(NullifierUpdateEntries__storage_, blockChangesArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[NullifierUpdateEntries class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(NullifierUpdateEntries__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GetRecentNullifierChangesRequest + +@implementation GetRecentNullifierChangesRequest + +@dynamic versionOneOfCase; +@dynamic v0; + +typedef struct GetRecentNullifierChangesRequest__storage_ { + uint32_t _has_storage_[2]; + GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0 *v0; +} GetRecentNullifierChangesRequest__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "v0", + .dataTypeSpecific.clazz = GPBObjCClass(GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0), + .number = GetRecentNullifierChangesRequest_FieldNumber_V0, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetRecentNullifierChangesRequest__storage_, v0), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetRecentNullifierChangesRequest class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetRecentNullifierChangesRequest__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "version", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetRecentNullifierChangesRequest_ClearVersionOneOfCase(GetRecentNullifierChangesRequest *message) { + GPBDescriptor *descriptor = [GetRecentNullifierChangesRequest descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0 + +@implementation GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0 + +@dynamic startHeight; +@dynamic prove; + +typedef struct GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0__storage_ { + uint32_t _has_storage_[1]; + uint64_t startHeight; +} GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "startHeight", + .dataTypeSpecific.clazz = Nil, + .number = GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0_FieldNumber_StartHeight, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0__storage_, startHeight), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeUInt64, + }, + { + .name = "prove", + .dataTypeSpecific.clazz = Nil, + .number = GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0_FieldNumber_Prove, + .hasIndex = 1, + .offset = 2, // Stored in _has_storage_ to save space. + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeBool, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0 class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetRecentNullifierChangesRequest_GetRecentNullifierChangesRequestV0__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetRecentNullifierChangesRequest)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GetRecentNullifierChangesResponse + +@implementation GetRecentNullifierChangesResponse + +@dynamic versionOneOfCase; +@dynamic v0; + +typedef struct GetRecentNullifierChangesResponse__storage_ { + uint32_t _has_storage_[2]; + GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0 *v0; +} GetRecentNullifierChangesResponse__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "v0", + .dataTypeSpecific.clazz = GPBObjCClass(GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0), + .number = GetRecentNullifierChangesResponse_FieldNumber_V0, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetRecentNullifierChangesResponse__storage_, v0), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetRecentNullifierChangesResponse class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetRecentNullifierChangesResponse__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "version", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetRecentNullifierChangesResponse_ClearVersionOneOfCase(GetRecentNullifierChangesResponse *message) { + GPBDescriptor *descriptor = [GetRecentNullifierChangesResponse descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0 + +@implementation GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0 + +@dynamic resultOneOfCase; +@dynamic nullifierUpdateEntries; +@dynamic proof; +@dynamic hasMetadata, metadata; + +typedef struct GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0__storage_ { + uint32_t _has_storage_[2]; + NullifierUpdateEntries *nullifierUpdateEntries; + Proof *proof; + ResponseMetadata *metadata; +} GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "nullifierUpdateEntries", + .dataTypeSpecific.clazz = GPBObjCClass(NullifierUpdateEntries), + .number = GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0_FieldNumber_NullifierUpdateEntries, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0__storage_, nullifierUpdateEntries), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + { + .name = "proof", + .dataTypeSpecific.clazz = GPBObjCClass(Proof), + .number = GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0_FieldNumber_Proof, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0__storage_, proof), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + { + .name = "metadata", + .dataTypeSpecific.clazz = GPBObjCClass(ResponseMetadata), + .number = GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0_FieldNumber_Metadata, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0__storage_, metadata), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0 class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "result", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetRecentNullifierChangesResponse)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0_ClearResultOneOfCase(GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0 *message) { + GPBDescriptor *descriptor = [GetRecentNullifierChangesResponse_GetRecentNullifierChangesResponseV0 descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - CompactedBlockNullifierChanges + +@implementation CompactedBlockNullifierChanges + +@dynamic startBlockHeight; +@dynamic endBlockHeight; +@dynamic nullifiersArray, nullifiersArray_Count; + +typedef struct CompactedBlockNullifierChanges__storage_ { + uint32_t _has_storage_[1]; + NSMutableArray *nullifiersArray; + uint64_t startBlockHeight; + uint64_t endBlockHeight; +} CompactedBlockNullifierChanges__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "startBlockHeight", + .dataTypeSpecific.clazz = Nil, + .number = CompactedBlockNullifierChanges_FieldNumber_StartBlockHeight, + .hasIndex = 0, + .offset = (uint32_t)offsetof(CompactedBlockNullifierChanges__storage_, startBlockHeight), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeUInt64, + }, + { + .name = "endBlockHeight", + .dataTypeSpecific.clazz = Nil, + .number = CompactedBlockNullifierChanges_FieldNumber_EndBlockHeight, + .hasIndex = 1, + .offset = (uint32_t)offsetof(CompactedBlockNullifierChanges__storage_, endBlockHeight), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeUInt64, + }, + { + .name = "nullifiersArray", + .dataTypeSpecific.clazz = Nil, + .number = CompactedBlockNullifierChanges_FieldNumber_NullifiersArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(CompactedBlockNullifierChanges__storage_, nullifiersArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeBytes, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[CompactedBlockNullifierChanges class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(CompactedBlockNullifierChanges__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - CompactedNullifierUpdateEntries + +@implementation CompactedNullifierUpdateEntries + +@dynamic compactedBlockChangesArray, compactedBlockChangesArray_Count; + +typedef struct CompactedNullifierUpdateEntries__storage_ { + uint32_t _has_storage_[1]; + NSMutableArray *compactedBlockChangesArray; +} CompactedNullifierUpdateEntries__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "compactedBlockChangesArray", + .dataTypeSpecific.clazz = GPBObjCClass(CompactedBlockNullifierChanges), + .number = CompactedNullifierUpdateEntries_FieldNumber_CompactedBlockChangesArray, + .hasIndex = GPBNoHasBit, + .offset = (uint32_t)offsetof(CompactedNullifierUpdateEntries__storage_, compactedBlockChangesArray), + .flags = GPBFieldRepeated, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[CompactedNullifierUpdateEntries class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(CompactedNullifierUpdateEntries__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GetRecentCompactedNullifierChangesRequest + +@implementation GetRecentCompactedNullifierChangesRequest + +@dynamic versionOneOfCase; +@dynamic v0; + +typedef struct GetRecentCompactedNullifierChangesRequest__storage_ { + uint32_t _has_storage_[2]; + GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0 *v0; +} GetRecentCompactedNullifierChangesRequest__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "v0", + .dataTypeSpecific.clazz = GPBObjCClass(GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0), + .number = GetRecentCompactedNullifierChangesRequest_FieldNumber_V0, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetRecentCompactedNullifierChangesRequest__storage_, v0), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetRecentCompactedNullifierChangesRequest class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetRecentCompactedNullifierChangesRequest__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "version", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetRecentCompactedNullifierChangesRequest_ClearVersionOneOfCase(GetRecentCompactedNullifierChangesRequest *message) { + GPBDescriptor *descriptor = [GetRecentCompactedNullifierChangesRequest descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0 + +@implementation GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0 + +@dynamic startBlockHeight; +@dynamic prove; + +typedef struct GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0__storage_ { + uint32_t _has_storage_[1]; + uint64_t startBlockHeight; +} GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "startBlockHeight", + .dataTypeSpecific.clazz = Nil, + .number = GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0_FieldNumber_StartBlockHeight, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0__storage_, startBlockHeight), + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeUInt64, + }, + { + .name = "prove", + .dataTypeSpecific.clazz = Nil, + .number = GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0_FieldNumber_Prove, + .hasIndex = 1, + .offset = 2, // Stored in _has_storage_ to save space. + .flags = (GPBFieldFlags)(GPBFieldOptional | GPBFieldClearHasIvarOnZero), + .dataType = GPBDataTypeBool, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0 class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetRecentCompactedNullifierChangesRequest_GetRecentCompactedNullifierChangesRequestV0__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetRecentCompactedNullifierChangesRequest)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +#pragma mark - GetRecentCompactedNullifierChangesResponse + +@implementation GetRecentCompactedNullifierChangesResponse + +@dynamic versionOneOfCase; +@dynamic v0; + +typedef struct GetRecentCompactedNullifierChangesResponse__storage_ { + uint32_t _has_storage_[2]; + GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0 *v0; +} GetRecentCompactedNullifierChangesResponse__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "v0", + .dataTypeSpecific.clazz = GPBObjCClass(GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0), + .number = GetRecentCompactedNullifierChangesResponse_FieldNumber_V0, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetRecentCompactedNullifierChangesResponse__storage_, v0), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetRecentCompactedNullifierChangesResponse class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetRecentCompactedNullifierChangesResponse__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "version", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetRecentCompactedNullifierChangesResponse_ClearVersionOneOfCase(GetRecentCompactedNullifierChangesResponse *message) { + GPBDescriptor *descriptor = [GetRecentCompactedNullifierChangesResponse descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} +#pragma mark - GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0 + +@implementation GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0 + +@dynamic resultOneOfCase; +@dynamic compactedNullifierUpdateEntries; +@dynamic proof; +@dynamic hasMetadata, metadata; + +typedef struct GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0__storage_ { + uint32_t _has_storage_[2]; + CompactedNullifierUpdateEntries *compactedNullifierUpdateEntries; + Proof *proof; + ResponseMetadata *metadata; +} GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0__storage_; + +// This method is threadsafe because it is initially called +// in +initialize for each subclass. ++ (GPBDescriptor *)descriptor { + static GPBDescriptor *descriptor = nil; + if (!descriptor) { + static GPBMessageFieldDescription fields[] = { + { + .name = "compactedNullifierUpdateEntries", + .dataTypeSpecific.clazz = GPBObjCClass(CompactedNullifierUpdateEntries), + .number = GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0_FieldNumber_CompactedNullifierUpdateEntries, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0__storage_, compactedNullifierUpdateEntries), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + { + .name = "proof", + .dataTypeSpecific.clazz = GPBObjCClass(Proof), + .number = GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0_FieldNumber_Proof, + .hasIndex = -1, + .offset = (uint32_t)offsetof(GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0__storage_, proof), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + { + .name = "metadata", + .dataTypeSpecific.clazz = GPBObjCClass(ResponseMetadata), + .number = GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0_FieldNumber_Metadata, + .hasIndex = 0, + .offset = (uint32_t)offsetof(GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0__storage_, metadata), + .flags = GPBFieldOptional, + .dataType = GPBDataTypeMessage, + }, + }; + GPBDescriptor *localDescriptor = + [GPBDescriptor allocDescriptorForClass:[GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0 class] + rootClass:[PlatformRoot class] + file:PlatformRoot_FileDescriptor() + fields:fields + fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription)) + storageSize:sizeof(GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0__storage_) + flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown)]; + static const char *oneofs[] = { + "result", + }; + [localDescriptor setupOneofs:oneofs + count:(uint32_t)(sizeof(oneofs) / sizeof(char*)) + firstHasIndex:-1]; + [localDescriptor setupContainingMessageClass:GPBObjCClass(GetRecentCompactedNullifierChangesResponse)]; + #if defined(DEBUG) && DEBUG + NSAssert(descriptor == nil, @"Startup recursed!"); + #endif // DEBUG + descriptor = localDescriptor; + } + return descriptor; +} + +@end + +void GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0_ClearResultOneOfCase(GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0 *message) { + GPBDescriptor *descriptor = [GetRecentCompactedNullifierChangesResponse_GetRecentCompactedNullifierChangesResponseV0 descriptor]; + GPBOneofDescriptor *oneof = [descriptor.oneofs objectAtIndex:0]; + GPBClearOneof(message, oneof); +} #pragma clang diagnostic pop diff --git a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.h b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.h index ca3c040a8ae..fa3b016fe90 100644 --- a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.h +++ b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.h @@ -87,6 +87,10 @@ @class GetIdentityTokenBalancesResponse; @class GetIdentityTokenInfosRequest; @class GetIdentityTokenInfosResponse; +@class GetNullifiersBranchStateRequest; +@class GetNullifiersBranchStateResponse; +@class GetNullifiersTrunkStateRequest; +@class GetNullifiersTrunkStateResponse; @class GetPathElementsRequest; @class GetPathElementsResponse; @class GetPrefundedSpecializedBalanceRequest; @@ -99,6 +103,10 @@ @class GetRecentAddressBalanceChangesResponse; @class GetRecentCompactedAddressBalanceChangesRequest; @class GetRecentCompactedAddressBalanceChangesResponse; +@class GetRecentCompactedNullifierChangesRequest; +@class GetRecentCompactedNullifierChangesResponse; +@class GetRecentNullifierChangesRequest; +@class GetRecentNullifierChangesResponse; @class GetShieldedAnchorsRequest; @class GetShieldedAnchorsResponse; @class GetShieldedEncryptedNotesRequest; @@ -400,6 +408,22 @@ NS_ASSUME_NONNULL_BEGIN - (GRPCUnaryProtoCall *)getShieldedNullifiersWithMessage:(GetShieldedNullifiersRequest *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *_Nullable)callOptions; +#pragma mark getNullifiersTrunkState(GetNullifiersTrunkStateRequest) returns (GetNullifiersTrunkStateResponse) + +- (GRPCUnaryProtoCall *)getNullifiersTrunkStateWithMessage:(GetNullifiersTrunkStateRequest *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *_Nullable)callOptions; + +#pragma mark getNullifiersBranchState(GetNullifiersBranchStateRequest) returns (GetNullifiersBranchStateResponse) + +- (GRPCUnaryProtoCall *)getNullifiersBranchStateWithMessage:(GetNullifiersBranchStateRequest *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *_Nullable)callOptions; + +#pragma mark getRecentNullifierChanges(GetRecentNullifierChangesRequest) returns (GetRecentNullifierChangesResponse) + +- (GRPCUnaryProtoCall *)getRecentNullifierChangesWithMessage:(GetRecentNullifierChangesRequest *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *_Nullable)callOptions; + +#pragma mark getRecentCompactedNullifierChanges(GetRecentCompactedNullifierChangesRequest) returns (GetRecentCompactedNullifierChangesResponse) + +- (GRPCUnaryProtoCall *)getRecentCompactedNullifierChangesWithMessage:(GetRecentCompactedNullifierChangesRequest *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *_Nullable)callOptions; + @end /** @@ -857,6 +881,34 @@ NS_ASSUME_NONNULL_BEGIN - (GRPCProtoCall *)RPCTogetShieldedNullifiersWithRequest:(GetShieldedNullifiersRequest *)request handler:(void(^)(GetShieldedNullifiersResponse *_Nullable response, NSError *_Nullable error))handler; +#pragma mark getNullifiersTrunkState(GetNullifiersTrunkStateRequest) returns (GetNullifiersTrunkStateResponse) + +- (void)getNullifiersTrunkStateWithRequest:(GetNullifiersTrunkStateRequest *)request handler:(void(^)(GetNullifiersTrunkStateResponse *_Nullable response, NSError *_Nullable error))handler; + +- (GRPCProtoCall *)RPCTogetNullifiersTrunkStateWithRequest:(GetNullifiersTrunkStateRequest *)request handler:(void(^)(GetNullifiersTrunkStateResponse *_Nullable response, NSError *_Nullable error))handler; + + +#pragma mark getNullifiersBranchState(GetNullifiersBranchStateRequest) returns (GetNullifiersBranchStateResponse) + +- (void)getNullifiersBranchStateWithRequest:(GetNullifiersBranchStateRequest *)request handler:(void(^)(GetNullifiersBranchStateResponse *_Nullable response, NSError *_Nullable error))handler; + +- (GRPCProtoCall *)RPCTogetNullifiersBranchStateWithRequest:(GetNullifiersBranchStateRequest *)request handler:(void(^)(GetNullifiersBranchStateResponse *_Nullable response, NSError *_Nullable error))handler; + + +#pragma mark getRecentNullifierChanges(GetRecentNullifierChangesRequest) returns (GetRecentNullifierChangesResponse) + +- (void)getRecentNullifierChangesWithRequest:(GetRecentNullifierChangesRequest *)request handler:(void(^)(GetRecentNullifierChangesResponse *_Nullable response, NSError *_Nullable error))handler; + +- (GRPCProtoCall *)RPCTogetRecentNullifierChangesWithRequest:(GetRecentNullifierChangesRequest *)request handler:(void(^)(GetRecentNullifierChangesResponse *_Nullable response, NSError *_Nullable error))handler; + + +#pragma mark getRecentCompactedNullifierChanges(GetRecentCompactedNullifierChangesRequest) returns (GetRecentCompactedNullifierChangesResponse) + +- (void)getRecentCompactedNullifierChangesWithRequest:(GetRecentCompactedNullifierChangesRequest *)request handler:(void(^)(GetRecentCompactedNullifierChangesResponse *_Nullable response, NSError *_Nullable error))handler; + +- (GRPCProtoCall *)RPCTogetRecentCompactedNullifierChangesWithRequest:(GetRecentCompactedNullifierChangesRequest *)request handler:(void(^)(GetRecentCompactedNullifierChangesResponse *_Nullable response, NSError *_Nullable error))handler; + + @end diff --git a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.m b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.m index 80aec983df3..49006e3eed6 100644 --- a/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.m +++ b/packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.m @@ -1275,5 +1275,85 @@ - (GRPCUnaryProtoCall *)getShieldedNullifiersWithMessage:(GetShieldedNullifiersR responseClass:[GetShieldedNullifiersResponse class]]; } +#pragma mark getNullifiersTrunkState(GetNullifiersTrunkStateRequest) returns (GetNullifiersTrunkStateResponse) + +- (void)getNullifiersTrunkStateWithRequest:(GetNullifiersTrunkStateRequest *)request handler:(void(^)(GetNullifiersTrunkStateResponse *_Nullable response, NSError *_Nullable error))handler{ + [[self RPCTogetNullifiersTrunkStateWithRequest:request handler:handler] start]; +} +// Returns a not-yet-started RPC object. +- (GRPCProtoCall *)RPCTogetNullifiersTrunkStateWithRequest:(GetNullifiersTrunkStateRequest *)request handler:(void(^)(GetNullifiersTrunkStateResponse *_Nullable response, NSError *_Nullable error))handler{ + return [self RPCToMethod:@"getNullifiersTrunkState" + requestsWriter:[GRXWriter writerWithValue:request] + responseClass:[GetNullifiersTrunkStateResponse class] + responsesWriteable:[GRXWriteable writeableWithSingleHandler:handler]]; +} +- (GRPCUnaryProtoCall *)getNullifiersTrunkStateWithMessage:(GetNullifiersTrunkStateRequest *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *_Nullable)callOptions { + return [self RPCToMethod:@"getNullifiersTrunkState" + message:message + responseHandler:handler + callOptions:callOptions + responseClass:[GetNullifiersTrunkStateResponse class]]; +} + +#pragma mark getNullifiersBranchState(GetNullifiersBranchStateRequest) returns (GetNullifiersBranchStateResponse) + +- (void)getNullifiersBranchStateWithRequest:(GetNullifiersBranchStateRequest *)request handler:(void(^)(GetNullifiersBranchStateResponse *_Nullable response, NSError *_Nullable error))handler{ + [[self RPCTogetNullifiersBranchStateWithRequest:request handler:handler] start]; +} +// Returns a not-yet-started RPC object. +- (GRPCProtoCall *)RPCTogetNullifiersBranchStateWithRequest:(GetNullifiersBranchStateRequest *)request handler:(void(^)(GetNullifiersBranchStateResponse *_Nullable response, NSError *_Nullable error))handler{ + return [self RPCToMethod:@"getNullifiersBranchState" + requestsWriter:[GRXWriter writerWithValue:request] + responseClass:[GetNullifiersBranchStateResponse class] + responsesWriteable:[GRXWriteable writeableWithSingleHandler:handler]]; +} +- (GRPCUnaryProtoCall *)getNullifiersBranchStateWithMessage:(GetNullifiersBranchStateRequest *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *_Nullable)callOptions { + return [self RPCToMethod:@"getNullifiersBranchState" + message:message + responseHandler:handler + callOptions:callOptions + responseClass:[GetNullifiersBranchStateResponse class]]; +} + +#pragma mark getRecentNullifierChanges(GetRecentNullifierChangesRequest) returns (GetRecentNullifierChangesResponse) + +- (void)getRecentNullifierChangesWithRequest:(GetRecentNullifierChangesRequest *)request handler:(void(^)(GetRecentNullifierChangesResponse *_Nullable response, NSError *_Nullable error))handler{ + [[self RPCTogetRecentNullifierChangesWithRequest:request handler:handler] start]; +} +// Returns a not-yet-started RPC object. +- (GRPCProtoCall *)RPCTogetRecentNullifierChangesWithRequest:(GetRecentNullifierChangesRequest *)request handler:(void(^)(GetRecentNullifierChangesResponse *_Nullable response, NSError *_Nullable error))handler{ + return [self RPCToMethod:@"getRecentNullifierChanges" + requestsWriter:[GRXWriter writerWithValue:request] + responseClass:[GetRecentNullifierChangesResponse class] + responsesWriteable:[GRXWriteable writeableWithSingleHandler:handler]]; +} +- (GRPCUnaryProtoCall *)getRecentNullifierChangesWithMessage:(GetRecentNullifierChangesRequest *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *_Nullable)callOptions { + return [self RPCToMethod:@"getRecentNullifierChanges" + message:message + responseHandler:handler + callOptions:callOptions + responseClass:[GetRecentNullifierChangesResponse class]]; +} + +#pragma mark getRecentCompactedNullifierChanges(GetRecentCompactedNullifierChangesRequest) returns (GetRecentCompactedNullifierChangesResponse) + +- (void)getRecentCompactedNullifierChangesWithRequest:(GetRecentCompactedNullifierChangesRequest *)request handler:(void(^)(GetRecentCompactedNullifierChangesResponse *_Nullable response, NSError *_Nullable error))handler{ + [[self RPCTogetRecentCompactedNullifierChangesWithRequest:request handler:handler] start]; +} +// Returns a not-yet-started RPC object. +- (GRPCProtoCall *)RPCTogetRecentCompactedNullifierChangesWithRequest:(GetRecentCompactedNullifierChangesRequest *)request handler:(void(^)(GetRecentCompactedNullifierChangesResponse *_Nullable response, NSError *_Nullable error))handler{ + return [self RPCToMethod:@"getRecentCompactedNullifierChanges" + requestsWriter:[GRXWriter writerWithValue:request] + responseClass:[GetRecentCompactedNullifierChangesResponse class] + responsesWriteable:[GRXWriteable writeableWithSingleHandler:handler]]; +} +- (GRPCUnaryProtoCall *)getRecentCompactedNullifierChangesWithMessage:(GetRecentCompactedNullifierChangesRequest *)message responseHandler:(id)handler callOptions:(GRPCCallOptions *_Nullable)callOptions { + return [self RPCToMethod:@"getRecentCompactedNullifierChanges" + message:message + responseHandler:handler + callOptions:callOptions + responseClass:[GetRecentCompactedNullifierChangesResponse class]]; +} + @end #endif diff --git a/packages/dapi-grpc/clients/platform/v0/python/platform_pb2.py b/packages/dapi-grpc/clients/platform/v0/python/platform_pb2.py index bf369b20a0c..c0f9758b733 100644 --- a/packages/dapi-grpc/clients/platform/v0/python/platform_pb2.py +++ b/packages/dapi-grpc/clients/platform/v0/python/platform_pb2.py @@ -23,7 +23,7 @@ syntax='proto3', serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x0eplatform.proto\x12\x19org.dash.platform.dapi.v0\x1a\x1egoogle/protobuf/wrappers.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x81\x01\n\x05Proof\x12\x15\n\rgrovedb_proof\x18\x01 \x01(\x0c\x12\x13\n\x0bquorum_hash\x18\x02 \x01(\x0c\x12\x11\n\tsignature\x18\x03 \x01(\x0c\x12\r\n\x05round\x18\x04 \x01(\r\x12\x15\n\rblock_id_hash\x18\x05 \x01(\x0c\x12\x13\n\x0bquorum_type\x18\x06 \x01(\r\"\x98\x01\n\x10ResponseMetadata\x12\x12\n\x06height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12 \n\x18\x63ore_chain_locked_height\x18\x02 \x01(\r\x12\r\n\x05\x65poch\x18\x03 \x01(\r\x12\x13\n\x07time_ms\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x18\n\x10protocol_version\x18\x05 \x01(\r\x12\x10\n\x08\x63hain_id\x18\x06 \x01(\t\"L\n\x1dStateTransitionBroadcastError\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\";\n\x1f\x42roadcastStateTransitionRequest\x12\x18\n\x10state_transition\x18\x01 \x01(\x0c\"\"\n BroadcastStateTransitionResponse\"\xa4\x01\n\x12GetIdentityRequest\x12P\n\x02v0\x18\x01 \x01(\x0b\x32\x42.org.dash.platform.dapi.v0.GetIdentityRequest.GetIdentityRequestV0H\x00\x1a\x31\n\x14GetIdentityRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xc1\x01\n\x17GetIdentityNonceRequest\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetIdentityNonceRequest.GetIdentityNonceRequestV0H\x00\x1a?\n\x19GetIdentityNonceRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xf6\x01\n\x1fGetIdentityContractNonceRequest\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetIdentityContractNonceRequest.GetIdentityContractNonceRequestV0H\x00\x1a\\\n!GetIdentityContractNonceRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x13\n\x0b\x63ontract_id\x18\x02 \x01(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xc0\x01\n\x19GetIdentityBalanceRequest\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetIdentityBalanceRequest.GetIdentityBalanceRequestV0H\x00\x1a\x38\n\x1bGetIdentityBalanceRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xec\x01\n$GetIdentityBalanceAndRevisionRequest\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionRequest.GetIdentityBalanceAndRevisionRequestV0H\x00\x1a\x43\n&GetIdentityBalanceAndRevisionRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x9e\x02\n\x13GetIdentityResponse\x12R\n\x02v0\x18\x01 \x01(\x0b\x32\x44.org.dash.platform.dapi.v0.GetIdentityResponse.GetIdentityResponseV0H\x00\x1a\xa7\x01\n\x15GetIdentityResponseV0\x12\x12\n\x08identity\x18\x01 \x01(\x0cH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xbc\x02\n\x18GetIdentityNonceResponse\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetIdentityNonceResponse.GetIdentityNonceResponseV0H\x00\x1a\xb6\x01\n\x1aGetIdentityNonceResponseV0\x12\x1c\n\x0eidentity_nonce\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xe5\x02\n GetIdentityContractNonceResponse\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetIdentityContractNonceResponse.GetIdentityContractNonceResponseV0H\x00\x1a\xc7\x01\n\"GetIdentityContractNonceResponseV0\x12%\n\x17identity_contract_nonce\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xbd\x02\n\x1aGetIdentityBalanceResponse\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetIdentityBalanceResponse.GetIdentityBalanceResponseV0H\x00\x1a\xb1\x01\n\x1cGetIdentityBalanceResponseV0\x12\x15\n\x07\x62\x61lance\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xb1\x04\n%GetIdentityBalanceAndRevisionResponse\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionResponse.GetIdentityBalanceAndRevisionResponseV0H\x00\x1a\x84\x03\n\'GetIdentityBalanceAndRevisionResponseV0\x12\x9b\x01\n\x14\x62\x61lance_and_revision\x18\x01 \x01(\x0b\x32{.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionResponse.GetIdentityBalanceAndRevisionResponseV0.BalanceAndRevisionH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a?\n\x12\x42\x61lanceAndRevision\x12\x13\n\x07\x62\x61lance\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x14\n\x08revision\x18\x02 \x01(\x04\x42\x02\x30\x01\x42\x08\n\x06resultB\t\n\x07version\"\xd1\x01\n\x0eKeyRequestType\x12\x36\n\x08\x61ll_keys\x18\x01 \x01(\x0b\x32\".org.dash.platform.dapi.v0.AllKeysH\x00\x12@\n\rspecific_keys\x18\x02 \x01(\x0b\x32\'.org.dash.platform.dapi.v0.SpecificKeysH\x00\x12:\n\nsearch_key\x18\x03 \x01(\x0b\x32$.org.dash.platform.dapi.v0.SearchKeyH\x00\x42\t\n\x07request\"\t\n\x07\x41llKeys\"\x1f\n\x0cSpecificKeys\x12\x0f\n\x07key_ids\x18\x01 \x03(\r\"\xb6\x01\n\tSearchKey\x12I\n\x0bpurpose_map\x18\x01 \x03(\x0b\x32\x34.org.dash.platform.dapi.v0.SearchKey.PurposeMapEntry\x1a^\n\x0fPurposeMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12:\n\x05value\x18\x02 \x01(\x0b\x32+.org.dash.platform.dapi.v0.SecurityLevelMap:\x02\x38\x01\"\xbf\x02\n\x10SecurityLevelMap\x12]\n\x12security_level_map\x18\x01 \x03(\x0b\x32\x41.org.dash.platform.dapi.v0.SecurityLevelMap.SecurityLevelMapEntry\x1aw\n\x15SecurityLevelMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12M\n\x05value\x18\x02 \x01(\x0e\x32>.org.dash.platform.dapi.v0.SecurityLevelMap.KeyKindRequestType:\x02\x38\x01\"S\n\x12KeyKindRequestType\x12\x1f\n\x1b\x43URRENT_KEY_OF_KIND_REQUEST\x10\x00\x12\x1c\n\x18\x41LL_KEYS_OF_KIND_REQUEST\x10\x01\"\xda\x02\n\x16GetIdentityKeysRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetIdentityKeysRequest.GetIdentityKeysRequestV0H\x00\x1a\xda\x01\n\x18GetIdentityKeysRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12?\n\x0crequest_type\x18\x02 \x01(\x0b\x32).org.dash.platform.dapi.v0.KeyRequestType\x12+\n\x05limit\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12,\n\x06offset\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\t\n\x07version\"\x99\x03\n\x17GetIdentityKeysResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetIdentityKeysResponse.GetIdentityKeysResponseV0H\x00\x1a\x96\x02\n\x19GetIdentityKeysResponseV0\x12\x61\n\x04keys\x18\x01 \x01(\x0b\x32Q.org.dash.platform.dapi.v0.GetIdentityKeysResponse.GetIdentityKeysResponseV0.KeysH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1a\n\x04Keys\x12\x12\n\nkeys_bytes\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xef\x02\n GetIdentitiesContractKeysRequest\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetIdentitiesContractKeysRequest.GetIdentitiesContractKeysRequestV0H\x00\x1a\xd1\x01\n\"GetIdentitiesContractKeysRequestV0\x12\x16\n\x0eidentities_ids\x18\x01 \x03(\x0c\x12\x13\n\x0b\x63ontract_id\x18\x02 \x01(\x0c\x12\x1f\n\x12\x64ocument_type_name\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x37\n\x08purposes\x18\x04 \x03(\x0e\x32%.org.dash.platform.dapi.v0.KeyPurpose\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\x15\n\x13_document_type_nameB\t\n\x07version\"\xdf\x06\n!GetIdentitiesContractKeysResponse\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0H\x00\x1a\xbe\x05\n#GetIdentitiesContractKeysResponseV0\x12\x8a\x01\n\x0fidentities_keys\x18\x01 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0.IdentitiesKeysH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aY\n\x0bPurposeKeys\x12\x36\n\x07purpose\x18\x01 \x01(\x0e\x32%.org.dash.platform.dapi.v0.KeyPurpose\x12\x12\n\nkeys_bytes\x18\x02 \x03(\x0c\x1a\x9f\x01\n\x0cIdentityKeys\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12z\n\x04keys\x18\x02 \x03(\x0b\x32l.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0.PurposeKeys\x1a\x90\x01\n\x0eIdentitiesKeys\x12~\n\x07\x65ntries\x18\x01 \x03(\x0b\x32m.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0.IdentityKeysB\x08\n\x06resultB\t\n\x07version\"\xa4\x02\n*GetEvonodesProposedEpochBlocksByIdsRequest\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByIdsRequest.GetEvonodesProposedEpochBlocksByIdsRequestV0H\x00\x1ah\n,GetEvonodesProposedEpochBlocksByIdsRequestV0\x12\x12\n\x05\x65poch\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x0b\n\x03ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\x08\n\x06_epochB\t\n\x07version\"\x92\x06\n&GetEvonodesProposedEpochBlocksResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse.GetEvonodesProposedEpochBlocksResponseV0H\x00\x1a\xe2\x04\n(GetEvonodesProposedEpochBlocksResponseV0\x12\xb1\x01\n#evonodes_proposed_block_counts_info\x18\x01 \x01(\x0b\x32\x81\x01.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse.GetEvonodesProposedEpochBlocksResponseV0.EvonodesProposedBlocksH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a?\n\x15\x45vonodeProposedBlocks\x12\x13\n\x0bpro_tx_hash\x18\x01 \x01(\x0c\x12\x11\n\x05\x63ount\x18\x02 \x01(\x04\x42\x02\x30\x01\x1a\xc4\x01\n\x16\x45vonodesProposedBlocks\x12\xa9\x01\n\x1e\x65vonodes_proposed_block_counts\x18\x01 \x03(\x0b\x32\x80\x01.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse.GetEvonodesProposedEpochBlocksResponseV0.EvonodeProposedBlocksB\x08\n\x06resultB\t\n\x07version\"\xf2\x02\n,GetEvonodesProposedEpochBlocksByRangeRequest\x12\x84\x01\n\x02v0\x18\x01 \x01(\x0b\x32v.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByRangeRequest.GetEvonodesProposedEpochBlocksByRangeRequestV0H\x00\x1a\xaf\x01\n.GetEvonodesProposedEpochBlocksByRangeRequestV0\x12\x12\n\x05\x65poch\x18\x01 \x01(\rH\x01\x88\x01\x01\x12\x12\n\x05limit\x18\x02 \x01(\rH\x02\x88\x01\x01\x12\x15\n\x0bstart_after\x18\x03 \x01(\x0cH\x00\x12\x12\n\x08start_at\x18\x04 \x01(\x0cH\x00\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\x07\n\x05startB\x08\n\x06_epochB\x08\n\x06_limitB\t\n\x07version\"\xcd\x01\n\x1cGetIdentitiesBalancesRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetIdentitiesBalancesRequest.GetIdentitiesBalancesRequestV0H\x00\x1a<\n\x1eGetIdentitiesBalancesRequestV0\x12\x0b\n\x03ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x9f\x05\n\x1dGetIdentitiesBalancesResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse.GetIdentitiesBalancesResponseV0H\x00\x1a\x8a\x04\n\x1fGetIdentitiesBalancesResponseV0\x12\x8a\x01\n\x13identities_balances\x18\x01 \x01(\x0b\x32k.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse.GetIdentitiesBalancesResponseV0.IdentitiesBalancesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aL\n\x0fIdentityBalance\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x18\n\x07\x62\x61lance\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x88\x01\x01\x42\n\n\x08_balance\x1a\x8f\x01\n\x12IdentitiesBalances\x12y\n\x07\x65ntries\x18\x01 \x03(\x0b\x32h.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse.GetIdentitiesBalancesResponseV0.IdentityBalanceB\x08\n\x06resultB\t\n\x07version\"\xb4\x01\n\x16GetDataContractRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetDataContractRequest.GetDataContractRequestV0H\x00\x1a\x35\n\x18GetDataContractRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xb3\x02\n\x17GetDataContractResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetDataContractResponse.GetDataContractResponseV0H\x00\x1a\xb0\x01\n\x19GetDataContractResponseV0\x12\x17\n\rdata_contract\x18\x01 \x01(\x0cH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xb9\x01\n\x17GetDataContractsRequest\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetDataContractsRequest.GetDataContractsRequestV0H\x00\x1a\x37\n\x19GetDataContractsRequestV0\x12\x0b\n\x03ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xcf\x04\n\x18GetDataContractsResponse\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetDataContractsResponse.GetDataContractsResponseV0H\x00\x1a[\n\x11\x44\x61taContractEntry\x12\x12\n\nidentifier\x18\x01 \x01(\x0c\x12\x32\n\rdata_contract\x18\x02 \x01(\x0b\x32\x1b.google.protobuf.BytesValue\x1au\n\rDataContracts\x12\x64\n\x15\x64\x61ta_contract_entries\x18\x01 \x03(\x0b\x32\x45.org.dash.platform.dapi.v0.GetDataContractsResponse.DataContractEntry\x1a\xf5\x01\n\x1aGetDataContractsResponseV0\x12[\n\x0e\x64\x61ta_contracts\x18\x01 \x01(\x0b\x32\x41.org.dash.platform.dapi.v0.GetDataContractsResponse.DataContractsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc5\x02\n\x1dGetDataContractHistoryRequest\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetDataContractHistoryRequest.GetDataContractHistoryRequestV0H\x00\x1a\xb0\x01\n\x1fGetDataContractHistoryRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12+\n\x05limit\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12,\n\x06offset\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\x17\n\x0bstart_at_ms\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\t\n\x07version\"\xb2\x05\n\x1eGetDataContractHistoryResponse\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetDataContractHistoryResponse.GetDataContractHistoryResponseV0H\x00\x1a\x9a\x04\n GetDataContractHistoryResponseV0\x12\x8f\x01\n\x15\x64\x61ta_contract_history\x18\x01 \x01(\x0b\x32n.org.dash.platform.dapi.v0.GetDataContractHistoryResponse.GetDataContractHistoryResponseV0.DataContractHistoryH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a;\n\x18\x44\x61taContractHistoryEntry\x12\x10\n\x04\x64\x61te\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05value\x18\x02 \x01(\x0c\x1a\xaa\x01\n\x13\x44\x61taContractHistory\x12\x92\x01\n\x15\x64\x61ta_contract_entries\x18\x01 \x03(\x0b\x32s.org.dash.platform.dapi.v0.GetDataContractHistoryResponse.GetDataContractHistoryResponseV0.DataContractHistoryEntryB\x08\n\x06resultB\t\n\x07version\"\xb2\x02\n\x13GetDocumentsRequest\x12R\n\x02v0\x18\x01 \x01(\x0b\x32\x44.org.dash.platform.dapi.v0.GetDocumentsRequest.GetDocumentsRequestV0H\x00\x1a\xbb\x01\n\x15GetDocumentsRequestV0\x12\x18\n\x10\x64\x61ta_contract_id\x18\x01 \x01(\x0c\x12\x15\n\rdocument_type\x18\x02 \x01(\t\x12\r\n\x05where\x18\x03 \x01(\x0c\x12\x10\n\x08order_by\x18\x04 \x01(\x0c\x12\r\n\x05limit\x18\x05 \x01(\r\x12\x15\n\x0bstart_after\x18\x06 \x01(\x0cH\x00\x12\x12\n\x08start_at\x18\x07 \x01(\x0cH\x00\x12\r\n\x05prove\x18\x08 \x01(\x08\x42\x07\n\x05startB\t\n\x07version\"\x95\x03\n\x14GetDocumentsResponse\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetDocumentsResponse.GetDocumentsResponseV0H\x00\x1a\x9b\x02\n\x16GetDocumentsResponseV0\x12\x65\n\tdocuments\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetDocumentsResponse.GetDocumentsResponseV0.DocumentsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1e\n\tDocuments\x12\x11\n\tdocuments\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xed\x01\n!GetIdentityByPublicKeyHashRequest\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashRequest.GetIdentityByPublicKeyHashRequestV0H\x00\x1aM\n#GetIdentityByPublicKeyHashRequestV0\x12\x17\n\x0fpublic_key_hash\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xda\x02\n\"GetIdentityByPublicKeyHashResponse\x12p\n\x02v0\x18\x01 \x01(\x0b\x32\x62.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashResponse.GetIdentityByPublicKeyHashResponseV0H\x00\x1a\xb6\x01\n$GetIdentityByPublicKeyHashResponseV0\x12\x12\n\x08identity\x18\x01 \x01(\x0cH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xbd\x02\n*GetIdentityByNonUniquePublicKeyHashRequest\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashRequest.GetIdentityByNonUniquePublicKeyHashRequestV0H\x00\x1a\x80\x01\n,GetIdentityByNonUniquePublicKeyHashRequestV0\x12\x17\n\x0fpublic_key_hash\x18\x01 \x01(\x0c\x12\x18\n\x0bstart_after\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\x0e\n\x0c_start_afterB\t\n\x07version\"\xd6\x06\n+GetIdentityByNonUniquePublicKeyHashResponse\x12\x82\x01\n\x02v0\x18\x01 \x01(\x0b\x32t.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse.GetIdentityByNonUniquePublicKeyHashResponseV0H\x00\x1a\x96\x05\n-GetIdentityByNonUniquePublicKeyHashResponseV0\x12\x9a\x01\n\x08identity\x18\x01 \x01(\x0b\x32\x85\x01.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse.GetIdentityByNonUniquePublicKeyHashResponseV0.IdentityResponseH\x00\x12\x9d\x01\n\x05proof\x18\x02 \x01(\x0b\x32\x8b\x01.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse.GetIdentityByNonUniquePublicKeyHashResponseV0.IdentityProvedResponseH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x36\n\x10IdentityResponse\x12\x15\n\x08identity\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\x0b\n\t_identity\x1a\xa6\x01\n\x16IdentityProvedResponse\x12P\n&grovedb_identity_public_key_hash_proof\x18\x01 \x01(\x0b\x32 .org.dash.platform.dapi.v0.Proof\x12!\n\x14identity_proof_bytes\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x42\x17\n\x15_identity_proof_bytesB\x08\n\x06resultB\t\n\x07version\"\xfb\x01\n#WaitForStateTransitionResultRequest\x12r\n\x02v0\x18\x01 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.WaitForStateTransitionResultRequest.WaitForStateTransitionResultRequestV0H\x00\x1aU\n%WaitForStateTransitionResultRequestV0\x12\x1d\n\x15state_transition_hash\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x99\x03\n$WaitForStateTransitionResultResponse\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.WaitForStateTransitionResultResponse.WaitForStateTransitionResultResponseV0H\x00\x1a\xef\x01\n&WaitForStateTransitionResultResponseV0\x12I\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x38.org.dash.platform.dapi.v0.StateTransitionBroadcastErrorH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc4\x01\n\x19GetConsensusParamsRequest\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetConsensusParamsRequest.GetConsensusParamsRequestV0H\x00\x1a<\n\x1bGetConsensusParamsRequestV0\x12\x0e\n\x06height\x18\x01 \x01(\x05\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x9c\x04\n\x1aGetConsensusParamsResponse\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetConsensusParamsResponse.GetConsensusParamsResponseV0H\x00\x1aP\n\x14\x43onsensusParamsBlock\x12\x11\n\tmax_bytes\x18\x01 \x01(\t\x12\x0f\n\x07max_gas\x18\x02 \x01(\t\x12\x14\n\x0ctime_iota_ms\x18\x03 \x01(\t\x1a\x62\n\x17\x43onsensusParamsEvidence\x12\x1a\n\x12max_age_num_blocks\x18\x01 \x01(\t\x12\x18\n\x10max_age_duration\x18\x02 \x01(\t\x12\x11\n\tmax_bytes\x18\x03 \x01(\t\x1a\xda\x01\n\x1cGetConsensusParamsResponseV0\x12Y\n\x05\x62lock\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetConsensusParamsResponse.ConsensusParamsBlock\x12_\n\x08\x65vidence\x18\x02 \x01(\x0b\x32M.org.dash.platform.dapi.v0.GetConsensusParamsResponse.ConsensusParamsEvidenceB\t\n\x07version\"\xe4\x01\n%GetProtocolVersionUpgradeStateRequest\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateRequest.GetProtocolVersionUpgradeStateRequestV0H\x00\x1a\x38\n\'GetProtocolVersionUpgradeStateRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xb5\x05\n&GetProtocolVersionUpgradeStateResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse.GetProtocolVersionUpgradeStateResponseV0H\x00\x1a\x85\x04\n(GetProtocolVersionUpgradeStateResponseV0\x12\x87\x01\n\x08versions\x18\x01 \x01(\x0b\x32s.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse.GetProtocolVersionUpgradeStateResponseV0.VersionsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x96\x01\n\x08Versions\x12\x89\x01\n\x08versions\x18\x01 \x03(\x0b\x32w.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse.GetProtocolVersionUpgradeStateResponseV0.VersionEntry\x1a:\n\x0cVersionEntry\x12\x16\n\x0eversion_number\x18\x01 \x01(\r\x12\x12\n\nvote_count\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xa3\x02\n*GetProtocolVersionUpgradeVoteStatusRequest\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusRequest.GetProtocolVersionUpgradeVoteStatusRequestV0H\x00\x1ag\n,GetProtocolVersionUpgradeVoteStatusRequestV0\x12\x19\n\x11start_pro_tx_hash\x18\x01 \x01(\x0c\x12\r\n\x05\x63ount\x18\x02 \x01(\r\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xef\x05\n+GetProtocolVersionUpgradeVoteStatusResponse\x12\x82\x01\n\x02v0\x18\x01 \x01(\x0b\x32t.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse.GetProtocolVersionUpgradeVoteStatusResponseV0H\x00\x1a\xaf\x04\n-GetProtocolVersionUpgradeVoteStatusResponseV0\x12\x98\x01\n\x08versions\x18\x01 \x01(\x0b\x32\x83\x01.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse.GetProtocolVersionUpgradeVoteStatusResponseV0.VersionSignalsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xaf\x01\n\x0eVersionSignals\x12\x9c\x01\n\x0fversion_signals\x18\x01 \x03(\x0b\x32\x82\x01.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse.GetProtocolVersionUpgradeVoteStatusResponseV0.VersionSignal\x1a\x35\n\rVersionSignal\x12\x13\n\x0bpro_tx_hash\x18\x01 \x01(\x0c\x12\x0f\n\x07version\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xf5\x01\n\x14GetEpochsInfoRequest\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetEpochsInfoRequest.GetEpochsInfoRequestV0H\x00\x1a|\n\x16GetEpochsInfoRequestV0\x12\x31\n\x0bstart_epoch\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\r\n\x05\x63ount\x18\x02 \x01(\r\x12\x11\n\tascending\x18\x03 \x01(\x08\x12\r\n\x05prove\x18\x04 \x01(\x08\x42\t\n\x07version\"\x99\x05\n\x15GetEpochsInfoResponse\x12V\n\x02v0\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetEpochsInfoResponse.GetEpochsInfoResponseV0H\x00\x1a\x9c\x04\n\x17GetEpochsInfoResponseV0\x12\x65\n\x06\x65pochs\x18\x01 \x01(\x0b\x32S.org.dash.platform.dapi.v0.GetEpochsInfoResponse.GetEpochsInfoResponseV0.EpochInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1au\n\nEpochInfos\x12g\n\x0b\x65poch_infos\x18\x01 \x03(\x0b\x32R.org.dash.platform.dapi.v0.GetEpochsInfoResponse.GetEpochsInfoResponseV0.EpochInfo\x1a\xa6\x01\n\tEpochInfo\x12\x0e\n\x06number\x18\x01 \x01(\r\x12\x1e\n\x12\x66irst_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x1f\n\x17\x66irst_core_block_height\x18\x03 \x01(\r\x12\x16\n\nstart_time\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x16\n\x0e\x66\x65\x65_multiplier\x18\x05 \x01(\x01\x12\x18\n\x10protocol_version\x18\x06 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xbf\x02\n\x1dGetFinalizedEpochInfosRequest\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetFinalizedEpochInfosRequest.GetFinalizedEpochInfosRequestV0H\x00\x1a\xaa\x01\n\x1fGetFinalizedEpochInfosRequestV0\x12\x19\n\x11start_epoch_index\x18\x01 \x01(\r\x12\"\n\x1astart_epoch_index_included\x18\x02 \x01(\x08\x12\x17\n\x0f\x65nd_epoch_index\x18\x03 \x01(\r\x12 \n\x18\x65nd_epoch_index_included\x18\x04 \x01(\x08\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\t\n\x07version\"\xbd\t\n\x1eGetFinalizedEpochInfosResponse\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0H\x00\x1a\xa5\x08\n GetFinalizedEpochInfosResponseV0\x12\x80\x01\n\x06\x65pochs\x18\x01 \x01(\x0b\x32n.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0.FinalizedEpochInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xa4\x01\n\x13\x46inalizedEpochInfos\x12\x8c\x01\n\x15\x66inalized_epoch_infos\x18\x01 \x03(\x0b\x32m.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0.FinalizedEpochInfo\x1a\x9f\x04\n\x12\x46inalizedEpochInfo\x12\x0e\n\x06number\x18\x01 \x01(\r\x12\x1e\n\x12\x66irst_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x1f\n\x17\x66irst_core_block_height\x18\x03 \x01(\r\x12\x1c\n\x10\x66irst_block_time\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x16\n\x0e\x66\x65\x65_multiplier\x18\x05 \x01(\x01\x12\x18\n\x10protocol_version\x18\x06 \x01(\r\x12!\n\x15total_blocks_in_epoch\x18\x07 \x01(\x04\x42\x02\x30\x01\x12*\n\"next_epoch_start_core_block_height\x18\x08 \x01(\r\x12!\n\x15total_processing_fees\x18\t \x01(\x04\x42\x02\x30\x01\x12*\n\x1etotal_distributed_storage_fees\x18\n \x01(\x04\x42\x02\x30\x01\x12&\n\x1atotal_created_storage_fees\x18\x0b \x01(\x04\x42\x02\x30\x01\x12\x1e\n\x12\x63ore_block_rewards\x18\x0c \x01(\x04\x42\x02\x30\x01\x12\x81\x01\n\x0f\x62lock_proposers\x18\r \x03(\x0b\x32h.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0.BlockProposer\x1a\x39\n\rBlockProposer\x12\x13\n\x0bproposer_id\x18\x01 \x01(\x0c\x12\x13\n\x0b\x62lock_count\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xde\x04\n\x1cGetContestedResourcesRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetContestedResourcesRequest.GetContestedResourcesRequestV0H\x00\x1a\xcc\x03\n\x1eGetContestedResourcesRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\x12\n\nindex_name\x18\x03 \x01(\t\x12\x1a\n\x12start_index_values\x18\x04 \x03(\x0c\x12\x18\n\x10\x65nd_index_values\x18\x05 \x03(\x0c\x12\x89\x01\n\x13start_at_value_info\x18\x06 \x01(\x0b\x32g.org.dash.platform.dapi.v0.GetContestedResourcesRequest.GetContestedResourcesRequestV0.StartAtValueInfoH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x07 \x01(\rH\x01\x88\x01\x01\x12\x17\n\x0forder_ascending\x18\x08 \x01(\x08\x12\r\n\x05prove\x18\t \x01(\x08\x1a\x45\n\x10StartAtValueInfo\x12\x13\n\x0bstart_value\x18\x01 \x01(\x0c\x12\x1c\n\x14start_value_included\x18\x02 \x01(\x08\x42\x16\n\x14_start_at_value_infoB\x08\n\x06_countB\t\n\x07version\"\x88\x04\n\x1dGetContestedResourcesResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetContestedResourcesResponse.GetContestedResourcesResponseV0H\x00\x1a\xf3\x02\n\x1fGetContestedResourcesResponseV0\x12\x95\x01\n\x19\x63ontested_resource_values\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetContestedResourcesResponse.GetContestedResourcesResponseV0.ContestedResourceValuesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a<\n\x17\x43ontestedResourceValues\x12!\n\x19\x63ontested_resource_values\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xd2\x05\n\x1cGetVotePollsByEndDateRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest.GetVotePollsByEndDateRequestV0H\x00\x1a\xc0\x04\n\x1eGetVotePollsByEndDateRequestV0\x12\x84\x01\n\x0fstart_time_info\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest.GetVotePollsByEndDateRequestV0.StartAtTimeInfoH\x00\x88\x01\x01\x12\x80\x01\n\rend_time_info\x18\x02 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest.GetVotePollsByEndDateRequestV0.EndAtTimeInfoH\x01\x88\x01\x01\x12\x12\n\x05limit\x18\x03 \x01(\rH\x02\x88\x01\x01\x12\x13\n\x06offset\x18\x04 \x01(\rH\x03\x88\x01\x01\x12\x11\n\tascending\x18\x05 \x01(\x08\x12\r\n\x05prove\x18\x06 \x01(\x08\x1aI\n\x0fStartAtTimeInfo\x12\x19\n\rstart_time_ms\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1b\n\x13start_time_included\x18\x02 \x01(\x08\x1a\x43\n\rEndAtTimeInfo\x12\x17\n\x0b\x65nd_time_ms\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x19\n\x11\x65nd_time_included\x18\x02 \x01(\x08\x42\x12\n\x10_start_time_infoB\x10\n\x0e_end_time_infoB\x08\n\x06_limitB\t\n\x07_offsetB\t\n\x07version\"\x83\x06\n\x1dGetVotePollsByEndDateResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse.GetVotePollsByEndDateResponseV0H\x00\x1a\xee\x04\n\x1fGetVotePollsByEndDateResponseV0\x12\x9c\x01\n\x18vote_polls_by_timestamps\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse.GetVotePollsByEndDateResponseV0.SerializedVotePollsByTimestampsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aV\n\x1eSerializedVotePollsByTimestamp\x12\x15\n\ttimestamp\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1d\n\x15serialized_vote_polls\x18\x02 \x03(\x0c\x1a\xd7\x01\n\x1fSerializedVotePollsByTimestamps\x12\x99\x01\n\x18vote_polls_by_timestamps\x18\x01 \x03(\x0b\x32w.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse.GetVotePollsByEndDateResponseV0.SerializedVotePollsByTimestamp\x12\x18\n\x10\x66inished_results\x18\x02 \x01(\x08\x42\x08\n\x06resultB\t\n\x07version\"\xff\x06\n$GetContestedResourceVoteStateRequest\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest.GetContestedResourceVoteStateRequestV0H\x00\x1a\xd5\x05\n&GetContestedResourceVoteStateRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\x12\n\nindex_name\x18\x03 \x01(\t\x12\x14\n\x0cindex_values\x18\x04 \x03(\x0c\x12\x86\x01\n\x0bresult_type\x18\x05 \x01(\x0e\x32q.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest.GetContestedResourceVoteStateRequestV0.ResultType\x12\x36\n.allow_include_locked_and_abstaining_vote_tally\x18\x06 \x01(\x08\x12\xa3\x01\n\x18start_at_identifier_info\x18\x07 \x01(\x0b\x32|.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest.GetContestedResourceVoteStateRequestV0.StartAtIdentifierInfoH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x08 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\t \x01(\x08\x1aT\n\x15StartAtIdentifierInfo\x12\x18\n\x10start_identifier\x18\x01 \x01(\x0c\x12!\n\x19start_identifier_included\x18\x02 \x01(\x08\"I\n\nResultType\x12\r\n\tDOCUMENTS\x10\x00\x12\x0e\n\nVOTE_TALLY\x10\x01\x12\x1c\n\x18\x44OCUMENTS_AND_VOTE_TALLY\x10\x02\x42\x1b\n\x19_start_at_identifier_infoB\x08\n\x06_countB\t\n\x07version\"\x94\x0c\n%GetContestedResourceVoteStateResponse\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0H\x00\x1a\xe7\n\n\'GetContestedResourceVoteStateResponseV0\x12\xae\x01\n\x1d\x63ontested_resource_contenders\x18\x01 \x01(\x0b\x32\x84\x01.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.ContestedResourceContendersH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xda\x03\n\x10\x46inishedVoteInfo\x12\xad\x01\n\x15\x66inished_vote_outcome\x18\x01 \x01(\x0e\x32\x8d\x01.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.FinishedVoteInfo.FinishedVoteOutcome\x12\x1f\n\x12won_by_identity_id\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12$\n\x18\x66inished_at_block_height\x18\x03 \x01(\x04\x42\x02\x30\x01\x12%\n\x1d\x66inished_at_core_block_height\x18\x04 \x01(\r\x12%\n\x19\x66inished_at_block_time_ms\x18\x05 \x01(\x04\x42\x02\x30\x01\x12\x19\n\x11\x66inished_at_epoch\x18\x06 \x01(\r\"O\n\x13\x46inishedVoteOutcome\x12\x14\n\x10TOWARDS_IDENTITY\x10\x00\x12\n\n\x06LOCKED\x10\x01\x12\x16\n\x12NO_PREVIOUS_WINNER\x10\x02\x42\x15\n\x13_won_by_identity_id\x1a\xc4\x03\n\x1b\x43ontestedResourceContenders\x12\x86\x01\n\ncontenders\x18\x01 \x03(\x0b\x32r.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.Contender\x12\x1f\n\x12\x61\x62stain_vote_tally\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x1c\n\x0flock_vote_tally\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x9a\x01\n\x12\x66inished_vote_info\x18\x04 \x01(\x0b\x32y.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.FinishedVoteInfoH\x02\x88\x01\x01\x42\x15\n\x13_abstain_vote_tallyB\x12\n\x10_lock_vote_tallyB\x15\n\x13_finished_vote_info\x1ak\n\tContender\x12\x12\n\nidentifier\x18\x01 \x01(\x0c\x12\x17\n\nvote_count\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x15\n\x08\x64ocument\x18\x03 \x01(\x0cH\x01\x88\x01\x01\x42\r\n\x0b_vote_countB\x0b\n\t_documentB\x08\n\x06resultB\t\n\x07version\"\xd5\x05\n,GetContestedResourceVotersForIdentityRequest\x12\x84\x01\n\x02v0\x18\x01 \x01(\x0b\x32v.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityRequest.GetContestedResourceVotersForIdentityRequestV0H\x00\x1a\x92\x04\n.GetContestedResourceVotersForIdentityRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\x12\n\nindex_name\x18\x03 \x01(\t\x12\x14\n\x0cindex_values\x18\x04 \x03(\x0c\x12\x15\n\rcontestant_id\x18\x05 \x01(\x0c\x12\xb4\x01\n\x18start_at_identifier_info\x18\x06 \x01(\x0b\x32\x8c\x01.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityRequest.GetContestedResourceVotersForIdentityRequestV0.StartAtIdentifierInfoH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x07 \x01(\rH\x01\x88\x01\x01\x12\x17\n\x0forder_ascending\x18\x08 \x01(\x08\x12\r\n\x05prove\x18\t \x01(\x08\x1aT\n\x15StartAtIdentifierInfo\x12\x18\n\x10start_identifier\x18\x01 \x01(\x0c\x12!\n\x19start_identifier_included\x18\x02 \x01(\x08\x42\x1b\n\x19_start_at_identifier_infoB\x08\n\x06_countB\t\n\x07version\"\xf1\x04\n-GetContestedResourceVotersForIdentityResponse\x12\x86\x01\n\x02v0\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityResponse.GetContestedResourceVotersForIdentityResponseV0H\x00\x1a\xab\x03\n/GetContestedResourceVotersForIdentityResponseV0\x12\xb6\x01\n\x19\x63ontested_resource_voters\x18\x01 \x01(\x0b\x32\x90\x01.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityResponse.GetContestedResourceVotersForIdentityResponseV0.ContestedResourceVotersH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x43\n\x17\x43ontestedResourceVoters\x12\x0e\n\x06voters\x18\x01 \x03(\x0c\x12\x18\n\x10\x66inished_results\x18\x02 \x01(\x08\x42\x08\n\x06resultB\t\n\x07version\"\xad\x05\n(GetContestedResourceIdentityVotesRequest\x12|\n\x02v0\x18\x01 \x01(\x0b\x32n.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesRequest.GetContestedResourceIdentityVotesRequestV0H\x00\x1a\xf7\x03\n*GetContestedResourceIdentityVotesRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12+\n\x05limit\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12,\n\x06offset\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\x17\n\x0forder_ascending\x18\x04 \x01(\x08\x12\xae\x01\n\x1astart_at_vote_poll_id_info\x18\x05 \x01(\x0b\x32\x84\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesRequest.GetContestedResourceIdentityVotesRequestV0.StartAtVotePollIdInfoH\x00\x88\x01\x01\x12\r\n\x05prove\x18\x06 \x01(\x08\x1a\x61\n\x15StartAtVotePollIdInfo\x12 \n\x18start_at_poll_identifier\x18\x01 \x01(\x0c\x12&\n\x1estart_poll_identifier_included\x18\x02 \x01(\x08\x42\x1d\n\x1b_start_at_vote_poll_id_infoB\t\n\x07version\"\xc8\n\n)GetContestedResourceIdentityVotesResponse\x12~\n\x02v0\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0H\x00\x1a\x8f\t\n+GetContestedResourceIdentityVotesResponseV0\x12\xa1\x01\n\x05votes\x18\x01 \x01(\x0b\x32\x8f\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ContestedResourceIdentityVotesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xf7\x01\n\x1e\x43ontestedResourceIdentityVotes\x12\xba\x01\n!contested_resource_identity_votes\x18\x01 \x03(\x0b\x32\x8e\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ContestedResourceIdentityVote\x12\x18\n\x10\x66inished_results\x18\x02 \x01(\x08\x1a\xad\x02\n\x12ResourceVoteChoice\x12\xad\x01\n\x10vote_choice_type\x18\x01 \x01(\x0e\x32\x92\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ResourceVoteChoice.VoteChoiceType\x12\x18\n\x0bidentity_id\x18\x02 \x01(\x0cH\x00\x88\x01\x01\"=\n\x0eVoteChoiceType\x12\x14\n\x10TOWARDS_IDENTITY\x10\x00\x12\x0b\n\x07\x41\x42STAIN\x10\x01\x12\x08\n\x04LOCK\x10\x02\x42\x0e\n\x0c_identity_id\x1a\x95\x02\n\x1d\x43ontestedResourceIdentityVote\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\'\n\x1fserialized_index_storage_values\x18\x03 \x03(\x0c\x12\x99\x01\n\x0bvote_choice\x18\x04 \x01(\x0b\x32\x83\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ResourceVoteChoiceB\x08\n\x06resultB\t\n\x07version\"\xf0\x01\n%GetPrefundedSpecializedBalanceRequest\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceRequest.GetPrefundedSpecializedBalanceRequestV0H\x00\x1a\x44\n\'GetPrefundedSpecializedBalanceRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xed\x02\n&GetPrefundedSpecializedBalanceResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceResponse.GetPrefundedSpecializedBalanceResponseV0H\x00\x1a\xbd\x01\n(GetPrefundedSpecializedBalanceResponseV0\x12\x15\n\x07\x62\x61lance\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xd0\x01\n GetTotalCreditsInPlatformRequest\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformRequest.GetTotalCreditsInPlatformRequestV0H\x00\x1a\x33\n\"GetTotalCreditsInPlatformRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xd9\x02\n!GetTotalCreditsInPlatformResponse\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformResponse.GetTotalCreditsInPlatformResponseV0H\x00\x1a\xb8\x01\n#GetTotalCreditsInPlatformResponseV0\x12\x15\n\x07\x63redits\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc4\x01\n\x16GetPathElementsRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetPathElementsRequest.GetPathElementsRequestV0H\x00\x1a\x45\n\x18GetPathElementsRequestV0\x12\x0c\n\x04path\x18\x01 \x03(\x0c\x12\x0c\n\x04keys\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xa3\x03\n\x17GetPathElementsResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetPathElementsResponse.GetPathElementsResponseV0H\x00\x1a\xa0\x02\n\x19GetPathElementsResponseV0\x12i\n\x08\x65lements\x18\x01 \x01(\x0b\x32U.org.dash.platform.dapi.v0.GetPathElementsResponse.GetPathElementsResponseV0.ElementsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1c\n\x08\x45lements\x12\x10\n\x08\x65lements\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\x81\x01\n\x10GetStatusRequest\x12L\n\x02v0\x18\x01 \x01(\x0b\x32>.org.dash.platform.dapi.v0.GetStatusRequest.GetStatusRequestV0H\x00\x1a\x14\n\x12GetStatusRequestV0B\t\n\x07version\"\xe4\x10\n\x11GetStatusResponse\x12N\n\x02v0\x18\x01 \x01(\x0b\x32@.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0H\x00\x1a\xf3\x0f\n\x13GetStatusResponseV0\x12Y\n\x07version\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version\x12S\n\x04node\x18\x02 \x01(\x0b\x32\x45.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Node\x12U\n\x05\x63hain\x18\x03 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Chain\x12Y\n\x07network\x18\x04 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Network\x12^\n\nstate_sync\x18\x05 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.StateSync\x12S\n\x04time\x18\x06 \x01(\x0b\x32\x45.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Time\x1a\x82\x05\n\x07Version\x12\x63\n\x08software\x18\x01 \x01(\x0b\x32Q.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Software\x12\x63\n\x08protocol\x18\x02 \x01(\x0b\x32Q.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Protocol\x1a^\n\x08Software\x12\x0c\n\x04\x64\x61pi\x18\x01 \x01(\t\x12\x12\n\x05\x64rive\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x17\n\ntenderdash\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_driveB\r\n\x0b_tenderdash\x1a\xcc\x02\n\x08Protocol\x12p\n\ntenderdash\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Protocol.Tenderdash\x12\x66\n\x05\x64rive\x18\x02 \x01(\x0b\x32W.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Protocol.Drive\x1a(\n\nTenderdash\x12\x0b\n\x03p2p\x18\x01 \x01(\r\x12\r\n\x05\x62lock\x18\x02 \x01(\r\x1a<\n\x05\x44rive\x12\x0e\n\x06latest\x18\x03 \x01(\r\x12\x0f\n\x07\x63urrent\x18\x04 \x01(\r\x12\x12\n\nnext_epoch\x18\x05 \x01(\r\x1a\x7f\n\x04Time\x12\x11\n\x05local\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x16\n\x05\x62lock\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x88\x01\x01\x12\x18\n\x07genesis\x18\x03 \x01(\x04\x42\x02\x30\x01H\x01\x88\x01\x01\x12\x12\n\x05\x65poch\x18\x04 \x01(\rH\x02\x88\x01\x01\x42\x08\n\x06_blockB\n\n\x08_genesisB\x08\n\x06_epoch\x1a<\n\x04Node\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x18\n\x0bpro_tx_hash\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x42\x0e\n\x0c_pro_tx_hash\x1a\xb3\x02\n\x05\x43hain\x12\x13\n\x0b\x63\x61tching_up\x18\x01 \x01(\x08\x12\x19\n\x11latest_block_hash\x18\x02 \x01(\x0c\x12\x17\n\x0flatest_app_hash\x18\x03 \x01(\x0c\x12\x1f\n\x13latest_block_height\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x1b\n\x13\x65\x61rliest_block_hash\x18\x05 \x01(\x0c\x12\x19\n\x11\x65\x61rliest_app_hash\x18\x06 \x01(\x0c\x12!\n\x15\x65\x61rliest_block_height\x18\x07 \x01(\x04\x42\x02\x30\x01\x12!\n\x15max_peer_block_height\x18\t \x01(\x04\x42\x02\x30\x01\x12%\n\x18\x63ore_chain_locked_height\x18\n \x01(\rH\x00\x88\x01\x01\x42\x1b\n\x19_core_chain_locked_height\x1a\x43\n\x07Network\x12\x10\n\x08\x63hain_id\x18\x01 \x01(\t\x12\x13\n\x0bpeers_count\x18\x02 \x01(\r\x12\x11\n\tlistening\x18\x03 \x01(\x08\x1a\x85\x02\n\tStateSync\x12\x1d\n\x11total_synced_time\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1a\n\x0eremaining_time\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x17\n\x0ftotal_snapshots\x18\x03 \x01(\r\x12\"\n\x16\x63hunk_process_avg_time\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x1b\n\x0fsnapshot_height\x18\x05 \x01(\x04\x42\x02\x30\x01\x12!\n\x15snapshot_chunks_count\x18\x06 \x01(\x04\x42\x02\x30\x01\x12\x1d\n\x11\x62\x61\x63kfilled_blocks\x18\x07 \x01(\x04\x42\x02\x30\x01\x12!\n\x15\x62\x61\x63kfill_blocks_total\x18\x08 \x01(\x04\x42\x02\x30\x01\x42\t\n\x07version\"\xb1\x01\n\x1cGetCurrentQuorumsInfoRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoRequest.GetCurrentQuorumsInfoRequestV0H\x00\x1a \n\x1eGetCurrentQuorumsInfoRequestV0B\t\n\x07version\"\xa1\x05\n\x1dGetCurrentQuorumsInfoResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse.GetCurrentQuorumsInfoResponseV0H\x00\x1a\x46\n\x0bValidatorV0\x12\x13\n\x0bpro_tx_hash\x18\x01 \x01(\x0c\x12\x0f\n\x07node_ip\x18\x02 \x01(\t\x12\x11\n\tis_banned\x18\x03 \x01(\x08\x1a\xaf\x01\n\x0eValidatorSetV0\x12\x13\n\x0bquorum_hash\x18\x01 \x01(\x0c\x12\x13\n\x0b\x63ore_height\x18\x02 \x01(\r\x12U\n\x07members\x18\x03 \x03(\x0b\x32\x44.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse.ValidatorV0\x12\x1c\n\x14threshold_public_key\x18\x04 \x01(\x0c\x1a\x92\x02\n\x1fGetCurrentQuorumsInfoResponseV0\x12\x15\n\rquorum_hashes\x18\x01 \x03(\x0c\x12\x1b\n\x13\x63urrent_quorum_hash\x18\x02 \x01(\x0c\x12_\n\x0evalidator_sets\x18\x03 \x03(\x0b\x32G.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse.ValidatorSetV0\x12\x1b\n\x13last_block_proposer\x18\x04 \x01(\x0c\x12=\n\x08metadata\x18\x05 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\t\n\x07version\"\xf4\x01\n\x1fGetIdentityTokenBalancesRequest\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetIdentityTokenBalancesRequest.GetIdentityTokenBalancesRequestV0H\x00\x1aZ\n!GetIdentityTokenBalancesRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x11\n\ttoken_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xad\x05\n GetIdentityTokenBalancesResponse\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse.GetIdentityTokenBalancesResponseV0H\x00\x1a\x8f\x04\n\"GetIdentityTokenBalancesResponseV0\x12\x86\x01\n\x0etoken_balances\x18\x01 \x01(\x0b\x32l.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse.GetIdentityTokenBalancesResponseV0.TokenBalancesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aG\n\x11TokenBalanceEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x14\n\x07\x62\x61lance\x18\x02 \x01(\x04H\x00\x88\x01\x01\x42\n\n\x08_balance\x1a\x9a\x01\n\rTokenBalances\x12\x88\x01\n\x0etoken_balances\x18\x01 \x03(\x0b\x32p.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse.GetIdentityTokenBalancesResponseV0.TokenBalanceEntryB\x08\n\x06resultB\t\n\x07version\"\xfc\x01\n!GetIdentitiesTokenBalancesRequest\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesRequest.GetIdentitiesTokenBalancesRequestV0H\x00\x1a\\\n#GetIdentitiesTokenBalancesRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x14\n\x0cidentity_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xf2\x05\n\"GetIdentitiesTokenBalancesResponse\x12p\n\x02v0\x18\x01 \x01(\x0b\x32\x62.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse.GetIdentitiesTokenBalancesResponseV0H\x00\x1a\xce\x04\n$GetIdentitiesTokenBalancesResponseV0\x12\x9b\x01\n\x17identity_token_balances\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse.GetIdentitiesTokenBalancesResponseV0.IdentityTokenBalancesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aR\n\x19IdentityTokenBalanceEntry\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x14\n\x07\x62\x61lance\x18\x02 \x01(\x04H\x00\x88\x01\x01\x42\n\n\x08_balance\x1a\xb7\x01\n\x15IdentityTokenBalances\x12\x9d\x01\n\x17identity_token_balances\x18\x01 \x03(\x0b\x32|.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse.GetIdentitiesTokenBalancesResponseV0.IdentityTokenBalanceEntryB\x08\n\x06resultB\t\n\x07version\"\xe8\x01\n\x1cGetIdentityTokenInfosRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetIdentityTokenInfosRequest.GetIdentityTokenInfosRequestV0H\x00\x1aW\n\x1eGetIdentityTokenInfosRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x11\n\ttoken_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\x98\x06\n\x1dGetIdentityTokenInfosResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0H\x00\x1a\x83\x05\n\x1fGetIdentityTokenInfosResponseV0\x12z\n\x0btoken_infos\x18\x01 \x01(\x0b\x32\x63.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a(\n\x16TokenIdentityInfoEntry\x12\x0e\n\x06\x66rozen\x18\x01 \x01(\x08\x1a\xb0\x01\n\x0eTokenInfoEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x82\x01\n\x04info\x18\x02 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenIdentityInfoEntryH\x00\x88\x01\x01\x42\x07\n\x05_info\x1a\x8a\x01\n\nTokenInfos\x12|\n\x0btoken_infos\x18\x01 \x03(\x0b\x32g.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenInfoEntryB\x08\n\x06resultB\t\n\x07version\"\xf0\x01\n\x1eGetIdentitiesTokenInfosRequest\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosRequest.GetIdentitiesTokenInfosRequestV0H\x00\x1aY\n GetIdentitiesTokenInfosRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x14\n\x0cidentity_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xca\x06\n\x1fGetIdentitiesTokenInfosResponse\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0H\x00\x1a\xaf\x05\n!GetIdentitiesTokenInfosResponseV0\x12\x8f\x01\n\x14identity_token_infos\x18\x01 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0.IdentityTokenInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a(\n\x16TokenIdentityInfoEntry\x12\x0e\n\x06\x66rozen\x18\x01 \x01(\x08\x1a\xb7\x01\n\x0eTokenInfoEntry\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x86\x01\n\x04info\x18\x02 \x01(\x0b\x32s.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0.TokenIdentityInfoEntryH\x00\x88\x01\x01\x42\x07\n\x05_info\x1a\x97\x01\n\x12IdentityTokenInfos\x12\x80\x01\n\x0btoken_infos\x18\x01 \x03(\x0b\x32k.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0.TokenInfoEntryB\x08\n\x06resultB\t\n\x07version\"\xbf\x01\n\x17GetTokenStatusesRequest\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetTokenStatusesRequest.GetTokenStatusesRequestV0H\x00\x1a=\n\x19GetTokenStatusesRequestV0\x12\x11\n\ttoken_ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xe7\x04\n\x18GetTokenStatusesResponse\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetTokenStatusesResponse.GetTokenStatusesResponseV0H\x00\x1a\xe1\x03\n\x1aGetTokenStatusesResponseV0\x12v\n\x0etoken_statuses\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetTokenStatusesResponse.GetTokenStatusesResponseV0.TokenStatusesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x44\n\x10TokenStatusEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x13\n\x06paused\x18\x02 \x01(\x08H\x00\x88\x01\x01\x42\t\n\x07_paused\x1a\x88\x01\n\rTokenStatuses\x12w\n\x0etoken_statuses\x18\x01 \x03(\x0b\x32_.org.dash.platform.dapi.v0.GetTokenStatusesResponse.GetTokenStatusesResponseV0.TokenStatusEntryB\x08\n\x06resultB\t\n\x07version\"\xef\x01\n#GetTokenDirectPurchasePricesRequest\x12r\n\x02v0\x18\x01 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesRequest.GetTokenDirectPurchasePricesRequestV0H\x00\x1aI\n%GetTokenDirectPurchasePricesRequestV0\x12\x11\n\ttoken_ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x8b\t\n$GetTokenDirectPurchasePricesResponse\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0H\x00\x1a\xe1\x07\n&GetTokenDirectPurchasePricesResponseV0\x12\xa9\x01\n\x1ctoken_direct_purchase_prices\x18\x01 \x01(\x0b\x32\x80\x01.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.TokenDirectPurchasePricesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x33\n\x10PriceForQuantity\x12\x10\n\x08quantity\x18\x01 \x01(\x04\x12\r\n\x05price\x18\x02 \x01(\x04\x1a\xa7\x01\n\x0fPricingSchedule\x12\x93\x01\n\x12price_for_quantity\x18\x01 \x03(\x0b\x32w.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.PriceForQuantity\x1a\xe4\x01\n\x1dTokenDirectPurchasePriceEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x15\n\x0b\x66ixed_price\x18\x02 \x01(\x04H\x00\x12\x90\x01\n\x0evariable_price\x18\x03 \x01(\x0b\x32v.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.PricingScheduleH\x00\x42\x07\n\x05price\x1a\xc8\x01\n\x19TokenDirectPurchasePrices\x12\xaa\x01\n\x1btoken_direct_purchase_price\x18\x01 \x03(\x0b\x32\x84\x01.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.TokenDirectPurchasePriceEntryB\x08\n\x06resultB\t\n\x07version\"\xce\x01\n\x1bGetTokenContractInfoRequest\x12\x62\n\x02v0\x18\x01 \x01(\x0b\x32T.org.dash.platform.dapi.v0.GetTokenContractInfoRequest.GetTokenContractInfoRequestV0H\x00\x1a@\n\x1dGetTokenContractInfoRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xfb\x03\n\x1cGetTokenContractInfoResponse\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetTokenContractInfoResponse.GetTokenContractInfoResponseV0H\x00\x1a\xe9\x02\n\x1eGetTokenContractInfoResponseV0\x12|\n\x04\x64\x61ta\x18\x01 \x01(\x0b\x32l.org.dash.platform.dapi.v0.GetTokenContractInfoResponse.GetTokenContractInfoResponseV0.TokenContractInfoDataH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aM\n\x15TokenContractInfoData\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17token_contract_position\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xef\x04\n)GetTokenPreProgrammedDistributionsRequest\x12~\n\x02v0\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsRequest.GetTokenPreProgrammedDistributionsRequestV0H\x00\x1a\xb6\x03\n+GetTokenPreProgrammedDistributionsRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x98\x01\n\rstart_at_info\x18\x02 \x01(\x0b\x32|.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsRequest.GetTokenPreProgrammedDistributionsRequestV0.StartAtInfoH\x00\x88\x01\x01\x12\x12\n\x05limit\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\x04 \x01(\x08\x1a\x9a\x01\n\x0bStartAtInfo\x12\x15\n\rstart_time_ms\x18\x01 \x01(\x04\x12\x1c\n\x0fstart_recipient\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12%\n\x18start_recipient_included\x18\x03 \x01(\x08H\x01\x88\x01\x01\x42\x12\n\x10_start_recipientB\x1b\n\x19_start_recipient_includedB\x10\n\x0e_start_at_infoB\x08\n\x06_limitB\t\n\x07version\"\xec\x07\n*GetTokenPreProgrammedDistributionsResponse\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0H\x00\x1a\xaf\x06\n,GetTokenPreProgrammedDistributionsResponseV0\x12\xa5\x01\n\x13token_distributions\x18\x01 \x01(\x0b\x32\x85\x01.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0.TokenDistributionsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a>\n\x16TokenDistributionEntry\x12\x14\n\x0crecipient_id\x18\x01 \x01(\x0c\x12\x0e\n\x06\x61mount\x18\x02 \x01(\x04\x1a\xd4\x01\n\x1bTokenTimedDistributionEntry\x12\x11\n\ttimestamp\x18\x01 \x01(\x04\x12\xa1\x01\n\rdistributions\x18\x02 \x03(\x0b\x32\x89\x01.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0.TokenDistributionEntry\x1a\xc3\x01\n\x12TokenDistributions\x12\xac\x01\n\x13token_distributions\x18\x01 \x03(\x0b\x32\x8e\x01.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0.TokenTimedDistributionEntryB\x08\n\x06resultB\t\n\x07version\"\x82\x04\n-GetTokenPerpetualDistributionLastClaimRequest\x12\x86\x01\n\x02v0\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimRequest.GetTokenPerpetualDistributionLastClaimRequestV0H\x00\x1aI\n\x11\x43ontractTokenInfo\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17token_contract_position\x18\x02 \x01(\r\x1a\xf1\x01\n/GetTokenPerpetualDistributionLastClaimRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12v\n\rcontract_info\x18\x02 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimRequest.ContractTokenInfoH\x00\x88\x01\x01\x12\x13\n\x0bidentity_id\x18\x04 \x01(\x0c\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\x10\n\x0e_contract_infoB\t\n\x07version\"\x93\x05\n.GetTokenPerpetualDistributionLastClaimResponse\x12\x88\x01\n\x02v0\x18\x01 \x01(\x0b\x32z.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimResponse.GetTokenPerpetualDistributionLastClaimResponseV0H\x00\x1a\xca\x03\n0GetTokenPerpetualDistributionLastClaimResponseV0\x12\x9f\x01\n\nlast_claim\x18\x01 \x01(\x0b\x32\x88\x01.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimResponse.GetTokenPerpetualDistributionLastClaimResponseV0.LastClaimInfoH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1ax\n\rLastClaimInfo\x12\x1a\n\x0ctimestamp_ms\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x1a\n\x0c\x62lock_height\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x12\x0f\n\x05\x65poch\x18\x03 \x01(\rH\x00\x12\x13\n\traw_bytes\x18\x04 \x01(\x0cH\x00\x42\t\n\x07paid_atB\x08\n\x06resultB\t\n\x07version\"\xca\x01\n\x1aGetTokenTotalSupplyRequest\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetTokenTotalSupplyRequest.GetTokenTotalSupplyRequestV0H\x00\x1a?\n\x1cGetTokenTotalSupplyRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xaf\x04\n\x1bGetTokenTotalSupplyResponse\x12\x62\n\x02v0\x18\x01 \x01(\x0b\x32T.org.dash.platform.dapi.v0.GetTokenTotalSupplyResponse.GetTokenTotalSupplyResponseV0H\x00\x1a\xa0\x03\n\x1dGetTokenTotalSupplyResponseV0\x12\x88\x01\n\x12token_total_supply\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetTokenTotalSupplyResponse.GetTokenTotalSupplyResponseV0.TokenTotalSupplyEntryH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1ax\n\x15TokenTotalSupplyEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x30\n(total_aggregated_amount_in_user_accounts\x18\x02 \x01(\x04\x12\x1b\n\x13total_system_amount\x18\x03 \x01(\x04\x42\x08\n\x06resultB\t\n\x07version\"\xd2\x01\n\x13GetGroupInfoRequest\x12R\n\x02v0\x18\x01 \x01(\x0b\x32\x44.org.dash.platform.dapi.v0.GetGroupInfoRequest.GetGroupInfoRequestV0H\x00\x1a\\\n\x15GetGroupInfoRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17group_contract_position\x18\x02 \x01(\r\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xd4\x05\n\x14GetGroupInfoResponse\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0H\x00\x1a\xda\x04\n\x16GetGroupInfoResponseV0\x12\x66\n\ngroup_info\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0.GroupInfoH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x04 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x34\n\x10GroupMemberEntry\x12\x11\n\tmember_id\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x02 \x01(\r\x1a\x98\x01\n\x0eGroupInfoEntry\x12h\n\x07members\x18\x01 \x03(\x0b\x32W.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0.GroupMemberEntry\x12\x1c\n\x14group_required_power\x18\x02 \x01(\r\x1a\x8a\x01\n\tGroupInfo\x12n\n\ngroup_info\x18\x01 \x01(\x0b\x32U.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0.GroupInfoEntryH\x00\x88\x01\x01\x42\r\n\x0b_group_infoB\x08\n\x06resultB\t\n\x07version\"\xed\x03\n\x14GetGroupInfosRequest\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetGroupInfosRequest.GetGroupInfosRequestV0H\x00\x1au\n\x1cStartAtGroupContractPosition\x12%\n\x1dstart_group_contract_position\x18\x01 \x01(\r\x12.\n&start_group_contract_position_included\x18\x02 \x01(\x08\x1a\xfc\x01\n\x16GetGroupInfosRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12{\n start_at_group_contract_position\x18\x02 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetGroupInfosRequest.StartAtGroupContractPositionH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\x04 \x01(\x08\x42#\n!_start_at_group_contract_positionB\x08\n\x06_countB\t\n\x07version\"\xff\x05\n\x15GetGroupInfosResponse\x12V\n\x02v0\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0H\x00\x1a\x82\x05\n\x17GetGroupInfosResponseV0\x12j\n\x0bgroup_infos\x18\x01 \x01(\x0b\x32S.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0.GroupInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x04 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x34\n\x10GroupMemberEntry\x12\x11\n\tmember_id\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x02 \x01(\r\x1a\xc3\x01\n\x16GroupPositionInfoEntry\x12\x1f\n\x17group_contract_position\x18\x01 \x01(\r\x12j\n\x07members\x18\x02 \x03(\x0b\x32Y.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0.GroupMemberEntry\x12\x1c\n\x14group_required_power\x18\x03 \x01(\r\x1a\x82\x01\n\nGroupInfos\x12t\n\x0bgroup_infos\x18\x01 \x03(\x0b\x32_.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0.GroupPositionInfoEntryB\x08\n\x06resultB\t\n\x07version\"\xbe\x04\n\x16GetGroupActionsRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetGroupActionsRequest.GetGroupActionsRequestV0H\x00\x1aL\n\x0fStartAtActionId\x12\x17\n\x0fstart_action_id\x18\x01 \x01(\x0c\x12 \n\x18start_action_id_included\x18\x02 \x01(\x08\x1a\xc8\x02\n\x18GetGroupActionsRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17group_contract_position\x18\x02 \x01(\r\x12N\n\x06status\x18\x03 \x01(\x0e\x32>.org.dash.platform.dapi.v0.GetGroupActionsRequest.ActionStatus\x12\x62\n\x12start_at_action_id\x18\x04 \x01(\x0b\x32\x41.org.dash.platform.dapi.v0.GetGroupActionsRequest.StartAtActionIdH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x05 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\x06 \x01(\x08\x42\x15\n\x13_start_at_action_idB\x08\n\x06_count\"&\n\x0c\x41\x63tionStatus\x12\n\n\x06\x41\x43TIVE\x10\x00\x12\n\n\x06\x43LOSED\x10\x01\x42\t\n\x07version\"\xd6\x1e\n\x17GetGroupActionsResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0H\x00\x1a\xd3\x1d\n\x19GetGroupActionsResponseV0\x12r\n\rgroup_actions\x18\x01 \x01(\x0b\x32Y.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.GroupActionsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a[\n\tMintEvent\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x04\x12\x14\n\x0crecipient_id\x18\x02 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a[\n\tBurnEvent\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x04\x12\x14\n\x0c\x62urn_from_id\x18\x02 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1aJ\n\x0b\x46reezeEvent\x12\x11\n\tfrozen_id\x18\x01 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1aL\n\rUnfreezeEvent\x12\x11\n\tfrozen_id\x18\x01 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a\x66\n\x17\x44\x65stroyFrozenFundsEvent\x12\x11\n\tfrozen_id\x18\x01 \x01(\x0c\x12\x0e\n\x06\x61mount\x18\x02 \x01(\x04\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a\x64\n\x13SharedEncryptedNote\x12\x18\n\x10sender_key_index\x18\x01 \x01(\r\x12\x1b\n\x13recipient_key_index\x18\x02 \x01(\r\x12\x16\n\x0e\x65ncrypted_data\x18\x03 \x01(\x0c\x1a{\n\x15PersonalEncryptedNote\x12!\n\x19root_encryption_key_index\x18\x01 \x01(\r\x12\'\n\x1f\x64\x65rivation_encryption_key_index\x18\x02 \x01(\r\x12\x16\n\x0e\x65ncrypted_data\x18\x03 \x01(\x0c\x1a\xe9\x01\n\x14\x45mergencyActionEvent\x12\x81\x01\n\x0b\x61\x63tion_type\x18\x01 \x01(\x0e\x32l.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.EmergencyActionEvent.ActionType\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\"#\n\nActionType\x12\t\n\x05PAUSE\x10\x00\x12\n\n\x06RESUME\x10\x01\x42\x0e\n\x0c_public_note\x1a\x64\n\x16TokenConfigUpdateEvent\x12 \n\x18token_config_update_item\x18\x01 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a\xe6\x03\n\x1eUpdateDirectPurchasePriceEvent\x12\x15\n\x0b\x66ixed_price\x18\x01 \x01(\x04H\x00\x12\x95\x01\n\x0evariable_price\x18\x02 \x01(\x0b\x32{.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UpdateDirectPurchasePriceEvent.PricingScheduleH\x00\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x01\x88\x01\x01\x1a\x33\n\x10PriceForQuantity\x12\x10\n\x08quantity\x18\x01 \x01(\x04\x12\r\n\x05price\x18\x02 \x01(\x04\x1a\xac\x01\n\x0fPricingSchedule\x12\x98\x01\n\x12price_for_quantity\x18\x01 \x03(\x0b\x32|.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UpdateDirectPurchasePriceEvent.PriceForQuantityB\x07\n\x05priceB\x0e\n\x0c_public_note\x1a\xfc\x02\n\x10GroupActionEvent\x12n\n\x0btoken_event\x18\x01 \x01(\x0b\x32W.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.TokenEventH\x00\x12t\n\x0e\x64ocument_event\x18\x02 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.DocumentEventH\x00\x12t\n\x0e\x63ontract_event\x18\x03 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.ContractEventH\x00\x42\x0c\n\nevent_type\x1a\x8b\x01\n\rDocumentEvent\x12r\n\x06\x63reate\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.DocumentCreateEventH\x00\x42\x06\n\x04type\x1a/\n\x13\x44ocumentCreateEvent\x12\x18\n\x10\x63reated_document\x18\x01 \x01(\x0c\x1a/\n\x13\x43ontractUpdateEvent\x12\x18\n\x10updated_contract\x18\x01 \x01(\x0c\x1a\x8b\x01\n\rContractEvent\x12r\n\x06update\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.ContractUpdateEventH\x00\x42\x06\n\x04type\x1a\xd1\x07\n\nTokenEvent\x12\x66\n\x04mint\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.MintEventH\x00\x12\x66\n\x04\x62urn\x18\x02 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.BurnEventH\x00\x12j\n\x06\x66reeze\x18\x03 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.FreezeEventH\x00\x12n\n\x08unfreeze\x18\x04 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UnfreezeEventH\x00\x12\x84\x01\n\x14\x64\x65stroy_frozen_funds\x18\x05 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.DestroyFrozenFundsEventH\x00\x12}\n\x10\x65mergency_action\x18\x06 \x01(\x0b\x32\x61.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.EmergencyActionEventH\x00\x12\x82\x01\n\x13token_config_update\x18\x07 \x01(\x0b\x32\x63.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.TokenConfigUpdateEventH\x00\x12\x83\x01\n\x0cupdate_price\x18\x08 \x01(\x0b\x32k.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UpdateDirectPurchasePriceEventH\x00\x42\x06\n\x04type\x1a\x93\x01\n\x10GroupActionEntry\x12\x11\n\taction_id\x18\x01 \x01(\x0c\x12l\n\x05\x65vent\x18\x02 \x01(\x0b\x32].org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.GroupActionEvent\x1a\x84\x01\n\x0cGroupActions\x12t\n\rgroup_actions\x18\x01 \x03(\x0b\x32].org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.GroupActionEntryB\x08\n\x06resultB\t\n\x07version\"\x88\x03\n\x1cGetGroupActionSignersRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetGroupActionSignersRequest.GetGroupActionSignersRequestV0H\x00\x1a\xce\x01\n\x1eGetGroupActionSignersRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17group_contract_position\x18\x02 \x01(\r\x12T\n\x06status\x18\x03 \x01(\x0e\x32\x44.org.dash.platform.dapi.v0.GetGroupActionSignersRequest.ActionStatus\x12\x11\n\taction_id\x18\x04 \x01(\x0c\x12\r\n\x05prove\x18\x05 \x01(\x08\"&\n\x0c\x41\x63tionStatus\x12\n\n\x06\x41\x43TIVE\x10\x00\x12\n\n\x06\x43LOSED\x10\x01\x42\t\n\x07version\"\x8b\x05\n\x1dGetGroupActionSignersResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetGroupActionSignersResponse.GetGroupActionSignersResponseV0H\x00\x1a\xf6\x03\n\x1fGetGroupActionSignersResponseV0\x12\x8b\x01\n\x14group_action_signers\x18\x01 \x01(\x0b\x32k.org.dash.platform.dapi.v0.GetGroupActionSignersResponse.GetGroupActionSignersResponseV0.GroupActionSignersH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x35\n\x11GroupActionSigner\x12\x11\n\tsigner_id\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x02 \x01(\r\x1a\x91\x01\n\x12GroupActionSigners\x12{\n\x07signers\x18\x01 \x03(\x0b\x32j.org.dash.platform.dapi.v0.GetGroupActionSignersResponse.GetGroupActionSignersResponseV0.GroupActionSignerB\x08\n\x06resultB\t\n\x07version\"\xb5\x01\n\x15GetAddressInfoRequest\x12V\n\x02v0\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetAddressInfoRequest.GetAddressInfoRequestV0H\x00\x1a\x39\n\x17GetAddressInfoRequestV0\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x85\x01\n\x10\x41\x64\x64ressInfoEntry\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12J\n\x11\x62\x61lance_and_nonce\x18\x02 \x01(\x0b\x32*.org.dash.platform.dapi.v0.BalanceAndNonceH\x00\x88\x01\x01\x42\x14\n\x12_balance_and_nonce\"1\n\x0f\x42\x61lanceAndNonce\x12\x0f\n\x07\x62\x61lance\x18\x01 \x01(\x04\x12\r\n\x05nonce\x18\x02 \x01(\r\"_\n\x12\x41\x64\x64ressInfoEntries\x12I\n\x14\x61\x64\x64ress_info_entries\x18\x01 \x03(\x0b\x32+.org.dash.platform.dapi.v0.AddressInfoEntry\"m\n\x14\x41\x64\x64ressBalanceChange\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x19\n\x0bset_balance\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x12\x1c\n\x0e\x61\x64\x64_to_balance\x18\x03 \x01(\x04\x42\x02\x30\x01H\x00\x42\x0b\n\toperation\"x\n\x1a\x42lockAddressBalanceChanges\x12\x18\n\x0c\x62lock_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12@\n\x07\x63hanges\x18\x02 \x03(\x0b\x32/.org.dash.platform.dapi.v0.AddressBalanceChange\"k\n\x1b\x41\x64\x64ressBalanceUpdateEntries\x12L\n\rblock_changes\x18\x01 \x03(\x0b\x32\x35.org.dash.platform.dapi.v0.BlockAddressBalanceChanges\"\xe1\x02\n\x16GetAddressInfoResponse\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetAddressInfoResponse.GetAddressInfoResponseV0H\x00\x1a\xe1\x01\n\x18GetAddressInfoResponseV0\x12I\n\x12\x61\x64\x64ress_info_entry\x18\x01 \x01(\x0b\x32+.org.dash.platform.dapi.v0.AddressInfoEntryH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc3\x01\n\x18GetAddressesInfosRequest\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetAddressesInfosRequest.GetAddressesInfosRequestV0H\x00\x1a>\n\x1aGetAddressesInfosRequestV0\x12\x11\n\taddresses\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xf1\x02\n\x19GetAddressesInfosResponse\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetAddressesInfosResponse.GetAddressesInfosResponseV0H\x00\x1a\xe8\x01\n\x1bGetAddressesInfosResponseV0\x12M\n\x14\x61\x64\x64ress_info_entries\x18\x01 \x01(\x0b\x32-.org.dash.platform.dapi.v0.AddressInfoEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xb5\x01\n\x1dGetAddressesTrunkStateRequest\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetAddressesTrunkStateRequest.GetAddressesTrunkStateRequestV0H\x00\x1a!\n\x1fGetAddressesTrunkStateRequestV0B\t\n\x07version\"\xaa\x02\n\x1eGetAddressesTrunkStateResponse\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetAddressesTrunkStateResponse.GetAddressesTrunkStateResponseV0H\x00\x1a\x92\x01\n GetAddressesTrunkStateResponseV0\x12/\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.Proof\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\t\n\x07version\"\xf0\x01\n\x1eGetAddressesBranchStateRequest\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetAddressesBranchStateRequest.GetAddressesBranchStateRequestV0H\x00\x1aY\n GetAddressesBranchStateRequestV0\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\r\n\x05\x64\x65pth\x18\x02 \x01(\r\x12\x19\n\x11\x63heckpoint_height\x18\x03 \x01(\x04\x42\t\n\x07version\"\xd1\x01\n\x1fGetAddressesBranchStateResponse\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetAddressesBranchStateResponse.GetAddressesBranchStateResponseV0H\x00\x1a\x37\n!GetAddressesBranchStateResponseV0\x12\x12\n\nmerk_proof\x18\x02 \x01(\x0c\x42\t\n\x07version\"\xfe\x01\n%GetRecentAddressBalanceChangesRequest\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesRequest.GetRecentAddressBalanceChangesRequestV0H\x00\x1aR\n\'GetRecentAddressBalanceChangesRequestV0\x12\x18\n\x0cstart_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xb8\x03\n&GetRecentAddressBalanceChangesResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesResponse.GetRecentAddressBalanceChangesResponseV0H\x00\x1a\x88\x02\n(GetRecentAddressBalanceChangesResponseV0\x12`\n\x1e\x61\x64\x64ress_balance_update_entries\x18\x01 \x01(\x0b\x32\x36.org.dash.platform.dapi.v0.AddressBalanceUpdateEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"G\n\x16\x42lockHeightCreditEntry\x12\x18\n\x0c\x62lock_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x13\n\x07\x63redits\x18\x02 \x01(\x04\x42\x02\x30\x01\"\xb0\x01\n\x1d\x43ompactedAddressBalanceChange\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x19\n\x0bset_credits\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x12V\n\x19\x61\x64\x64_to_credits_operations\x18\x03 \x01(\x0b\x32\x31.org.dash.platform.dapi.v0.AddToCreditsOperationsH\x00\x42\x0b\n\toperation\"\\\n\x16\x41\x64\x64ToCreditsOperations\x12\x42\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x31.org.dash.platform.dapi.v0.BlockHeightCreditEntry\"\xae\x01\n#CompactedBlockAddressBalanceChanges\x12\x1e\n\x12start_block_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1c\n\x10\x65nd_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12I\n\x07\x63hanges\x18\x03 \x03(\x0b\x32\x38.org.dash.platform.dapi.v0.CompactedAddressBalanceChange\"\x87\x01\n$CompactedAddressBalanceUpdateEntries\x12_\n\x17\x63ompacted_block_changes\x18\x01 \x03(\x0b\x32>.org.dash.platform.dapi.v0.CompactedBlockAddressBalanceChanges\"\xa9\x02\n.GetRecentCompactedAddressBalanceChangesRequest\x12\x88\x01\n\x02v0\x18\x01 \x01(\x0b\x32z.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesRequest.GetRecentCompactedAddressBalanceChangesRequestV0H\x00\x1a\x61\n0GetRecentCompactedAddressBalanceChangesRequestV0\x12\x1e\n\x12start_block_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xf0\x03\n/GetRecentCompactedAddressBalanceChangesResponse\x12\x8a\x01\n\x02v0\x18\x01 \x01(\x0b\x32|.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0H\x00\x1a\xa4\x02\n1GetRecentCompactedAddressBalanceChangesResponseV0\x12s\n(compacted_address_balance_update_entries\x18\x01 \x01(\x0b\x32?.org.dash.platform.dapi.v0.CompactedAddressBalanceUpdateEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xf4\x01\n GetShieldedEncryptedNotesRequest\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0H\x00\x1aW\n\"GetShieldedEncryptedNotesRequestV0\x12\x13\n\x0bstart_index\x18\x01 \x01(\x04\x12\r\n\x05\x63ount\x18\x02 \x01(\r\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xac\x05\n!GetShieldedEncryptedNotesResponse\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0H\x00\x1a\x8b\x04\n#GetShieldedEncryptedNotesResponseV0\x12\x8a\x01\n\x0f\x65ncrypted_notes\x18\x01 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aG\n\rEncryptedNote\x12\x11\n\tnullifier\x18\x01 \x01(\x0c\x12\x0b\n\x03\x63mx\x18\x02 \x01(\x0c\x12\x16\n\x0e\x65ncrypted_note\x18\x03 \x01(\x0c\x1a\x91\x01\n\x0e\x45ncryptedNotes\x12\x7f\n\x07\x65ntries\x18\x01 \x03(\x0b\x32n.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNoteB\x08\n\x06resultB\t\n\x07version\"\xb4\x01\n\x19GetShieldedAnchorsRequest\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0H\x00\x1a,\n\x1bGetShieldedAnchorsRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xb1\x03\n\x1aGetShieldedAnchorsResponse\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0H\x00\x1a\xa5\x02\n\x1cGetShieldedAnchorsResponseV0\x12m\n\x07\x61nchors\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.AnchorsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1a\n\x07\x41nchors\x12\x0f\n\x07\x61nchors\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xbc\x01\n\x1bGetShieldedPoolStateRequest\x12\x62\n\x02v0\x18\x01 \x01(\x0b\x32T.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0H\x00\x1a.\n\x1dGetShieldedPoolStateRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xcb\x02\n\x1cGetShieldedPoolStateResponse\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0H\x00\x1a\xb9\x01\n\x1eGetShieldedPoolStateResponseV0\x12\x1b\n\rtotal_balance\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xd4\x01\n\x1cGetShieldedNullifiersRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0H\x00\x1a\x43\n\x1eGetShieldedNullifiersRequestV0\x12\x12\n\nnullifiers\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x86\x05\n\x1dGetShieldedNullifiersResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0H\x00\x1a\xf1\x03\n\x1fGetShieldedNullifiersResponseV0\x12\x88\x01\n\x12nullifier_statuses\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatusesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x36\n\x0fNullifierStatus\x12\x11\n\tnullifier\x18\x01 \x01(\x0c\x12\x10\n\x08is_spent\x18\x02 \x01(\x08\x1a\x8e\x01\n\x11NullifierStatuses\x12y\n\x07\x65ntries\x18\x01 \x03(\x0b\x32h.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatusB\x08\n\x06resultB\t\n\x07version*Z\n\nKeyPurpose\x12\x12\n\x0e\x41UTHENTICATION\x10\x00\x12\x0e\n\nENCRYPTION\x10\x01\x12\x0e\n\nDECRYPTION\x10\x02\x12\x0c\n\x08TRANSFER\x10\x03\x12\n\n\x06VOTING\x10\x05\x32\x9e\x41\n\x08Platform\x12\x93\x01\n\x18\x62roadcastStateTransition\x12:.org.dash.platform.dapi.v0.BroadcastStateTransitionRequest\x1a;.org.dash.platform.dapi.v0.BroadcastStateTransitionResponse\x12l\n\x0bgetIdentity\x12-.org.dash.platform.dapi.v0.GetIdentityRequest\x1a..org.dash.platform.dapi.v0.GetIdentityResponse\x12x\n\x0fgetIdentityKeys\x12\x31.org.dash.platform.dapi.v0.GetIdentityKeysRequest\x1a\x32.org.dash.platform.dapi.v0.GetIdentityKeysResponse\x12\x96\x01\n\x19getIdentitiesContractKeys\x12;.org.dash.platform.dapi.v0.GetIdentitiesContractKeysRequest\x1a<.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse\x12{\n\x10getIdentityNonce\x12\x32.org.dash.platform.dapi.v0.GetIdentityNonceRequest\x1a\x33.org.dash.platform.dapi.v0.GetIdentityNonceResponse\x12\x93\x01\n\x18getIdentityContractNonce\x12:.org.dash.platform.dapi.v0.GetIdentityContractNonceRequest\x1a;.org.dash.platform.dapi.v0.GetIdentityContractNonceResponse\x12\x81\x01\n\x12getIdentityBalance\x12\x34.org.dash.platform.dapi.v0.GetIdentityBalanceRequest\x1a\x35.org.dash.platform.dapi.v0.GetIdentityBalanceResponse\x12\x8a\x01\n\x15getIdentitiesBalances\x12\x37.org.dash.platform.dapi.v0.GetIdentitiesBalancesRequest\x1a\x38.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse\x12\xa2\x01\n\x1dgetIdentityBalanceAndRevision\x12?.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionRequest\x1a@.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionResponse\x12\xaf\x01\n#getEvonodesProposedEpochBlocksByIds\x12\x45.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByIdsRequest\x1a\x41.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse\x12\xb3\x01\n%getEvonodesProposedEpochBlocksByRange\x12G.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByRangeRequest\x1a\x41.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse\x12x\n\x0fgetDataContract\x12\x31.org.dash.platform.dapi.v0.GetDataContractRequest\x1a\x32.org.dash.platform.dapi.v0.GetDataContractResponse\x12\x8d\x01\n\x16getDataContractHistory\x12\x38.org.dash.platform.dapi.v0.GetDataContractHistoryRequest\x1a\x39.org.dash.platform.dapi.v0.GetDataContractHistoryResponse\x12{\n\x10getDataContracts\x12\x32.org.dash.platform.dapi.v0.GetDataContractsRequest\x1a\x33.org.dash.platform.dapi.v0.GetDataContractsResponse\x12o\n\x0cgetDocuments\x12..org.dash.platform.dapi.v0.GetDocumentsRequest\x1a/.org.dash.platform.dapi.v0.GetDocumentsResponse\x12\x99\x01\n\x1agetIdentityByPublicKeyHash\x12<.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashRequest\x1a=.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashResponse\x12\xb4\x01\n#getIdentityByNonUniquePublicKeyHash\x12\x45.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashRequest\x1a\x46.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse\x12\x9f\x01\n\x1cwaitForStateTransitionResult\x12>.org.dash.platform.dapi.v0.WaitForStateTransitionResultRequest\x1a?.org.dash.platform.dapi.v0.WaitForStateTransitionResultResponse\x12\x81\x01\n\x12getConsensusParams\x12\x34.org.dash.platform.dapi.v0.GetConsensusParamsRequest\x1a\x35.org.dash.platform.dapi.v0.GetConsensusParamsResponse\x12\xa5\x01\n\x1egetProtocolVersionUpgradeState\x12@.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateRequest\x1a\x41.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse\x12\xb4\x01\n#getProtocolVersionUpgradeVoteStatus\x12\x45.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusRequest\x1a\x46.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse\x12r\n\rgetEpochsInfo\x12/.org.dash.platform.dapi.v0.GetEpochsInfoRequest\x1a\x30.org.dash.platform.dapi.v0.GetEpochsInfoResponse\x12\x8d\x01\n\x16getFinalizedEpochInfos\x12\x38.org.dash.platform.dapi.v0.GetFinalizedEpochInfosRequest\x1a\x39.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse\x12\x8a\x01\n\x15getContestedResources\x12\x37.org.dash.platform.dapi.v0.GetContestedResourcesRequest\x1a\x38.org.dash.platform.dapi.v0.GetContestedResourcesResponse\x12\xa2\x01\n\x1dgetContestedResourceVoteState\x12?.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest\x1a@.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse\x12\xba\x01\n%getContestedResourceVotersForIdentity\x12G.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityRequest\x1aH.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityResponse\x12\xae\x01\n!getContestedResourceIdentityVotes\x12\x43.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesRequest\x1a\x44.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse\x12\x8a\x01\n\x15getVotePollsByEndDate\x12\x37.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest\x1a\x38.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse\x12\xa5\x01\n\x1egetPrefundedSpecializedBalance\x12@.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceRequest\x1a\x41.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceResponse\x12\x96\x01\n\x19getTotalCreditsInPlatform\x12;.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformRequest\x1a<.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformResponse\x12x\n\x0fgetPathElements\x12\x31.org.dash.platform.dapi.v0.GetPathElementsRequest\x1a\x32.org.dash.platform.dapi.v0.GetPathElementsResponse\x12\x66\n\tgetStatus\x12+.org.dash.platform.dapi.v0.GetStatusRequest\x1a,.org.dash.platform.dapi.v0.GetStatusResponse\x12\x8a\x01\n\x15getCurrentQuorumsInfo\x12\x37.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoRequest\x1a\x38.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse\x12\x93\x01\n\x18getIdentityTokenBalances\x12:.org.dash.platform.dapi.v0.GetIdentityTokenBalancesRequest\x1a;.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse\x12\x99\x01\n\x1agetIdentitiesTokenBalances\x12<.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesRequest\x1a=.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse\x12\x8a\x01\n\x15getIdentityTokenInfos\x12\x37.org.dash.platform.dapi.v0.GetIdentityTokenInfosRequest\x1a\x38.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse\x12\x90\x01\n\x17getIdentitiesTokenInfos\x12\x39.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosRequest\x1a:.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse\x12{\n\x10getTokenStatuses\x12\x32.org.dash.platform.dapi.v0.GetTokenStatusesRequest\x1a\x33.org.dash.platform.dapi.v0.GetTokenStatusesResponse\x12\x9f\x01\n\x1cgetTokenDirectPurchasePrices\x12>.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesRequest\x1a?.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse\x12\x87\x01\n\x14getTokenContractInfo\x12\x36.org.dash.platform.dapi.v0.GetTokenContractInfoRequest\x1a\x37.org.dash.platform.dapi.v0.GetTokenContractInfoResponse\x12\xb1\x01\n\"getTokenPreProgrammedDistributions\x12\x44.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsRequest\x1a\x45.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse\x12\xbd\x01\n&getTokenPerpetualDistributionLastClaim\x12H.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimRequest\x1aI.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimResponse\x12\x84\x01\n\x13getTokenTotalSupply\x12\x35.org.dash.platform.dapi.v0.GetTokenTotalSupplyRequest\x1a\x36.org.dash.platform.dapi.v0.GetTokenTotalSupplyResponse\x12o\n\x0cgetGroupInfo\x12..org.dash.platform.dapi.v0.GetGroupInfoRequest\x1a/.org.dash.platform.dapi.v0.GetGroupInfoResponse\x12r\n\rgetGroupInfos\x12/.org.dash.platform.dapi.v0.GetGroupInfosRequest\x1a\x30.org.dash.platform.dapi.v0.GetGroupInfosResponse\x12x\n\x0fgetGroupActions\x12\x31.org.dash.platform.dapi.v0.GetGroupActionsRequest\x1a\x32.org.dash.platform.dapi.v0.GetGroupActionsResponse\x12\x8a\x01\n\x15getGroupActionSigners\x12\x37.org.dash.platform.dapi.v0.GetGroupActionSignersRequest\x1a\x38.org.dash.platform.dapi.v0.GetGroupActionSignersResponse\x12u\n\x0egetAddressInfo\x12\x30.org.dash.platform.dapi.v0.GetAddressInfoRequest\x1a\x31.org.dash.platform.dapi.v0.GetAddressInfoResponse\x12~\n\x11getAddressesInfos\x12\x33.org.dash.platform.dapi.v0.GetAddressesInfosRequest\x1a\x34.org.dash.platform.dapi.v0.GetAddressesInfosResponse\x12\x8d\x01\n\x16getAddressesTrunkState\x12\x38.org.dash.platform.dapi.v0.GetAddressesTrunkStateRequest\x1a\x39.org.dash.platform.dapi.v0.GetAddressesTrunkStateResponse\x12\x90\x01\n\x17getAddressesBranchState\x12\x39.org.dash.platform.dapi.v0.GetAddressesBranchStateRequest\x1a:.org.dash.platform.dapi.v0.GetAddressesBranchStateResponse\x12\xa5\x01\n\x1egetRecentAddressBalanceChanges\x12@.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesRequest\x1a\x41.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesResponse\x12\xc0\x01\n\'getRecentCompactedAddressBalanceChanges\x12I.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesRequest\x1aJ.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse\x12\x96\x01\n\x19getShieldedEncryptedNotes\x12;.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest\x1a<.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse\x12\x81\x01\n\x12getShieldedAnchors\x12\x34.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest\x1a\x35.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse\x12\x87\x01\n\x14getShieldedPoolState\x12\x36.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest\x1a\x37.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse\x12\x8a\x01\n\x15getShieldedNullifiers\x12\x37.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest\x1a\x38.org.dash.platform.dapi.v0.GetShieldedNullifiersResponseb\x06proto3' + serialized_pb=b'\n\x0eplatform.proto\x12\x19org.dash.platform.dapi.v0\x1a\x1egoogle/protobuf/wrappers.proto\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x81\x01\n\x05Proof\x12\x15\n\rgrovedb_proof\x18\x01 \x01(\x0c\x12\x13\n\x0bquorum_hash\x18\x02 \x01(\x0c\x12\x11\n\tsignature\x18\x03 \x01(\x0c\x12\r\n\x05round\x18\x04 \x01(\r\x12\x15\n\rblock_id_hash\x18\x05 \x01(\x0c\x12\x13\n\x0bquorum_type\x18\x06 \x01(\r\"\x98\x01\n\x10ResponseMetadata\x12\x12\n\x06height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12 \n\x18\x63ore_chain_locked_height\x18\x02 \x01(\r\x12\r\n\x05\x65poch\x18\x03 \x01(\r\x12\x13\n\x07time_ms\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x18\n\x10protocol_version\x18\x05 \x01(\r\x12\x10\n\x08\x63hain_id\x18\x06 \x01(\t\"L\n\x1dStateTransitionBroadcastError\x12\x0c\n\x04\x63ode\x18\x01 \x01(\r\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\";\n\x1f\x42roadcastStateTransitionRequest\x12\x18\n\x10state_transition\x18\x01 \x01(\x0c\"\"\n BroadcastStateTransitionResponse\"\xa4\x01\n\x12GetIdentityRequest\x12P\n\x02v0\x18\x01 \x01(\x0b\x32\x42.org.dash.platform.dapi.v0.GetIdentityRequest.GetIdentityRequestV0H\x00\x1a\x31\n\x14GetIdentityRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xc1\x01\n\x17GetIdentityNonceRequest\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetIdentityNonceRequest.GetIdentityNonceRequestV0H\x00\x1a?\n\x19GetIdentityNonceRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xf6\x01\n\x1fGetIdentityContractNonceRequest\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetIdentityContractNonceRequest.GetIdentityContractNonceRequestV0H\x00\x1a\\\n!GetIdentityContractNonceRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x13\n\x0b\x63ontract_id\x18\x02 \x01(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xc0\x01\n\x19GetIdentityBalanceRequest\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetIdentityBalanceRequest.GetIdentityBalanceRequestV0H\x00\x1a\x38\n\x1bGetIdentityBalanceRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xec\x01\n$GetIdentityBalanceAndRevisionRequest\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionRequest.GetIdentityBalanceAndRevisionRequestV0H\x00\x1a\x43\n&GetIdentityBalanceAndRevisionRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x9e\x02\n\x13GetIdentityResponse\x12R\n\x02v0\x18\x01 \x01(\x0b\x32\x44.org.dash.platform.dapi.v0.GetIdentityResponse.GetIdentityResponseV0H\x00\x1a\xa7\x01\n\x15GetIdentityResponseV0\x12\x12\n\x08identity\x18\x01 \x01(\x0cH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xbc\x02\n\x18GetIdentityNonceResponse\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetIdentityNonceResponse.GetIdentityNonceResponseV0H\x00\x1a\xb6\x01\n\x1aGetIdentityNonceResponseV0\x12\x1c\n\x0eidentity_nonce\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xe5\x02\n GetIdentityContractNonceResponse\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetIdentityContractNonceResponse.GetIdentityContractNonceResponseV0H\x00\x1a\xc7\x01\n\"GetIdentityContractNonceResponseV0\x12%\n\x17identity_contract_nonce\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xbd\x02\n\x1aGetIdentityBalanceResponse\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetIdentityBalanceResponse.GetIdentityBalanceResponseV0H\x00\x1a\xb1\x01\n\x1cGetIdentityBalanceResponseV0\x12\x15\n\x07\x62\x61lance\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xb1\x04\n%GetIdentityBalanceAndRevisionResponse\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionResponse.GetIdentityBalanceAndRevisionResponseV0H\x00\x1a\x84\x03\n\'GetIdentityBalanceAndRevisionResponseV0\x12\x9b\x01\n\x14\x62\x61lance_and_revision\x18\x01 \x01(\x0b\x32{.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionResponse.GetIdentityBalanceAndRevisionResponseV0.BalanceAndRevisionH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a?\n\x12\x42\x61lanceAndRevision\x12\x13\n\x07\x62\x61lance\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x14\n\x08revision\x18\x02 \x01(\x04\x42\x02\x30\x01\x42\x08\n\x06resultB\t\n\x07version\"\xd1\x01\n\x0eKeyRequestType\x12\x36\n\x08\x61ll_keys\x18\x01 \x01(\x0b\x32\".org.dash.platform.dapi.v0.AllKeysH\x00\x12@\n\rspecific_keys\x18\x02 \x01(\x0b\x32\'.org.dash.platform.dapi.v0.SpecificKeysH\x00\x12:\n\nsearch_key\x18\x03 \x01(\x0b\x32$.org.dash.platform.dapi.v0.SearchKeyH\x00\x42\t\n\x07request\"\t\n\x07\x41llKeys\"\x1f\n\x0cSpecificKeys\x12\x0f\n\x07key_ids\x18\x01 \x03(\r\"\xb6\x01\n\tSearchKey\x12I\n\x0bpurpose_map\x18\x01 \x03(\x0b\x32\x34.org.dash.platform.dapi.v0.SearchKey.PurposeMapEntry\x1a^\n\x0fPurposeMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12:\n\x05value\x18\x02 \x01(\x0b\x32+.org.dash.platform.dapi.v0.SecurityLevelMap:\x02\x38\x01\"\xbf\x02\n\x10SecurityLevelMap\x12]\n\x12security_level_map\x18\x01 \x03(\x0b\x32\x41.org.dash.platform.dapi.v0.SecurityLevelMap.SecurityLevelMapEntry\x1aw\n\x15SecurityLevelMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\r\x12M\n\x05value\x18\x02 \x01(\x0e\x32>.org.dash.platform.dapi.v0.SecurityLevelMap.KeyKindRequestType:\x02\x38\x01\"S\n\x12KeyKindRequestType\x12\x1f\n\x1b\x43URRENT_KEY_OF_KIND_REQUEST\x10\x00\x12\x1c\n\x18\x41LL_KEYS_OF_KIND_REQUEST\x10\x01\"\xda\x02\n\x16GetIdentityKeysRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetIdentityKeysRequest.GetIdentityKeysRequestV0H\x00\x1a\xda\x01\n\x18GetIdentityKeysRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12?\n\x0crequest_type\x18\x02 \x01(\x0b\x32).org.dash.platform.dapi.v0.KeyRequestType\x12+\n\x05limit\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12,\n\x06offset\x18\x04 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\t\n\x07version\"\x99\x03\n\x17GetIdentityKeysResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetIdentityKeysResponse.GetIdentityKeysResponseV0H\x00\x1a\x96\x02\n\x19GetIdentityKeysResponseV0\x12\x61\n\x04keys\x18\x01 \x01(\x0b\x32Q.org.dash.platform.dapi.v0.GetIdentityKeysResponse.GetIdentityKeysResponseV0.KeysH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1a\n\x04Keys\x12\x12\n\nkeys_bytes\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xef\x02\n GetIdentitiesContractKeysRequest\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetIdentitiesContractKeysRequest.GetIdentitiesContractKeysRequestV0H\x00\x1a\xd1\x01\n\"GetIdentitiesContractKeysRequestV0\x12\x16\n\x0eidentities_ids\x18\x01 \x03(\x0c\x12\x13\n\x0b\x63ontract_id\x18\x02 \x01(\x0c\x12\x1f\n\x12\x64ocument_type_name\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x37\n\x08purposes\x18\x04 \x03(\x0e\x32%.org.dash.platform.dapi.v0.KeyPurpose\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\x15\n\x13_document_type_nameB\t\n\x07version\"\xdf\x06\n!GetIdentitiesContractKeysResponse\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0H\x00\x1a\xbe\x05\n#GetIdentitiesContractKeysResponseV0\x12\x8a\x01\n\x0fidentities_keys\x18\x01 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0.IdentitiesKeysH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aY\n\x0bPurposeKeys\x12\x36\n\x07purpose\x18\x01 \x01(\x0e\x32%.org.dash.platform.dapi.v0.KeyPurpose\x12\x12\n\nkeys_bytes\x18\x02 \x03(\x0c\x1a\x9f\x01\n\x0cIdentityKeys\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12z\n\x04keys\x18\x02 \x03(\x0b\x32l.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0.PurposeKeys\x1a\x90\x01\n\x0eIdentitiesKeys\x12~\n\x07\x65ntries\x18\x01 \x03(\x0b\x32m.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse.GetIdentitiesContractKeysResponseV0.IdentityKeysB\x08\n\x06resultB\t\n\x07version\"\xa4\x02\n*GetEvonodesProposedEpochBlocksByIdsRequest\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByIdsRequest.GetEvonodesProposedEpochBlocksByIdsRequestV0H\x00\x1ah\n,GetEvonodesProposedEpochBlocksByIdsRequestV0\x12\x12\n\x05\x65poch\x18\x01 \x01(\rH\x00\x88\x01\x01\x12\x0b\n\x03ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\x08\n\x06_epochB\t\n\x07version\"\x92\x06\n&GetEvonodesProposedEpochBlocksResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse.GetEvonodesProposedEpochBlocksResponseV0H\x00\x1a\xe2\x04\n(GetEvonodesProposedEpochBlocksResponseV0\x12\xb1\x01\n#evonodes_proposed_block_counts_info\x18\x01 \x01(\x0b\x32\x81\x01.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse.GetEvonodesProposedEpochBlocksResponseV0.EvonodesProposedBlocksH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a?\n\x15\x45vonodeProposedBlocks\x12\x13\n\x0bpro_tx_hash\x18\x01 \x01(\x0c\x12\x11\n\x05\x63ount\x18\x02 \x01(\x04\x42\x02\x30\x01\x1a\xc4\x01\n\x16\x45vonodesProposedBlocks\x12\xa9\x01\n\x1e\x65vonodes_proposed_block_counts\x18\x01 \x03(\x0b\x32\x80\x01.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse.GetEvonodesProposedEpochBlocksResponseV0.EvonodeProposedBlocksB\x08\n\x06resultB\t\n\x07version\"\xf2\x02\n,GetEvonodesProposedEpochBlocksByRangeRequest\x12\x84\x01\n\x02v0\x18\x01 \x01(\x0b\x32v.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByRangeRequest.GetEvonodesProposedEpochBlocksByRangeRequestV0H\x00\x1a\xaf\x01\n.GetEvonodesProposedEpochBlocksByRangeRequestV0\x12\x12\n\x05\x65poch\x18\x01 \x01(\rH\x01\x88\x01\x01\x12\x12\n\x05limit\x18\x02 \x01(\rH\x02\x88\x01\x01\x12\x15\n\x0bstart_after\x18\x03 \x01(\x0cH\x00\x12\x12\n\x08start_at\x18\x04 \x01(\x0cH\x00\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\x07\n\x05startB\x08\n\x06_epochB\x08\n\x06_limitB\t\n\x07version\"\xcd\x01\n\x1cGetIdentitiesBalancesRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetIdentitiesBalancesRequest.GetIdentitiesBalancesRequestV0H\x00\x1a<\n\x1eGetIdentitiesBalancesRequestV0\x12\x0b\n\x03ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x9f\x05\n\x1dGetIdentitiesBalancesResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse.GetIdentitiesBalancesResponseV0H\x00\x1a\x8a\x04\n\x1fGetIdentitiesBalancesResponseV0\x12\x8a\x01\n\x13identities_balances\x18\x01 \x01(\x0b\x32k.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse.GetIdentitiesBalancesResponseV0.IdentitiesBalancesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aL\n\x0fIdentityBalance\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x18\n\x07\x62\x61lance\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x88\x01\x01\x42\n\n\x08_balance\x1a\x8f\x01\n\x12IdentitiesBalances\x12y\n\x07\x65ntries\x18\x01 \x03(\x0b\x32h.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse.GetIdentitiesBalancesResponseV0.IdentityBalanceB\x08\n\x06resultB\t\n\x07version\"\xb4\x01\n\x16GetDataContractRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetDataContractRequest.GetDataContractRequestV0H\x00\x1a\x35\n\x18GetDataContractRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xb3\x02\n\x17GetDataContractResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetDataContractResponse.GetDataContractResponseV0H\x00\x1a\xb0\x01\n\x19GetDataContractResponseV0\x12\x17\n\rdata_contract\x18\x01 \x01(\x0cH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xb9\x01\n\x17GetDataContractsRequest\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetDataContractsRequest.GetDataContractsRequestV0H\x00\x1a\x37\n\x19GetDataContractsRequestV0\x12\x0b\n\x03ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xcf\x04\n\x18GetDataContractsResponse\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetDataContractsResponse.GetDataContractsResponseV0H\x00\x1a[\n\x11\x44\x61taContractEntry\x12\x12\n\nidentifier\x18\x01 \x01(\x0c\x12\x32\n\rdata_contract\x18\x02 \x01(\x0b\x32\x1b.google.protobuf.BytesValue\x1au\n\rDataContracts\x12\x64\n\x15\x64\x61ta_contract_entries\x18\x01 \x03(\x0b\x32\x45.org.dash.platform.dapi.v0.GetDataContractsResponse.DataContractEntry\x1a\xf5\x01\n\x1aGetDataContractsResponseV0\x12[\n\x0e\x64\x61ta_contracts\x18\x01 \x01(\x0b\x32\x41.org.dash.platform.dapi.v0.GetDataContractsResponse.DataContractsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc5\x02\n\x1dGetDataContractHistoryRequest\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetDataContractHistoryRequest.GetDataContractHistoryRequestV0H\x00\x1a\xb0\x01\n\x1fGetDataContractHistoryRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12+\n\x05limit\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12,\n\x06offset\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\x17\n\x0bstart_at_ms\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\t\n\x07version\"\xb2\x05\n\x1eGetDataContractHistoryResponse\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetDataContractHistoryResponse.GetDataContractHistoryResponseV0H\x00\x1a\x9a\x04\n GetDataContractHistoryResponseV0\x12\x8f\x01\n\x15\x64\x61ta_contract_history\x18\x01 \x01(\x0b\x32n.org.dash.platform.dapi.v0.GetDataContractHistoryResponse.GetDataContractHistoryResponseV0.DataContractHistoryH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a;\n\x18\x44\x61taContractHistoryEntry\x12\x10\n\x04\x64\x61te\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05value\x18\x02 \x01(\x0c\x1a\xaa\x01\n\x13\x44\x61taContractHistory\x12\x92\x01\n\x15\x64\x61ta_contract_entries\x18\x01 \x03(\x0b\x32s.org.dash.platform.dapi.v0.GetDataContractHistoryResponse.GetDataContractHistoryResponseV0.DataContractHistoryEntryB\x08\n\x06resultB\t\n\x07version\"\xb2\x02\n\x13GetDocumentsRequest\x12R\n\x02v0\x18\x01 \x01(\x0b\x32\x44.org.dash.platform.dapi.v0.GetDocumentsRequest.GetDocumentsRequestV0H\x00\x1a\xbb\x01\n\x15GetDocumentsRequestV0\x12\x18\n\x10\x64\x61ta_contract_id\x18\x01 \x01(\x0c\x12\x15\n\rdocument_type\x18\x02 \x01(\t\x12\r\n\x05where\x18\x03 \x01(\x0c\x12\x10\n\x08order_by\x18\x04 \x01(\x0c\x12\r\n\x05limit\x18\x05 \x01(\r\x12\x15\n\x0bstart_after\x18\x06 \x01(\x0cH\x00\x12\x12\n\x08start_at\x18\x07 \x01(\x0cH\x00\x12\r\n\x05prove\x18\x08 \x01(\x08\x42\x07\n\x05startB\t\n\x07version\"\x95\x03\n\x14GetDocumentsResponse\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetDocumentsResponse.GetDocumentsResponseV0H\x00\x1a\x9b\x02\n\x16GetDocumentsResponseV0\x12\x65\n\tdocuments\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetDocumentsResponse.GetDocumentsResponseV0.DocumentsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1e\n\tDocuments\x12\x11\n\tdocuments\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xed\x01\n!GetIdentityByPublicKeyHashRequest\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashRequest.GetIdentityByPublicKeyHashRequestV0H\x00\x1aM\n#GetIdentityByPublicKeyHashRequestV0\x12\x17\n\x0fpublic_key_hash\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xda\x02\n\"GetIdentityByPublicKeyHashResponse\x12p\n\x02v0\x18\x01 \x01(\x0b\x32\x62.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashResponse.GetIdentityByPublicKeyHashResponseV0H\x00\x1a\xb6\x01\n$GetIdentityByPublicKeyHashResponseV0\x12\x12\n\x08identity\x18\x01 \x01(\x0cH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xbd\x02\n*GetIdentityByNonUniquePublicKeyHashRequest\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashRequest.GetIdentityByNonUniquePublicKeyHashRequestV0H\x00\x1a\x80\x01\n,GetIdentityByNonUniquePublicKeyHashRequestV0\x12\x17\n\x0fpublic_key_hash\x18\x01 \x01(\x0c\x12\x18\n\x0bstart_after\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\x0e\n\x0c_start_afterB\t\n\x07version\"\xd6\x06\n+GetIdentityByNonUniquePublicKeyHashResponse\x12\x82\x01\n\x02v0\x18\x01 \x01(\x0b\x32t.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse.GetIdentityByNonUniquePublicKeyHashResponseV0H\x00\x1a\x96\x05\n-GetIdentityByNonUniquePublicKeyHashResponseV0\x12\x9a\x01\n\x08identity\x18\x01 \x01(\x0b\x32\x85\x01.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse.GetIdentityByNonUniquePublicKeyHashResponseV0.IdentityResponseH\x00\x12\x9d\x01\n\x05proof\x18\x02 \x01(\x0b\x32\x8b\x01.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse.GetIdentityByNonUniquePublicKeyHashResponseV0.IdentityProvedResponseH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x36\n\x10IdentityResponse\x12\x15\n\x08identity\x18\x01 \x01(\x0cH\x00\x88\x01\x01\x42\x0b\n\t_identity\x1a\xa6\x01\n\x16IdentityProvedResponse\x12P\n&grovedb_identity_public_key_hash_proof\x18\x01 \x01(\x0b\x32 .org.dash.platform.dapi.v0.Proof\x12!\n\x14identity_proof_bytes\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x42\x17\n\x15_identity_proof_bytesB\x08\n\x06resultB\t\n\x07version\"\xfb\x01\n#WaitForStateTransitionResultRequest\x12r\n\x02v0\x18\x01 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.WaitForStateTransitionResultRequest.WaitForStateTransitionResultRequestV0H\x00\x1aU\n%WaitForStateTransitionResultRequestV0\x12\x1d\n\x15state_transition_hash\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x99\x03\n$WaitForStateTransitionResultResponse\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.WaitForStateTransitionResultResponse.WaitForStateTransitionResultResponseV0H\x00\x1a\xef\x01\n&WaitForStateTransitionResultResponseV0\x12I\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x38.org.dash.platform.dapi.v0.StateTransitionBroadcastErrorH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc4\x01\n\x19GetConsensusParamsRequest\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetConsensusParamsRequest.GetConsensusParamsRequestV0H\x00\x1a<\n\x1bGetConsensusParamsRequestV0\x12\x0e\n\x06height\x18\x01 \x01(\x05\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x9c\x04\n\x1aGetConsensusParamsResponse\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetConsensusParamsResponse.GetConsensusParamsResponseV0H\x00\x1aP\n\x14\x43onsensusParamsBlock\x12\x11\n\tmax_bytes\x18\x01 \x01(\t\x12\x0f\n\x07max_gas\x18\x02 \x01(\t\x12\x14\n\x0ctime_iota_ms\x18\x03 \x01(\t\x1a\x62\n\x17\x43onsensusParamsEvidence\x12\x1a\n\x12max_age_num_blocks\x18\x01 \x01(\t\x12\x18\n\x10max_age_duration\x18\x02 \x01(\t\x12\x11\n\tmax_bytes\x18\x03 \x01(\t\x1a\xda\x01\n\x1cGetConsensusParamsResponseV0\x12Y\n\x05\x62lock\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetConsensusParamsResponse.ConsensusParamsBlock\x12_\n\x08\x65vidence\x18\x02 \x01(\x0b\x32M.org.dash.platform.dapi.v0.GetConsensusParamsResponse.ConsensusParamsEvidenceB\t\n\x07version\"\xe4\x01\n%GetProtocolVersionUpgradeStateRequest\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateRequest.GetProtocolVersionUpgradeStateRequestV0H\x00\x1a\x38\n\'GetProtocolVersionUpgradeStateRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xb5\x05\n&GetProtocolVersionUpgradeStateResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse.GetProtocolVersionUpgradeStateResponseV0H\x00\x1a\x85\x04\n(GetProtocolVersionUpgradeStateResponseV0\x12\x87\x01\n\x08versions\x18\x01 \x01(\x0b\x32s.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse.GetProtocolVersionUpgradeStateResponseV0.VersionsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x96\x01\n\x08Versions\x12\x89\x01\n\x08versions\x18\x01 \x03(\x0b\x32w.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse.GetProtocolVersionUpgradeStateResponseV0.VersionEntry\x1a:\n\x0cVersionEntry\x12\x16\n\x0eversion_number\x18\x01 \x01(\r\x12\x12\n\nvote_count\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xa3\x02\n*GetProtocolVersionUpgradeVoteStatusRequest\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusRequest.GetProtocolVersionUpgradeVoteStatusRequestV0H\x00\x1ag\n,GetProtocolVersionUpgradeVoteStatusRequestV0\x12\x19\n\x11start_pro_tx_hash\x18\x01 \x01(\x0c\x12\r\n\x05\x63ount\x18\x02 \x01(\r\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xef\x05\n+GetProtocolVersionUpgradeVoteStatusResponse\x12\x82\x01\n\x02v0\x18\x01 \x01(\x0b\x32t.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse.GetProtocolVersionUpgradeVoteStatusResponseV0H\x00\x1a\xaf\x04\n-GetProtocolVersionUpgradeVoteStatusResponseV0\x12\x98\x01\n\x08versions\x18\x01 \x01(\x0b\x32\x83\x01.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse.GetProtocolVersionUpgradeVoteStatusResponseV0.VersionSignalsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xaf\x01\n\x0eVersionSignals\x12\x9c\x01\n\x0fversion_signals\x18\x01 \x03(\x0b\x32\x82\x01.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse.GetProtocolVersionUpgradeVoteStatusResponseV0.VersionSignal\x1a\x35\n\rVersionSignal\x12\x13\n\x0bpro_tx_hash\x18\x01 \x01(\x0c\x12\x0f\n\x07version\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xf5\x01\n\x14GetEpochsInfoRequest\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetEpochsInfoRequest.GetEpochsInfoRequestV0H\x00\x1a|\n\x16GetEpochsInfoRequestV0\x12\x31\n\x0bstart_epoch\x18\x01 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\r\n\x05\x63ount\x18\x02 \x01(\r\x12\x11\n\tascending\x18\x03 \x01(\x08\x12\r\n\x05prove\x18\x04 \x01(\x08\x42\t\n\x07version\"\x99\x05\n\x15GetEpochsInfoResponse\x12V\n\x02v0\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetEpochsInfoResponse.GetEpochsInfoResponseV0H\x00\x1a\x9c\x04\n\x17GetEpochsInfoResponseV0\x12\x65\n\x06\x65pochs\x18\x01 \x01(\x0b\x32S.org.dash.platform.dapi.v0.GetEpochsInfoResponse.GetEpochsInfoResponseV0.EpochInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1au\n\nEpochInfos\x12g\n\x0b\x65poch_infos\x18\x01 \x03(\x0b\x32R.org.dash.platform.dapi.v0.GetEpochsInfoResponse.GetEpochsInfoResponseV0.EpochInfo\x1a\xa6\x01\n\tEpochInfo\x12\x0e\n\x06number\x18\x01 \x01(\r\x12\x1e\n\x12\x66irst_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x1f\n\x17\x66irst_core_block_height\x18\x03 \x01(\r\x12\x16\n\nstart_time\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x16\n\x0e\x66\x65\x65_multiplier\x18\x05 \x01(\x01\x12\x18\n\x10protocol_version\x18\x06 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xbf\x02\n\x1dGetFinalizedEpochInfosRequest\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetFinalizedEpochInfosRequest.GetFinalizedEpochInfosRequestV0H\x00\x1a\xaa\x01\n\x1fGetFinalizedEpochInfosRequestV0\x12\x19\n\x11start_epoch_index\x18\x01 \x01(\r\x12\"\n\x1astart_epoch_index_included\x18\x02 \x01(\x08\x12\x17\n\x0f\x65nd_epoch_index\x18\x03 \x01(\r\x12 \n\x18\x65nd_epoch_index_included\x18\x04 \x01(\x08\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\t\n\x07version\"\xbd\t\n\x1eGetFinalizedEpochInfosResponse\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0H\x00\x1a\xa5\x08\n GetFinalizedEpochInfosResponseV0\x12\x80\x01\n\x06\x65pochs\x18\x01 \x01(\x0b\x32n.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0.FinalizedEpochInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xa4\x01\n\x13\x46inalizedEpochInfos\x12\x8c\x01\n\x15\x66inalized_epoch_infos\x18\x01 \x03(\x0b\x32m.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0.FinalizedEpochInfo\x1a\x9f\x04\n\x12\x46inalizedEpochInfo\x12\x0e\n\x06number\x18\x01 \x01(\r\x12\x1e\n\x12\x66irst_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x1f\n\x17\x66irst_core_block_height\x18\x03 \x01(\r\x12\x1c\n\x10\x66irst_block_time\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x16\n\x0e\x66\x65\x65_multiplier\x18\x05 \x01(\x01\x12\x18\n\x10protocol_version\x18\x06 \x01(\r\x12!\n\x15total_blocks_in_epoch\x18\x07 \x01(\x04\x42\x02\x30\x01\x12*\n\"next_epoch_start_core_block_height\x18\x08 \x01(\r\x12!\n\x15total_processing_fees\x18\t \x01(\x04\x42\x02\x30\x01\x12*\n\x1etotal_distributed_storage_fees\x18\n \x01(\x04\x42\x02\x30\x01\x12&\n\x1atotal_created_storage_fees\x18\x0b \x01(\x04\x42\x02\x30\x01\x12\x1e\n\x12\x63ore_block_rewards\x18\x0c \x01(\x04\x42\x02\x30\x01\x12\x81\x01\n\x0f\x62lock_proposers\x18\r \x03(\x0b\x32h.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse.GetFinalizedEpochInfosResponseV0.BlockProposer\x1a\x39\n\rBlockProposer\x12\x13\n\x0bproposer_id\x18\x01 \x01(\x0c\x12\x13\n\x0b\x62lock_count\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xde\x04\n\x1cGetContestedResourcesRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetContestedResourcesRequest.GetContestedResourcesRequestV0H\x00\x1a\xcc\x03\n\x1eGetContestedResourcesRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\x12\n\nindex_name\x18\x03 \x01(\t\x12\x1a\n\x12start_index_values\x18\x04 \x03(\x0c\x12\x18\n\x10\x65nd_index_values\x18\x05 \x03(\x0c\x12\x89\x01\n\x13start_at_value_info\x18\x06 \x01(\x0b\x32g.org.dash.platform.dapi.v0.GetContestedResourcesRequest.GetContestedResourcesRequestV0.StartAtValueInfoH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x07 \x01(\rH\x01\x88\x01\x01\x12\x17\n\x0forder_ascending\x18\x08 \x01(\x08\x12\r\n\x05prove\x18\t \x01(\x08\x1a\x45\n\x10StartAtValueInfo\x12\x13\n\x0bstart_value\x18\x01 \x01(\x0c\x12\x1c\n\x14start_value_included\x18\x02 \x01(\x08\x42\x16\n\x14_start_at_value_infoB\x08\n\x06_countB\t\n\x07version\"\x88\x04\n\x1dGetContestedResourcesResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetContestedResourcesResponse.GetContestedResourcesResponseV0H\x00\x1a\xf3\x02\n\x1fGetContestedResourcesResponseV0\x12\x95\x01\n\x19\x63ontested_resource_values\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetContestedResourcesResponse.GetContestedResourcesResponseV0.ContestedResourceValuesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a<\n\x17\x43ontestedResourceValues\x12!\n\x19\x63ontested_resource_values\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xd2\x05\n\x1cGetVotePollsByEndDateRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest.GetVotePollsByEndDateRequestV0H\x00\x1a\xc0\x04\n\x1eGetVotePollsByEndDateRequestV0\x12\x84\x01\n\x0fstart_time_info\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest.GetVotePollsByEndDateRequestV0.StartAtTimeInfoH\x00\x88\x01\x01\x12\x80\x01\n\rend_time_info\x18\x02 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest.GetVotePollsByEndDateRequestV0.EndAtTimeInfoH\x01\x88\x01\x01\x12\x12\n\x05limit\x18\x03 \x01(\rH\x02\x88\x01\x01\x12\x13\n\x06offset\x18\x04 \x01(\rH\x03\x88\x01\x01\x12\x11\n\tascending\x18\x05 \x01(\x08\x12\r\n\x05prove\x18\x06 \x01(\x08\x1aI\n\x0fStartAtTimeInfo\x12\x19\n\rstart_time_ms\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1b\n\x13start_time_included\x18\x02 \x01(\x08\x1a\x43\n\rEndAtTimeInfo\x12\x17\n\x0b\x65nd_time_ms\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x19\n\x11\x65nd_time_included\x18\x02 \x01(\x08\x42\x12\n\x10_start_time_infoB\x10\n\x0e_end_time_infoB\x08\n\x06_limitB\t\n\x07_offsetB\t\n\x07version\"\x83\x06\n\x1dGetVotePollsByEndDateResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse.GetVotePollsByEndDateResponseV0H\x00\x1a\xee\x04\n\x1fGetVotePollsByEndDateResponseV0\x12\x9c\x01\n\x18vote_polls_by_timestamps\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse.GetVotePollsByEndDateResponseV0.SerializedVotePollsByTimestampsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aV\n\x1eSerializedVotePollsByTimestamp\x12\x15\n\ttimestamp\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1d\n\x15serialized_vote_polls\x18\x02 \x03(\x0c\x1a\xd7\x01\n\x1fSerializedVotePollsByTimestamps\x12\x99\x01\n\x18vote_polls_by_timestamps\x18\x01 \x03(\x0b\x32w.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse.GetVotePollsByEndDateResponseV0.SerializedVotePollsByTimestamp\x12\x18\n\x10\x66inished_results\x18\x02 \x01(\x08\x42\x08\n\x06resultB\t\n\x07version\"\xff\x06\n$GetContestedResourceVoteStateRequest\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest.GetContestedResourceVoteStateRequestV0H\x00\x1a\xd5\x05\n&GetContestedResourceVoteStateRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\x12\n\nindex_name\x18\x03 \x01(\t\x12\x14\n\x0cindex_values\x18\x04 \x03(\x0c\x12\x86\x01\n\x0bresult_type\x18\x05 \x01(\x0e\x32q.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest.GetContestedResourceVoteStateRequestV0.ResultType\x12\x36\n.allow_include_locked_and_abstaining_vote_tally\x18\x06 \x01(\x08\x12\xa3\x01\n\x18start_at_identifier_info\x18\x07 \x01(\x0b\x32|.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest.GetContestedResourceVoteStateRequestV0.StartAtIdentifierInfoH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x08 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\t \x01(\x08\x1aT\n\x15StartAtIdentifierInfo\x12\x18\n\x10start_identifier\x18\x01 \x01(\x0c\x12!\n\x19start_identifier_included\x18\x02 \x01(\x08\"I\n\nResultType\x12\r\n\tDOCUMENTS\x10\x00\x12\x0e\n\nVOTE_TALLY\x10\x01\x12\x1c\n\x18\x44OCUMENTS_AND_VOTE_TALLY\x10\x02\x42\x1b\n\x19_start_at_identifier_infoB\x08\n\x06_countB\t\n\x07version\"\x94\x0c\n%GetContestedResourceVoteStateResponse\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0H\x00\x1a\xe7\n\n\'GetContestedResourceVoteStateResponseV0\x12\xae\x01\n\x1d\x63ontested_resource_contenders\x18\x01 \x01(\x0b\x32\x84\x01.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.ContestedResourceContendersH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xda\x03\n\x10\x46inishedVoteInfo\x12\xad\x01\n\x15\x66inished_vote_outcome\x18\x01 \x01(\x0e\x32\x8d\x01.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.FinishedVoteInfo.FinishedVoteOutcome\x12\x1f\n\x12won_by_identity_id\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12$\n\x18\x66inished_at_block_height\x18\x03 \x01(\x04\x42\x02\x30\x01\x12%\n\x1d\x66inished_at_core_block_height\x18\x04 \x01(\r\x12%\n\x19\x66inished_at_block_time_ms\x18\x05 \x01(\x04\x42\x02\x30\x01\x12\x19\n\x11\x66inished_at_epoch\x18\x06 \x01(\r\"O\n\x13\x46inishedVoteOutcome\x12\x14\n\x10TOWARDS_IDENTITY\x10\x00\x12\n\n\x06LOCKED\x10\x01\x12\x16\n\x12NO_PREVIOUS_WINNER\x10\x02\x42\x15\n\x13_won_by_identity_id\x1a\xc4\x03\n\x1b\x43ontestedResourceContenders\x12\x86\x01\n\ncontenders\x18\x01 \x03(\x0b\x32r.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.Contender\x12\x1f\n\x12\x61\x62stain_vote_tally\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x1c\n\x0flock_vote_tally\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\x9a\x01\n\x12\x66inished_vote_info\x18\x04 \x01(\x0b\x32y.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse.GetContestedResourceVoteStateResponseV0.FinishedVoteInfoH\x02\x88\x01\x01\x42\x15\n\x13_abstain_vote_tallyB\x12\n\x10_lock_vote_tallyB\x15\n\x13_finished_vote_info\x1ak\n\tContender\x12\x12\n\nidentifier\x18\x01 \x01(\x0c\x12\x17\n\nvote_count\x18\x02 \x01(\rH\x00\x88\x01\x01\x12\x15\n\x08\x64ocument\x18\x03 \x01(\x0cH\x01\x88\x01\x01\x42\r\n\x0b_vote_countB\x0b\n\t_documentB\x08\n\x06resultB\t\n\x07version\"\xd5\x05\n,GetContestedResourceVotersForIdentityRequest\x12\x84\x01\n\x02v0\x18\x01 \x01(\x0b\x32v.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityRequest.GetContestedResourceVotersForIdentityRequestV0H\x00\x1a\x92\x04\n.GetContestedResourceVotersForIdentityRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\x12\n\nindex_name\x18\x03 \x01(\t\x12\x14\n\x0cindex_values\x18\x04 \x03(\x0c\x12\x15\n\rcontestant_id\x18\x05 \x01(\x0c\x12\xb4\x01\n\x18start_at_identifier_info\x18\x06 \x01(\x0b\x32\x8c\x01.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityRequest.GetContestedResourceVotersForIdentityRequestV0.StartAtIdentifierInfoH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x07 \x01(\rH\x01\x88\x01\x01\x12\x17\n\x0forder_ascending\x18\x08 \x01(\x08\x12\r\n\x05prove\x18\t \x01(\x08\x1aT\n\x15StartAtIdentifierInfo\x12\x18\n\x10start_identifier\x18\x01 \x01(\x0c\x12!\n\x19start_identifier_included\x18\x02 \x01(\x08\x42\x1b\n\x19_start_at_identifier_infoB\x08\n\x06_countB\t\n\x07version\"\xf1\x04\n-GetContestedResourceVotersForIdentityResponse\x12\x86\x01\n\x02v0\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityResponse.GetContestedResourceVotersForIdentityResponseV0H\x00\x1a\xab\x03\n/GetContestedResourceVotersForIdentityResponseV0\x12\xb6\x01\n\x19\x63ontested_resource_voters\x18\x01 \x01(\x0b\x32\x90\x01.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityResponse.GetContestedResourceVotersForIdentityResponseV0.ContestedResourceVotersH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x43\n\x17\x43ontestedResourceVoters\x12\x0e\n\x06voters\x18\x01 \x03(\x0c\x12\x18\n\x10\x66inished_results\x18\x02 \x01(\x08\x42\x08\n\x06resultB\t\n\x07version\"\xad\x05\n(GetContestedResourceIdentityVotesRequest\x12|\n\x02v0\x18\x01 \x01(\x0b\x32n.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesRequest.GetContestedResourceIdentityVotesRequestV0H\x00\x1a\xf7\x03\n*GetContestedResourceIdentityVotesRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12+\n\x05limit\x18\x02 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12,\n\x06offset\x18\x03 \x01(\x0b\x32\x1c.google.protobuf.UInt32Value\x12\x17\n\x0forder_ascending\x18\x04 \x01(\x08\x12\xae\x01\n\x1astart_at_vote_poll_id_info\x18\x05 \x01(\x0b\x32\x84\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesRequest.GetContestedResourceIdentityVotesRequestV0.StartAtVotePollIdInfoH\x00\x88\x01\x01\x12\r\n\x05prove\x18\x06 \x01(\x08\x1a\x61\n\x15StartAtVotePollIdInfo\x12 \n\x18start_at_poll_identifier\x18\x01 \x01(\x0c\x12&\n\x1estart_poll_identifier_included\x18\x02 \x01(\x08\x42\x1d\n\x1b_start_at_vote_poll_id_infoB\t\n\x07version\"\xc8\n\n)GetContestedResourceIdentityVotesResponse\x12~\n\x02v0\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0H\x00\x1a\x8f\t\n+GetContestedResourceIdentityVotesResponseV0\x12\xa1\x01\n\x05votes\x18\x01 \x01(\x0b\x32\x8f\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ContestedResourceIdentityVotesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\xf7\x01\n\x1e\x43ontestedResourceIdentityVotes\x12\xba\x01\n!contested_resource_identity_votes\x18\x01 \x03(\x0b\x32\x8e\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ContestedResourceIdentityVote\x12\x18\n\x10\x66inished_results\x18\x02 \x01(\x08\x1a\xad\x02\n\x12ResourceVoteChoice\x12\xad\x01\n\x10vote_choice_type\x18\x01 \x01(\x0e\x32\x92\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ResourceVoteChoice.VoteChoiceType\x12\x18\n\x0bidentity_id\x18\x02 \x01(\x0cH\x00\x88\x01\x01\"=\n\x0eVoteChoiceType\x12\x14\n\x10TOWARDS_IDENTITY\x10\x00\x12\x0b\n\x07\x41\x42STAIN\x10\x01\x12\x08\n\x04LOCK\x10\x02\x42\x0e\n\x0c_identity_id\x1a\x95\x02\n\x1d\x43ontestedResourceIdentityVote\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1a\n\x12\x64ocument_type_name\x18\x02 \x01(\t\x12\'\n\x1fserialized_index_storage_values\x18\x03 \x03(\x0c\x12\x99\x01\n\x0bvote_choice\x18\x04 \x01(\x0b\x32\x83\x01.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse.GetContestedResourceIdentityVotesResponseV0.ResourceVoteChoiceB\x08\n\x06resultB\t\n\x07version\"\xf0\x01\n%GetPrefundedSpecializedBalanceRequest\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceRequest.GetPrefundedSpecializedBalanceRequestV0H\x00\x1a\x44\n\'GetPrefundedSpecializedBalanceRequestV0\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xed\x02\n&GetPrefundedSpecializedBalanceResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceResponse.GetPrefundedSpecializedBalanceResponseV0H\x00\x1a\xbd\x01\n(GetPrefundedSpecializedBalanceResponseV0\x12\x15\n\x07\x62\x61lance\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xd0\x01\n GetTotalCreditsInPlatformRequest\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformRequest.GetTotalCreditsInPlatformRequestV0H\x00\x1a\x33\n\"GetTotalCreditsInPlatformRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xd9\x02\n!GetTotalCreditsInPlatformResponse\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformResponse.GetTotalCreditsInPlatformResponseV0H\x00\x1a\xb8\x01\n#GetTotalCreditsInPlatformResponseV0\x12\x15\n\x07\x63redits\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc4\x01\n\x16GetPathElementsRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetPathElementsRequest.GetPathElementsRequestV0H\x00\x1a\x45\n\x18GetPathElementsRequestV0\x12\x0c\n\x04path\x18\x01 \x03(\x0c\x12\x0c\n\x04keys\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xa3\x03\n\x17GetPathElementsResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetPathElementsResponse.GetPathElementsResponseV0H\x00\x1a\xa0\x02\n\x19GetPathElementsResponseV0\x12i\n\x08\x65lements\x18\x01 \x01(\x0b\x32U.org.dash.platform.dapi.v0.GetPathElementsResponse.GetPathElementsResponseV0.ElementsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1c\n\x08\x45lements\x12\x10\n\x08\x65lements\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\x81\x01\n\x10GetStatusRequest\x12L\n\x02v0\x18\x01 \x01(\x0b\x32>.org.dash.platform.dapi.v0.GetStatusRequest.GetStatusRequestV0H\x00\x1a\x14\n\x12GetStatusRequestV0B\t\n\x07version\"\xe4\x10\n\x11GetStatusResponse\x12N\n\x02v0\x18\x01 \x01(\x0b\x32@.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0H\x00\x1a\xf3\x0f\n\x13GetStatusResponseV0\x12Y\n\x07version\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version\x12S\n\x04node\x18\x02 \x01(\x0b\x32\x45.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Node\x12U\n\x05\x63hain\x18\x03 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Chain\x12Y\n\x07network\x18\x04 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Network\x12^\n\nstate_sync\x18\x05 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.StateSync\x12S\n\x04time\x18\x06 \x01(\x0b\x32\x45.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Time\x1a\x82\x05\n\x07Version\x12\x63\n\x08software\x18\x01 \x01(\x0b\x32Q.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Software\x12\x63\n\x08protocol\x18\x02 \x01(\x0b\x32Q.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Protocol\x1a^\n\x08Software\x12\x0c\n\x04\x64\x61pi\x18\x01 \x01(\t\x12\x12\n\x05\x64rive\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x17\n\ntenderdash\x18\x03 \x01(\tH\x01\x88\x01\x01\x42\x08\n\x06_driveB\r\n\x0b_tenderdash\x1a\xcc\x02\n\x08Protocol\x12p\n\ntenderdash\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Protocol.Tenderdash\x12\x66\n\x05\x64rive\x18\x02 \x01(\x0b\x32W.org.dash.platform.dapi.v0.GetStatusResponse.GetStatusResponseV0.Version.Protocol.Drive\x1a(\n\nTenderdash\x12\x0b\n\x03p2p\x18\x01 \x01(\r\x12\r\n\x05\x62lock\x18\x02 \x01(\r\x1a<\n\x05\x44rive\x12\x0e\n\x06latest\x18\x03 \x01(\r\x12\x0f\n\x07\x63urrent\x18\x04 \x01(\r\x12\x12\n\nnext_epoch\x18\x05 \x01(\r\x1a\x7f\n\x04Time\x12\x11\n\x05local\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x16\n\x05\x62lock\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x88\x01\x01\x12\x18\n\x07genesis\x18\x03 \x01(\x04\x42\x02\x30\x01H\x01\x88\x01\x01\x12\x12\n\x05\x65poch\x18\x04 \x01(\rH\x02\x88\x01\x01\x42\x08\n\x06_blockB\n\n\x08_genesisB\x08\n\x06_epoch\x1a<\n\x04Node\x12\n\n\x02id\x18\x01 \x01(\x0c\x12\x18\n\x0bpro_tx_hash\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x42\x0e\n\x0c_pro_tx_hash\x1a\xb3\x02\n\x05\x43hain\x12\x13\n\x0b\x63\x61tching_up\x18\x01 \x01(\x08\x12\x19\n\x11latest_block_hash\x18\x02 \x01(\x0c\x12\x17\n\x0flatest_app_hash\x18\x03 \x01(\x0c\x12\x1f\n\x13latest_block_height\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x1b\n\x13\x65\x61rliest_block_hash\x18\x05 \x01(\x0c\x12\x19\n\x11\x65\x61rliest_app_hash\x18\x06 \x01(\x0c\x12!\n\x15\x65\x61rliest_block_height\x18\x07 \x01(\x04\x42\x02\x30\x01\x12!\n\x15max_peer_block_height\x18\t \x01(\x04\x42\x02\x30\x01\x12%\n\x18\x63ore_chain_locked_height\x18\n \x01(\rH\x00\x88\x01\x01\x42\x1b\n\x19_core_chain_locked_height\x1a\x43\n\x07Network\x12\x10\n\x08\x63hain_id\x18\x01 \x01(\t\x12\x13\n\x0bpeers_count\x18\x02 \x01(\r\x12\x11\n\tlistening\x18\x03 \x01(\x08\x1a\x85\x02\n\tStateSync\x12\x1d\n\x11total_synced_time\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1a\n\x0eremaining_time\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x17\n\x0ftotal_snapshots\x18\x03 \x01(\r\x12\"\n\x16\x63hunk_process_avg_time\x18\x04 \x01(\x04\x42\x02\x30\x01\x12\x1b\n\x0fsnapshot_height\x18\x05 \x01(\x04\x42\x02\x30\x01\x12!\n\x15snapshot_chunks_count\x18\x06 \x01(\x04\x42\x02\x30\x01\x12\x1d\n\x11\x62\x61\x63kfilled_blocks\x18\x07 \x01(\x04\x42\x02\x30\x01\x12!\n\x15\x62\x61\x63kfill_blocks_total\x18\x08 \x01(\x04\x42\x02\x30\x01\x42\t\n\x07version\"\xb1\x01\n\x1cGetCurrentQuorumsInfoRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoRequest.GetCurrentQuorumsInfoRequestV0H\x00\x1a \n\x1eGetCurrentQuorumsInfoRequestV0B\t\n\x07version\"\xa1\x05\n\x1dGetCurrentQuorumsInfoResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse.GetCurrentQuorumsInfoResponseV0H\x00\x1a\x46\n\x0bValidatorV0\x12\x13\n\x0bpro_tx_hash\x18\x01 \x01(\x0c\x12\x0f\n\x07node_ip\x18\x02 \x01(\t\x12\x11\n\tis_banned\x18\x03 \x01(\x08\x1a\xaf\x01\n\x0eValidatorSetV0\x12\x13\n\x0bquorum_hash\x18\x01 \x01(\x0c\x12\x13\n\x0b\x63ore_height\x18\x02 \x01(\r\x12U\n\x07members\x18\x03 \x03(\x0b\x32\x44.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse.ValidatorV0\x12\x1c\n\x14threshold_public_key\x18\x04 \x01(\x0c\x1a\x92\x02\n\x1fGetCurrentQuorumsInfoResponseV0\x12\x15\n\rquorum_hashes\x18\x01 \x03(\x0c\x12\x1b\n\x13\x63urrent_quorum_hash\x18\x02 \x01(\x0c\x12_\n\x0evalidator_sets\x18\x03 \x03(\x0b\x32G.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse.ValidatorSetV0\x12\x1b\n\x13last_block_proposer\x18\x04 \x01(\x0c\x12=\n\x08metadata\x18\x05 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\t\n\x07version\"\xf4\x01\n\x1fGetIdentityTokenBalancesRequest\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetIdentityTokenBalancesRequest.GetIdentityTokenBalancesRequestV0H\x00\x1aZ\n!GetIdentityTokenBalancesRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x11\n\ttoken_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xad\x05\n GetIdentityTokenBalancesResponse\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse.GetIdentityTokenBalancesResponseV0H\x00\x1a\x8f\x04\n\"GetIdentityTokenBalancesResponseV0\x12\x86\x01\n\x0etoken_balances\x18\x01 \x01(\x0b\x32l.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse.GetIdentityTokenBalancesResponseV0.TokenBalancesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aG\n\x11TokenBalanceEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x14\n\x07\x62\x61lance\x18\x02 \x01(\x04H\x00\x88\x01\x01\x42\n\n\x08_balance\x1a\x9a\x01\n\rTokenBalances\x12\x88\x01\n\x0etoken_balances\x18\x01 \x03(\x0b\x32p.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse.GetIdentityTokenBalancesResponseV0.TokenBalanceEntryB\x08\n\x06resultB\t\n\x07version\"\xfc\x01\n!GetIdentitiesTokenBalancesRequest\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesRequest.GetIdentitiesTokenBalancesRequestV0H\x00\x1a\\\n#GetIdentitiesTokenBalancesRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x14\n\x0cidentity_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xf2\x05\n\"GetIdentitiesTokenBalancesResponse\x12p\n\x02v0\x18\x01 \x01(\x0b\x32\x62.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse.GetIdentitiesTokenBalancesResponseV0H\x00\x1a\xce\x04\n$GetIdentitiesTokenBalancesResponseV0\x12\x9b\x01\n\x17identity_token_balances\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse.GetIdentitiesTokenBalancesResponseV0.IdentityTokenBalancesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aR\n\x19IdentityTokenBalanceEntry\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x14\n\x07\x62\x61lance\x18\x02 \x01(\x04H\x00\x88\x01\x01\x42\n\n\x08_balance\x1a\xb7\x01\n\x15IdentityTokenBalances\x12\x9d\x01\n\x17identity_token_balances\x18\x01 \x03(\x0b\x32|.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse.GetIdentitiesTokenBalancesResponseV0.IdentityTokenBalanceEntryB\x08\n\x06resultB\t\n\x07version\"\xe8\x01\n\x1cGetIdentityTokenInfosRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetIdentityTokenInfosRequest.GetIdentityTokenInfosRequestV0H\x00\x1aW\n\x1eGetIdentityTokenInfosRequestV0\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x11\n\ttoken_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\x98\x06\n\x1dGetIdentityTokenInfosResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0H\x00\x1a\x83\x05\n\x1fGetIdentityTokenInfosResponseV0\x12z\n\x0btoken_infos\x18\x01 \x01(\x0b\x32\x63.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a(\n\x16TokenIdentityInfoEntry\x12\x0e\n\x06\x66rozen\x18\x01 \x01(\x08\x1a\xb0\x01\n\x0eTokenInfoEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x82\x01\n\x04info\x18\x02 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenIdentityInfoEntryH\x00\x88\x01\x01\x42\x07\n\x05_info\x1a\x8a\x01\n\nTokenInfos\x12|\n\x0btoken_infos\x18\x01 \x03(\x0b\x32g.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenInfoEntryB\x08\n\x06resultB\t\n\x07version\"\xf0\x01\n\x1eGetIdentitiesTokenInfosRequest\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosRequest.GetIdentitiesTokenInfosRequestV0H\x00\x1aY\n GetIdentitiesTokenInfosRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x14\n\x0cidentity_ids\x18\x02 \x03(\x0c\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xca\x06\n\x1fGetIdentitiesTokenInfosResponse\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0H\x00\x1a\xaf\x05\n!GetIdentitiesTokenInfosResponseV0\x12\x8f\x01\n\x14identity_token_infos\x18\x01 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0.IdentityTokenInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a(\n\x16TokenIdentityInfoEntry\x12\x0e\n\x06\x66rozen\x18\x01 \x01(\x08\x1a\xb7\x01\n\x0eTokenInfoEntry\x12\x13\n\x0bidentity_id\x18\x01 \x01(\x0c\x12\x86\x01\n\x04info\x18\x02 \x01(\x0b\x32s.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0.TokenIdentityInfoEntryH\x00\x88\x01\x01\x42\x07\n\x05_info\x1a\x97\x01\n\x12IdentityTokenInfos\x12\x80\x01\n\x0btoken_infos\x18\x01 \x03(\x0b\x32k.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse.GetIdentitiesTokenInfosResponseV0.TokenInfoEntryB\x08\n\x06resultB\t\n\x07version\"\xbf\x01\n\x17GetTokenStatusesRequest\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetTokenStatusesRequest.GetTokenStatusesRequestV0H\x00\x1a=\n\x19GetTokenStatusesRequestV0\x12\x11\n\ttoken_ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xe7\x04\n\x18GetTokenStatusesResponse\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetTokenStatusesResponse.GetTokenStatusesResponseV0H\x00\x1a\xe1\x03\n\x1aGetTokenStatusesResponseV0\x12v\n\x0etoken_statuses\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetTokenStatusesResponse.GetTokenStatusesResponseV0.TokenStatusesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x44\n\x10TokenStatusEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x13\n\x06paused\x18\x02 \x01(\x08H\x00\x88\x01\x01\x42\t\n\x07_paused\x1a\x88\x01\n\rTokenStatuses\x12w\n\x0etoken_statuses\x18\x01 \x03(\x0b\x32_.org.dash.platform.dapi.v0.GetTokenStatusesResponse.GetTokenStatusesResponseV0.TokenStatusEntryB\x08\n\x06resultB\t\n\x07version\"\xef\x01\n#GetTokenDirectPurchasePricesRequest\x12r\n\x02v0\x18\x01 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesRequest.GetTokenDirectPurchasePricesRequestV0H\x00\x1aI\n%GetTokenDirectPurchasePricesRequestV0\x12\x11\n\ttoken_ids\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x8b\t\n$GetTokenDirectPurchasePricesResponse\x12t\n\x02v0\x18\x01 \x01(\x0b\x32\x66.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0H\x00\x1a\xe1\x07\n&GetTokenDirectPurchasePricesResponseV0\x12\xa9\x01\n\x1ctoken_direct_purchase_prices\x18\x01 \x01(\x0b\x32\x80\x01.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.TokenDirectPurchasePricesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x33\n\x10PriceForQuantity\x12\x10\n\x08quantity\x18\x01 \x01(\x04\x12\r\n\x05price\x18\x02 \x01(\x04\x1a\xa7\x01\n\x0fPricingSchedule\x12\x93\x01\n\x12price_for_quantity\x18\x01 \x03(\x0b\x32w.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.PriceForQuantity\x1a\xe4\x01\n\x1dTokenDirectPurchasePriceEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x15\n\x0b\x66ixed_price\x18\x02 \x01(\x04H\x00\x12\x90\x01\n\x0evariable_price\x18\x03 \x01(\x0b\x32v.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.PricingScheduleH\x00\x42\x07\n\x05price\x1a\xc8\x01\n\x19TokenDirectPurchasePrices\x12\xaa\x01\n\x1btoken_direct_purchase_price\x18\x01 \x03(\x0b\x32\x84\x01.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse.GetTokenDirectPurchasePricesResponseV0.TokenDirectPurchasePriceEntryB\x08\n\x06resultB\t\n\x07version\"\xce\x01\n\x1bGetTokenContractInfoRequest\x12\x62\n\x02v0\x18\x01 \x01(\x0b\x32T.org.dash.platform.dapi.v0.GetTokenContractInfoRequest.GetTokenContractInfoRequestV0H\x00\x1a@\n\x1dGetTokenContractInfoRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xfb\x03\n\x1cGetTokenContractInfoResponse\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetTokenContractInfoResponse.GetTokenContractInfoResponseV0H\x00\x1a\xe9\x02\n\x1eGetTokenContractInfoResponseV0\x12|\n\x04\x64\x61ta\x18\x01 \x01(\x0b\x32l.org.dash.platform.dapi.v0.GetTokenContractInfoResponse.GetTokenContractInfoResponseV0.TokenContractInfoDataH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aM\n\x15TokenContractInfoData\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17token_contract_position\x18\x02 \x01(\rB\x08\n\x06resultB\t\n\x07version\"\xef\x04\n)GetTokenPreProgrammedDistributionsRequest\x12~\n\x02v0\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsRequest.GetTokenPreProgrammedDistributionsRequestV0H\x00\x1a\xb6\x03\n+GetTokenPreProgrammedDistributionsRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x98\x01\n\rstart_at_info\x18\x02 \x01(\x0b\x32|.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsRequest.GetTokenPreProgrammedDistributionsRequestV0.StartAtInfoH\x00\x88\x01\x01\x12\x12\n\x05limit\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\x04 \x01(\x08\x1a\x9a\x01\n\x0bStartAtInfo\x12\x15\n\rstart_time_ms\x18\x01 \x01(\x04\x12\x1c\n\x0fstart_recipient\x18\x02 \x01(\x0cH\x00\x88\x01\x01\x12%\n\x18start_recipient_included\x18\x03 \x01(\x08H\x01\x88\x01\x01\x42\x12\n\x10_start_recipientB\x1b\n\x19_start_recipient_includedB\x10\n\x0e_start_at_infoB\x08\n\x06_limitB\t\n\x07version\"\xec\x07\n*GetTokenPreProgrammedDistributionsResponse\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0H\x00\x1a\xaf\x06\n,GetTokenPreProgrammedDistributionsResponseV0\x12\xa5\x01\n\x13token_distributions\x18\x01 \x01(\x0b\x32\x85\x01.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0.TokenDistributionsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a>\n\x16TokenDistributionEntry\x12\x14\n\x0crecipient_id\x18\x01 \x01(\x0c\x12\x0e\n\x06\x61mount\x18\x02 \x01(\x04\x1a\xd4\x01\n\x1bTokenTimedDistributionEntry\x12\x11\n\ttimestamp\x18\x01 \x01(\x04\x12\xa1\x01\n\rdistributions\x18\x02 \x03(\x0b\x32\x89\x01.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0.TokenDistributionEntry\x1a\xc3\x01\n\x12TokenDistributions\x12\xac\x01\n\x13token_distributions\x18\x01 \x03(\x0b\x32\x8e\x01.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse.GetTokenPreProgrammedDistributionsResponseV0.TokenTimedDistributionEntryB\x08\n\x06resultB\t\n\x07version\"\x82\x04\n-GetTokenPerpetualDistributionLastClaimRequest\x12\x86\x01\n\x02v0\x18\x01 \x01(\x0b\x32x.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimRequest.GetTokenPerpetualDistributionLastClaimRequestV0H\x00\x1aI\n\x11\x43ontractTokenInfo\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17token_contract_position\x18\x02 \x01(\r\x1a\xf1\x01\n/GetTokenPerpetualDistributionLastClaimRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12v\n\rcontract_info\x18\x02 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimRequest.ContractTokenInfoH\x00\x88\x01\x01\x12\x13\n\x0bidentity_id\x18\x04 \x01(\x0c\x12\r\n\x05prove\x18\x05 \x01(\x08\x42\x10\n\x0e_contract_infoB\t\n\x07version\"\x93\x05\n.GetTokenPerpetualDistributionLastClaimResponse\x12\x88\x01\n\x02v0\x18\x01 \x01(\x0b\x32z.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimResponse.GetTokenPerpetualDistributionLastClaimResponseV0H\x00\x1a\xca\x03\n0GetTokenPerpetualDistributionLastClaimResponseV0\x12\x9f\x01\n\nlast_claim\x18\x01 \x01(\x0b\x32\x88\x01.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimResponse.GetTokenPerpetualDistributionLastClaimResponseV0.LastClaimInfoH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1ax\n\rLastClaimInfo\x12\x1a\n\x0ctimestamp_ms\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x1a\n\x0c\x62lock_height\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x12\x0f\n\x05\x65poch\x18\x03 \x01(\rH\x00\x12\x13\n\traw_bytes\x18\x04 \x01(\x0cH\x00\x42\t\n\x07paid_atB\x08\n\x06resultB\t\n\x07version\"\xca\x01\n\x1aGetTokenTotalSupplyRequest\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetTokenTotalSupplyRequest.GetTokenTotalSupplyRequestV0H\x00\x1a?\n\x1cGetTokenTotalSupplyRequestV0\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xaf\x04\n\x1bGetTokenTotalSupplyResponse\x12\x62\n\x02v0\x18\x01 \x01(\x0b\x32T.org.dash.platform.dapi.v0.GetTokenTotalSupplyResponse.GetTokenTotalSupplyResponseV0H\x00\x1a\xa0\x03\n\x1dGetTokenTotalSupplyResponseV0\x12\x88\x01\n\x12token_total_supply\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetTokenTotalSupplyResponse.GetTokenTotalSupplyResponseV0.TokenTotalSupplyEntryH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1ax\n\x15TokenTotalSupplyEntry\x12\x10\n\x08token_id\x18\x01 \x01(\x0c\x12\x30\n(total_aggregated_amount_in_user_accounts\x18\x02 \x01(\x04\x12\x1b\n\x13total_system_amount\x18\x03 \x01(\x04\x42\x08\n\x06resultB\t\n\x07version\"\xd2\x01\n\x13GetGroupInfoRequest\x12R\n\x02v0\x18\x01 \x01(\x0b\x32\x44.org.dash.platform.dapi.v0.GetGroupInfoRequest.GetGroupInfoRequestV0H\x00\x1a\\\n\x15GetGroupInfoRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17group_contract_position\x18\x02 \x01(\r\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xd4\x05\n\x14GetGroupInfoResponse\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0H\x00\x1a\xda\x04\n\x16GetGroupInfoResponseV0\x12\x66\n\ngroup_info\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0.GroupInfoH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x04 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x34\n\x10GroupMemberEntry\x12\x11\n\tmember_id\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x02 \x01(\r\x1a\x98\x01\n\x0eGroupInfoEntry\x12h\n\x07members\x18\x01 \x03(\x0b\x32W.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0.GroupMemberEntry\x12\x1c\n\x14group_required_power\x18\x02 \x01(\r\x1a\x8a\x01\n\tGroupInfo\x12n\n\ngroup_info\x18\x01 \x01(\x0b\x32U.org.dash.platform.dapi.v0.GetGroupInfoResponse.GetGroupInfoResponseV0.GroupInfoEntryH\x00\x88\x01\x01\x42\r\n\x0b_group_infoB\x08\n\x06resultB\t\n\x07version\"\xed\x03\n\x14GetGroupInfosRequest\x12T\n\x02v0\x18\x01 \x01(\x0b\x32\x46.org.dash.platform.dapi.v0.GetGroupInfosRequest.GetGroupInfosRequestV0H\x00\x1au\n\x1cStartAtGroupContractPosition\x12%\n\x1dstart_group_contract_position\x18\x01 \x01(\r\x12.\n&start_group_contract_position_included\x18\x02 \x01(\x08\x1a\xfc\x01\n\x16GetGroupInfosRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12{\n start_at_group_contract_position\x18\x02 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetGroupInfosRequest.StartAtGroupContractPositionH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x03 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\x04 \x01(\x08\x42#\n!_start_at_group_contract_positionB\x08\n\x06_countB\t\n\x07version\"\xff\x05\n\x15GetGroupInfosResponse\x12V\n\x02v0\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0H\x00\x1a\x82\x05\n\x17GetGroupInfosResponseV0\x12j\n\x0bgroup_infos\x18\x01 \x01(\x0b\x32S.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0.GroupInfosH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x04 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x34\n\x10GroupMemberEntry\x12\x11\n\tmember_id\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x02 \x01(\r\x1a\xc3\x01\n\x16GroupPositionInfoEntry\x12\x1f\n\x17group_contract_position\x18\x01 \x01(\r\x12j\n\x07members\x18\x02 \x03(\x0b\x32Y.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0.GroupMemberEntry\x12\x1c\n\x14group_required_power\x18\x03 \x01(\r\x1a\x82\x01\n\nGroupInfos\x12t\n\x0bgroup_infos\x18\x01 \x03(\x0b\x32_.org.dash.platform.dapi.v0.GetGroupInfosResponse.GetGroupInfosResponseV0.GroupPositionInfoEntryB\x08\n\x06resultB\t\n\x07version\"\xbe\x04\n\x16GetGroupActionsRequest\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetGroupActionsRequest.GetGroupActionsRequestV0H\x00\x1aL\n\x0fStartAtActionId\x12\x17\n\x0fstart_action_id\x18\x01 \x01(\x0c\x12 \n\x18start_action_id_included\x18\x02 \x01(\x08\x1a\xc8\x02\n\x18GetGroupActionsRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17group_contract_position\x18\x02 \x01(\r\x12N\n\x06status\x18\x03 \x01(\x0e\x32>.org.dash.platform.dapi.v0.GetGroupActionsRequest.ActionStatus\x12\x62\n\x12start_at_action_id\x18\x04 \x01(\x0b\x32\x41.org.dash.platform.dapi.v0.GetGroupActionsRequest.StartAtActionIdH\x00\x88\x01\x01\x12\x12\n\x05\x63ount\x18\x05 \x01(\rH\x01\x88\x01\x01\x12\r\n\x05prove\x18\x06 \x01(\x08\x42\x15\n\x13_start_at_action_idB\x08\n\x06_count\"&\n\x0c\x41\x63tionStatus\x12\n\n\x06\x41\x43TIVE\x10\x00\x12\n\n\x06\x43LOSED\x10\x01\x42\t\n\x07version\"\xd6\x1e\n\x17GetGroupActionsResponse\x12Z\n\x02v0\x18\x01 \x01(\x0b\x32L.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0H\x00\x1a\xd3\x1d\n\x19GetGroupActionsResponseV0\x12r\n\rgroup_actions\x18\x01 \x01(\x0b\x32Y.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.GroupActionsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a[\n\tMintEvent\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x04\x12\x14\n\x0crecipient_id\x18\x02 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a[\n\tBurnEvent\x12\x0e\n\x06\x61mount\x18\x01 \x01(\x04\x12\x14\n\x0c\x62urn_from_id\x18\x02 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1aJ\n\x0b\x46reezeEvent\x12\x11\n\tfrozen_id\x18\x01 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1aL\n\rUnfreezeEvent\x12\x11\n\tfrozen_id\x18\x01 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a\x66\n\x17\x44\x65stroyFrozenFundsEvent\x12\x11\n\tfrozen_id\x18\x01 \x01(\x0c\x12\x0e\n\x06\x61mount\x18\x02 \x01(\x04\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a\x64\n\x13SharedEncryptedNote\x12\x18\n\x10sender_key_index\x18\x01 \x01(\r\x12\x1b\n\x13recipient_key_index\x18\x02 \x01(\r\x12\x16\n\x0e\x65ncrypted_data\x18\x03 \x01(\x0c\x1a{\n\x15PersonalEncryptedNote\x12!\n\x19root_encryption_key_index\x18\x01 \x01(\r\x12\'\n\x1f\x64\x65rivation_encryption_key_index\x18\x02 \x01(\r\x12\x16\n\x0e\x65ncrypted_data\x18\x03 \x01(\x0c\x1a\xe9\x01\n\x14\x45mergencyActionEvent\x12\x81\x01\n\x0b\x61\x63tion_type\x18\x01 \x01(\x0e\x32l.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.EmergencyActionEvent.ActionType\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\"#\n\nActionType\x12\t\n\x05PAUSE\x10\x00\x12\n\n\x06RESUME\x10\x01\x42\x0e\n\x0c_public_note\x1a\x64\n\x16TokenConfigUpdateEvent\x12 \n\x18token_config_update_item\x18\x01 \x01(\x0c\x12\x18\n\x0bpublic_note\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0e\n\x0c_public_note\x1a\xe6\x03\n\x1eUpdateDirectPurchasePriceEvent\x12\x15\n\x0b\x66ixed_price\x18\x01 \x01(\x04H\x00\x12\x95\x01\n\x0evariable_price\x18\x02 \x01(\x0b\x32{.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UpdateDirectPurchasePriceEvent.PricingScheduleH\x00\x12\x18\n\x0bpublic_note\x18\x03 \x01(\tH\x01\x88\x01\x01\x1a\x33\n\x10PriceForQuantity\x12\x10\n\x08quantity\x18\x01 \x01(\x04\x12\r\n\x05price\x18\x02 \x01(\x04\x1a\xac\x01\n\x0fPricingSchedule\x12\x98\x01\n\x12price_for_quantity\x18\x01 \x03(\x0b\x32|.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UpdateDirectPurchasePriceEvent.PriceForQuantityB\x07\n\x05priceB\x0e\n\x0c_public_note\x1a\xfc\x02\n\x10GroupActionEvent\x12n\n\x0btoken_event\x18\x01 \x01(\x0b\x32W.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.TokenEventH\x00\x12t\n\x0e\x64ocument_event\x18\x02 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.DocumentEventH\x00\x12t\n\x0e\x63ontract_event\x18\x03 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.ContractEventH\x00\x42\x0c\n\nevent_type\x1a\x8b\x01\n\rDocumentEvent\x12r\n\x06\x63reate\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.DocumentCreateEventH\x00\x42\x06\n\x04type\x1a/\n\x13\x44ocumentCreateEvent\x12\x18\n\x10\x63reated_document\x18\x01 \x01(\x0c\x1a/\n\x13\x43ontractUpdateEvent\x12\x18\n\x10updated_contract\x18\x01 \x01(\x0c\x1a\x8b\x01\n\rContractEvent\x12r\n\x06update\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.ContractUpdateEventH\x00\x42\x06\n\x04type\x1a\xd1\x07\n\nTokenEvent\x12\x66\n\x04mint\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.MintEventH\x00\x12\x66\n\x04\x62urn\x18\x02 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.BurnEventH\x00\x12j\n\x06\x66reeze\x18\x03 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.FreezeEventH\x00\x12n\n\x08unfreeze\x18\x04 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UnfreezeEventH\x00\x12\x84\x01\n\x14\x64\x65stroy_frozen_funds\x18\x05 \x01(\x0b\x32\x64.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.DestroyFrozenFundsEventH\x00\x12}\n\x10\x65mergency_action\x18\x06 \x01(\x0b\x32\x61.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.EmergencyActionEventH\x00\x12\x82\x01\n\x13token_config_update\x18\x07 \x01(\x0b\x32\x63.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.TokenConfigUpdateEventH\x00\x12\x83\x01\n\x0cupdate_price\x18\x08 \x01(\x0b\x32k.org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.UpdateDirectPurchasePriceEventH\x00\x42\x06\n\x04type\x1a\x93\x01\n\x10GroupActionEntry\x12\x11\n\taction_id\x18\x01 \x01(\x0c\x12l\n\x05\x65vent\x18\x02 \x01(\x0b\x32].org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.GroupActionEvent\x1a\x84\x01\n\x0cGroupActions\x12t\n\rgroup_actions\x18\x01 \x03(\x0b\x32].org.dash.platform.dapi.v0.GetGroupActionsResponse.GetGroupActionsResponseV0.GroupActionEntryB\x08\n\x06resultB\t\n\x07version\"\x88\x03\n\x1cGetGroupActionSignersRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetGroupActionSignersRequest.GetGroupActionSignersRequestV0H\x00\x1a\xce\x01\n\x1eGetGroupActionSignersRequestV0\x12\x13\n\x0b\x63ontract_id\x18\x01 \x01(\x0c\x12\x1f\n\x17group_contract_position\x18\x02 \x01(\r\x12T\n\x06status\x18\x03 \x01(\x0e\x32\x44.org.dash.platform.dapi.v0.GetGroupActionSignersRequest.ActionStatus\x12\x11\n\taction_id\x18\x04 \x01(\x0c\x12\r\n\x05prove\x18\x05 \x01(\x08\"&\n\x0c\x41\x63tionStatus\x12\n\n\x06\x41\x43TIVE\x10\x00\x12\n\n\x06\x43LOSED\x10\x01\x42\t\n\x07version\"\x8b\x05\n\x1dGetGroupActionSignersResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetGroupActionSignersResponse.GetGroupActionSignersResponseV0H\x00\x1a\xf6\x03\n\x1fGetGroupActionSignersResponseV0\x12\x8b\x01\n\x14group_action_signers\x18\x01 \x01(\x0b\x32k.org.dash.platform.dapi.v0.GetGroupActionSignersResponse.GetGroupActionSignersResponseV0.GroupActionSignersH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x35\n\x11GroupActionSigner\x12\x11\n\tsigner_id\x18\x01 \x01(\x0c\x12\r\n\x05power\x18\x02 \x01(\r\x1a\x91\x01\n\x12GroupActionSigners\x12{\n\x07signers\x18\x01 \x03(\x0b\x32j.org.dash.platform.dapi.v0.GetGroupActionSignersResponse.GetGroupActionSignersResponseV0.GroupActionSignerB\x08\n\x06resultB\t\n\x07version\"\xb5\x01\n\x15GetAddressInfoRequest\x12V\n\x02v0\x18\x01 \x01(\x0b\x32H.org.dash.platform.dapi.v0.GetAddressInfoRequest.GetAddressInfoRequestV0H\x00\x1a\x39\n\x17GetAddressInfoRequestV0\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x85\x01\n\x10\x41\x64\x64ressInfoEntry\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12J\n\x11\x62\x61lance_and_nonce\x18\x02 \x01(\x0b\x32*.org.dash.platform.dapi.v0.BalanceAndNonceH\x00\x88\x01\x01\x42\x14\n\x12_balance_and_nonce\"1\n\x0f\x42\x61lanceAndNonce\x12\x0f\n\x07\x62\x61lance\x18\x01 \x01(\x04\x12\r\n\x05nonce\x18\x02 \x01(\r\"_\n\x12\x41\x64\x64ressInfoEntries\x12I\n\x14\x61\x64\x64ress_info_entries\x18\x01 \x03(\x0b\x32+.org.dash.platform.dapi.v0.AddressInfoEntry\"m\n\x14\x41\x64\x64ressBalanceChange\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x19\n\x0bset_balance\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x12\x1c\n\x0e\x61\x64\x64_to_balance\x18\x03 \x01(\x04\x42\x02\x30\x01H\x00\x42\x0b\n\toperation\"x\n\x1a\x42lockAddressBalanceChanges\x12\x18\n\x0c\x62lock_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12@\n\x07\x63hanges\x18\x02 \x03(\x0b\x32/.org.dash.platform.dapi.v0.AddressBalanceChange\"k\n\x1b\x41\x64\x64ressBalanceUpdateEntries\x12L\n\rblock_changes\x18\x01 \x03(\x0b\x32\x35.org.dash.platform.dapi.v0.BlockAddressBalanceChanges\"\xe1\x02\n\x16GetAddressInfoResponse\x12X\n\x02v0\x18\x01 \x01(\x0b\x32J.org.dash.platform.dapi.v0.GetAddressInfoResponse.GetAddressInfoResponseV0H\x00\x1a\xe1\x01\n\x18GetAddressInfoResponseV0\x12I\n\x12\x61\x64\x64ress_info_entry\x18\x01 \x01(\x0b\x32+.org.dash.platform.dapi.v0.AddressInfoEntryH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xc3\x01\n\x18GetAddressesInfosRequest\x12\\\n\x02v0\x18\x01 \x01(\x0b\x32N.org.dash.platform.dapi.v0.GetAddressesInfosRequest.GetAddressesInfosRequestV0H\x00\x1a>\n\x1aGetAddressesInfosRequestV0\x12\x11\n\taddresses\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xf1\x02\n\x19GetAddressesInfosResponse\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetAddressesInfosResponse.GetAddressesInfosResponseV0H\x00\x1a\xe8\x01\n\x1bGetAddressesInfosResponseV0\x12M\n\x14\x61\x64\x64ress_info_entries\x18\x01 \x01(\x0b\x32-.org.dash.platform.dapi.v0.AddressInfoEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xb5\x01\n\x1dGetAddressesTrunkStateRequest\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetAddressesTrunkStateRequest.GetAddressesTrunkStateRequestV0H\x00\x1a!\n\x1fGetAddressesTrunkStateRequestV0B\t\n\x07version\"\xaa\x02\n\x1eGetAddressesTrunkStateResponse\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetAddressesTrunkStateResponse.GetAddressesTrunkStateResponseV0H\x00\x1a\x92\x01\n GetAddressesTrunkStateResponseV0\x12/\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.Proof\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\t\n\x07version\"\xf0\x01\n\x1eGetAddressesBranchStateRequest\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetAddressesBranchStateRequest.GetAddressesBranchStateRequestV0H\x00\x1aY\n GetAddressesBranchStateRequestV0\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\r\n\x05\x64\x65pth\x18\x02 \x01(\r\x12\x19\n\x11\x63heckpoint_height\x18\x03 \x01(\x04\x42\t\n\x07version\"\xd1\x01\n\x1fGetAddressesBranchStateResponse\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetAddressesBranchStateResponse.GetAddressesBranchStateResponseV0H\x00\x1a\x37\n!GetAddressesBranchStateResponseV0\x12\x12\n\nmerk_proof\x18\x02 \x01(\x0c\x42\t\n\x07version\"\xfe\x01\n%GetRecentAddressBalanceChangesRequest\x12v\n\x02v0\x18\x01 \x01(\x0b\x32h.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesRequest.GetRecentAddressBalanceChangesRequestV0H\x00\x1aR\n\'GetRecentAddressBalanceChangesRequestV0\x12\x18\n\x0cstart_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xb8\x03\n&GetRecentAddressBalanceChangesResponse\x12x\n\x02v0\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesResponse.GetRecentAddressBalanceChangesResponseV0H\x00\x1a\x88\x02\n(GetRecentAddressBalanceChangesResponseV0\x12`\n\x1e\x61\x64\x64ress_balance_update_entries\x18\x01 \x01(\x0b\x32\x36.org.dash.platform.dapi.v0.AddressBalanceUpdateEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"G\n\x16\x42lockHeightCreditEntry\x12\x18\n\x0c\x62lock_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x13\n\x07\x63redits\x18\x02 \x01(\x04\x42\x02\x30\x01\"\xb0\x01\n\x1d\x43ompactedAddressBalanceChange\x12\x0f\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0c\x12\x19\n\x0bset_credits\x18\x02 \x01(\x04\x42\x02\x30\x01H\x00\x12V\n\x19\x61\x64\x64_to_credits_operations\x18\x03 \x01(\x0b\x32\x31.org.dash.platform.dapi.v0.AddToCreditsOperationsH\x00\x42\x0b\n\toperation\"\\\n\x16\x41\x64\x64ToCreditsOperations\x12\x42\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x31.org.dash.platform.dapi.v0.BlockHeightCreditEntry\"\xae\x01\n#CompactedBlockAddressBalanceChanges\x12\x1e\n\x12start_block_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1c\n\x10\x65nd_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12I\n\x07\x63hanges\x18\x03 \x03(\x0b\x32\x38.org.dash.platform.dapi.v0.CompactedAddressBalanceChange\"\x87\x01\n$CompactedAddressBalanceUpdateEntries\x12_\n\x17\x63ompacted_block_changes\x18\x01 \x03(\x0b\x32>.org.dash.platform.dapi.v0.CompactedBlockAddressBalanceChanges\"\xa9\x02\n.GetRecentCompactedAddressBalanceChangesRequest\x12\x88\x01\n\x02v0\x18\x01 \x01(\x0b\x32z.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesRequest.GetRecentCompactedAddressBalanceChangesRequestV0H\x00\x1a\x61\n0GetRecentCompactedAddressBalanceChangesRequestV0\x12\x1e\n\x12start_block_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xf0\x03\n/GetRecentCompactedAddressBalanceChangesResponse\x12\x8a\x01\n\x02v0\x18\x01 \x01(\x0b\x32|.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0H\x00\x1a\xa4\x02\n1GetRecentCompactedAddressBalanceChangesResponseV0\x12s\n(compacted_address_balance_update_entries\x18\x01 \x01(\x0b\x32?.org.dash.platform.dapi.v0.CompactedAddressBalanceUpdateEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xf4\x01\n GetShieldedEncryptedNotesRequest\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest.GetShieldedEncryptedNotesRequestV0H\x00\x1aW\n\"GetShieldedEncryptedNotesRequestV0\x12\x13\n\x0bstart_index\x18\x01 \x01(\x04\x12\r\n\x05\x63ount\x18\x02 \x01(\r\x12\r\n\x05prove\x18\x03 \x01(\x08\x42\t\n\x07version\"\xac\x05\n!GetShieldedEncryptedNotesResponse\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0H\x00\x1a\x8b\x04\n#GetShieldedEncryptedNotesResponseV0\x12\x8a\x01\n\x0f\x65ncrypted_notes\x18\x01 \x01(\x0b\x32o.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNotesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1aG\n\rEncryptedNote\x12\x11\n\tnullifier\x18\x01 \x01(\x0c\x12\x0b\n\x03\x63mx\x18\x02 \x01(\x0c\x12\x16\n\x0e\x65ncrypted_note\x18\x03 \x01(\x0c\x1a\x91\x01\n\x0e\x45ncryptedNotes\x12\x7f\n\x07\x65ntries\x18\x01 \x03(\x0b\x32n.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse.GetShieldedEncryptedNotesResponseV0.EncryptedNoteB\x08\n\x06resultB\t\n\x07version\"\xb4\x01\n\x19GetShieldedAnchorsRequest\x12^\n\x02v0\x18\x01 \x01(\x0b\x32P.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0H\x00\x1a,\n\x1bGetShieldedAnchorsRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xb1\x03\n\x1aGetShieldedAnchorsResponse\x12`\n\x02v0\x18\x01 \x01(\x0b\x32R.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0H\x00\x1a\xa5\x02\n\x1cGetShieldedAnchorsResponseV0\x12m\n\x07\x61nchors\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse.GetShieldedAnchorsResponseV0.AnchorsH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x1a\n\x07\x41nchors\x12\x0f\n\x07\x61nchors\x18\x01 \x03(\x0c\x42\x08\n\x06resultB\t\n\x07version\"\xbc\x01\n\x1bGetShieldedPoolStateRequest\x12\x62\n\x02v0\x18\x01 \x01(\x0b\x32T.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest.GetShieldedPoolStateRequestV0H\x00\x1a.\n\x1dGetShieldedPoolStateRequestV0\x12\r\n\x05prove\x18\x01 \x01(\x08\x42\t\n\x07version\"\xcb\x02\n\x1cGetShieldedPoolStateResponse\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse.GetShieldedPoolStateResponseV0H\x00\x1a\xb9\x01\n\x1eGetShieldedPoolStateResponseV0\x12\x1b\n\rtotal_balance\x18\x01 \x01(\x04\x42\x02\x30\x01H\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"\xd4\x01\n\x1cGetShieldedNullifiersRequest\x12\x64\n\x02v0\x18\x01 \x01(\x0b\x32V.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest.GetShieldedNullifiersRequestV0H\x00\x1a\x43\n\x1eGetShieldedNullifiersRequestV0\x12\x12\n\nnullifiers\x18\x01 \x03(\x0c\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x86\x05\n\x1dGetShieldedNullifiersResponse\x12\x66\n\x02v0\x18\x01 \x01(\x0b\x32X.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0H\x00\x1a\xf1\x03\n\x1fGetShieldedNullifiersResponseV0\x12\x88\x01\n\x12nullifier_statuses\x18\x01 \x01(\x0b\x32j.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatusesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadata\x1a\x36\n\x0fNullifierStatus\x12\x11\n\tnullifier\x18\x01 \x01(\x0c\x12\x10\n\x08is_spent\x18\x02 \x01(\x08\x1a\x8e\x01\n\x11NullifierStatuses\x12y\n\x07\x65ntries\x18\x01 \x03(\x0b\x32h.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatusB\x08\n\x06resultB\t\n\x07version\"\xe5\x01\n\x1eGetNullifiersTrunkStateRequest\x12h\n\x02v0\x18\x01 \x01(\x0b\x32Z.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0H\x00\x1aN\n GetNullifiersTrunkStateRequestV0\x12\x11\n\tpool_type\x18\x01 \x01(\r\x12\x17\n\x0fpool_identifier\x18\x02 \x01(\x0c\x42\t\n\x07version\"\xae\x02\n\x1fGetNullifiersTrunkStateResponse\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0H\x00\x1a\x93\x01\n!GetNullifiersTrunkStateResponseV0\x12/\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.Proof\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\t\n\x07version\"\xa1\x02\n\x1fGetNullifiersBranchStateRequest\x12j\n\x02v0\x18\x01 \x01(\x0b\x32\\.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0H\x00\x1a\x86\x01\n!GetNullifiersBranchStateRequestV0\x12\x11\n\tpool_type\x18\x01 \x01(\r\x12\x17\n\x0fpool_identifier\x18\x02 \x01(\x0c\x12\x0b\n\x03key\x18\x03 \x01(\x0c\x12\r\n\x05\x64\x65pth\x18\x04 \x01(\r\x12\x19\n\x11\x63heckpoint_height\x18\x05 \x01(\x04\x42\t\n\x07version\"\xd5\x01\n GetNullifiersBranchStateResponse\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0H\x00\x1a\x38\n\"GetNullifiersBranchStateResponseV0\x12\x12\n\nmerk_proof\x18\x02 \x01(\x0c\x42\t\n\x07version\"E\n\x15\x42lockNullifierChanges\x12\x18\n\x0c\x62lock_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x12\n\nnullifiers\x18\x02 \x03(\x0c\"a\n\x16NullifierUpdateEntries\x12G\n\rblock_changes\x18\x01 \x03(\x0b\x32\x30.org.dash.platform.dapi.v0.BlockNullifierChanges\"\xea\x01\n GetRecentNullifierChangesRequest\x12l\n\x02v0\x18\x01 \x01(\x0b\x32^.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0H\x00\x1aM\n\"GetRecentNullifierChangesRequestV0\x12\x18\n\x0cstart_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\x99\x03\n!GetRecentNullifierChangesResponse\x12n\n\x02v0\x18\x01 \x01(\x0b\x32`.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0H\x00\x1a\xf8\x01\n#GetRecentNullifierChangesResponseV0\x12U\n\x18nullifier_update_entries\x18\x01 \x01(\x0b\x32\x31.org.dash.platform.dapi.v0.NullifierUpdateEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version\"r\n\x1e\x43ompactedBlockNullifierChanges\x12\x1e\n\x12start_block_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\x1c\n\x10\x65nd_block_height\x18\x02 \x01(\x04\x42\x02\x30\x01\x12\x12\n\nnullifiers\x18\x03 \x03(\x0c\"}\n\x1f\x43ompactedNullifierUpdateEntries\x12Z\n\x17\x63ompacted_block_changes\x18\x01 \x03(\x0b\x32\x39.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges\"\x94\x02\n)GetRecentCompactedNullifierChangesRequest\x12~\n\x02v0\x18\x01 \x01(\x0b\x32p.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0H\x00\x1a\\\n+GetRecentCompactedNullifierChangesRequestV0\x12\x1e\n\x12start_block_height\x18\x01 \x01(\x04\x42\x02\x30\x01\x12\r\n\x05prove\x18\x02 \x01(\x08\x42\t\n\x07version\"\xd1\x03\n*GetRecentCompactedNullifierChangesResponse\x12\x80\x01\n\x02v0\x18\x01 \x01(\x0b\x32r.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0H\x00\x1a\x94\x02\n,GetRecentCompactedNullifierChangesResponseV0\x12h\n\"compacted_nullifier_update_entries\x18\x01 \x01(\x0b\x32:.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntriesH\x00\x12\x31\n\x05proof\x18\x02 \x01(\x0b\x32 .org.dash.platform.dapi.v0.ProofH\x00\x12=\n\x08metadata\x18\x03 \x01(\x0b\x32+.org.dash.platform.dapi.v0.ResponseMetadataB\x08\n\x06resultB\t\n\x07version*Z\n\nKeyPurpose\x12\x12\n\x0e\x41UTHENTICATION\x10\x00\x12\x0e\n\nENCRYPTION\x10\x01\x12\x0e\n\nDECRYPTION\x10\x02\x12\x0c\n\x08TRANSFER\x10\x03\x12\n\n\x06VOTING\x10\x05\x32\x94\x46\n\x08Platform\x12\x93\x01\n\x18\x62roadcastStateTransition\x12:.org.dash.platform.dapi.v0.BroadcastStateTransitionRequest\x1a;.org.dash.platform.dapi.v0.BroadcastStateTransitionResponse\x12l\n\x0bgetIdentity\x12-.org.dash.platform.dapi.v0.GetIdentityRequest\x1a..org.dash.platform.dapi.v0.GetIdentityResponse\x12x\n\x0fgetIdentityKeys\x12\x31.org.dash.platform.dapi.v0.GetIdentityKeysRequest\x1a\x32.org.dash.platform.dapi.v0.GetIdentityKeysResponse\x12\x96\x01\n\x19getIdentitiesContractKeys\x12;.org.dash.platform.dapi.v0.GetIdentitiesContractKeysRequest\x1a<.org.dash.platform.dapi.v0.GetIdentitiesContractKeysResponse\x12{\n\x10getIdentityNonce\x12\x32.org.dash.platform.dapi.v0.GetIdentityNonceRequest\x1a\x33.org.dash.platform.dapi.v0.GetIdentityNonceResponse\x12\x93\x01\n\x18getIdentityContractNonce\x12:.org.dash.platform.dapi.v0.GetIdentityContractNonceRequest\x1a;.org.dash.platform.dapi.v0.GetIdentityContractNonceResponse\x12\x81\x01\n\x12getIdentityBalance\x12\x34.org.dash.platform.dapi.v0.GetIdentityBalanceRequest\x1a\x35.org.dash.platform.dapi.v0.GetIdentityBalanceResponse\x12\x8a\x01\n\x15getIdentitiesBalances\x12\x37.org.dash.platform.dapi.v0.GetIdentitiesBalancesRequest\x1a\x38.org.dash.platform.dapi.v0.GetIdentitiesBalancesResponse\x12\xa2\x01\n\x1dgetIdentityBalanceAndRevision\x12?.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionRequest\x1a@.org.dash.platform.dapi.v0.GetIdentityBalanceAndRevisionResponse\x12\xaf\x01\n#getEvonodesProposedEpochBlocksByIds\x12\x45.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByIdsRequest\x1a\x41.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse\x12\xb3\x01\n%getEvonodesProposedEpochBlocksByRange\x12G.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksByRangeRequest\x1a\x41.org.dash.platform.dapi.v0.GetEvonodesProposedEpochBlocksResponse\x12x\n\x0fgetDataContract\x12\x31.org.dash.platform.dapi.v0.GetDataContractRequest\x1a\x32.org.dash.platform.dapi.v0.GetDataContractResponse\x12\x8d\x01\n\x16getDataContractHistory\x12\x38.org.dash.platform.dapi.v0.GetDataContractHistoryRequest\x1a\x39.org.dash.platform.dapi.v0.GetDataContractHistoryResponse\x12{\n\x10getDataContracts\x12\x32.org.dash.platform.dapi.v0.GetDataContractsRequest\x1a\x33.org.dash.platform.dapi.v0.GetDataContractsResponse\x12o\n\x0cgetDocuments\x12..org.dash.platform.dapi.v0.GetDocumentsRequest\x1a/.org.dash.platform.dapi.v0.GetDocumentsResponse\x12\x99\x01\n\x1agetIdentityByPublicKeyHash\x12<.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashRequest\x1a=.org.dash.platform.dapi.v0.GetIdentityByPublicKeyHashResponse\x12\xb4\x01\n#getIdentityByNonUniquePublicKeyHash\x12\x45.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashRequest\x1a\x46.org.dash.platform.dapi.v0.GetIdentityByNonUniquePublicKeyHashResponse\x12\x9f\x01\n\x1cwaitForStateTransitionResult\x12>.org.dash.platform.dapi.v0.WaitForStateTransitionResultRequest\x1a?.org.dash.platform.dapi.v0.WaitForStateTransitionResultResponse\x12\x81\x01\n\x12getConsensusParams\x12\x34.org.dash.platform.dapi.v0.GetConsensusParamsRequest\x1a\x35.org.dash.platform.dapi.v0.GetConsensusParamsResponse\x12\xa5\x01\n\x1egetProtocolVersionUpgradeState\x12@.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateRequest\x1a\x41.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeStateResponse\x12\xb4\x01\n#getProtocolVersionUpgradeVoteStatus\x12\x45.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusRequest\x1a\x46.org.dash.platform.dapi.v0.GetProtocolVersionUpgradeVoteStatusResponse\x12r\n\rgetEpochsInfo\x12/.org.dash.platform.dapi.v0.GetEpochsInfoRequest\x1a\x30.org.dash.platform.dapi.v0.GetEpochsInfoResponse\x12\x8d\x01\n\x16getFinalizedEpochInfos\x12\x38.org.dash.platform.dapi.v0.GetFinalizedEpochInfosRequest\x1a\x39.org.dash.platform.dapi.v0.GetFinalizedEpochInfosResponse\x12\x8a\x01\n\x15getContestedResources\x12\x37.org.dash.platform.dapi.v0.GetContestedResourcesRequest\x1a\x38.org.dash.platform.dapi.v0.GetContestedResourcesResponse\x12\xa2\x01\n\x1dgetContestedResourceVoteState\x12?.org.dash.platform.dapi.v0.GetContestedResourceVoteStateRequest\x1a@.org.dash.platform.dapi.v0.GetContestedResourceVoteStateResponse\x12\xba\x01\n%getContestedResourceVotersForIdentity\x12G.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityRequest\x1aH.org.dash.platform.dapi.v0.GetContestedResourceVotersForIdentityResponse\x12\xae\x01\n!getContestedResourceIdentityVotes\x12\x43.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesRequest\x1a\x44.org.dash.platform.dapi.v0.GetContestedResourceIdentityVotesResponse\x12\x8a\x01\n\x15getVotePollsByEndDate\x12\x37.org.dash.platform.dapi.v0.GetVotePollsByEndDateRequest\x1a\x38.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse\x12\xa5\x01\n\x1egetPrefundedSpecializedBalance\x12@.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceRequest\x1a\x41.org.dash.platform.dapi.v0.GetPrefundedSpecializedBalanceResponse\x12\x96\x01\n\x19getTotalCreditsInPlatform\x12;.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformRequest\x1a<.org.dash.platform.dapi.v0.GetTotalCreditsInPlatformResponse\x12x\n\x0fgetPathElements\x12\x31.org.dash.platform.dapi.v0.GetPathElementsRequest\x1a\x32.org.dash.platform.dapi.v0.GetPathElementsResponse\x12\x66\n\tgetStatus\x12+.org.dash.platform.dapi.v0.GetStatusRequest\x1a,.org.dash.platform.dapi.v0.GetStatusResponse\x12\x8a\x01\n\x15getCurrentQuorumsInfo\x12\x37.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoRequest\x1a\x38.org.dash.platform.dapi.v0.GetCurrentQuorumsInfoResponse\x12\x93\x01\n\x18getIdentityTokenBalances\x12:.org.dash.platform.dapi.v0.GetIdentityTokenBalancesRequest\x1a;.org.dash.platform.dapi.v0.GetIdentityTokenBalancesResponse\x12\x99\x01\n\x1agetIdentitiesTokenBalances\x12<.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesRequest\x1a=.org.dash.platform.dapi.v0.GetIdentitiesTokenBalancesResponse\x12\x8a\x01\n\x15getIdentityTokenInfos\x12\x37.org.dash.platform.dapi.v0.GetIdentityTokenInfosRequest\x1a\x38.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse\x12\x90\x01\n\x17getIdentitiesTokenInfos\x12\x39.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosRequest\x1a:.org.dash.platform.dapi.v0.GetIdentitiesTokenInfosResponse\x12{\n\x10getTokenStatuses\x12\x32.org.dash.platform.dapi.v0.GetTokenStatusesRequest\x1a\x33.org.dash.platform.dapi.v0.GetTokenStatusesResponse\x12\x9f\x01\n\x1cgetTokenDirectPurchasePrices\x12>.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesRequest\x1a?.org.dash.platform.dapi.v0.GetTokenDirectPurchasePricesResponse\x12\x87\x01\n\x14getTokenContractInfo\x12\x36.org.dash.platform.dapi.v0.GetTokenContractInfoRequest\x1a\x37.org.dash.platform.dapi.v0.GetTokenContractInfoResponse\x12\xb1\x01\n\"getTokenPreProgrammedDistributions\x12\x44.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsRequest\x1a\x45.org.dash.platform.dapi.v0.GetTokenPreProgrammedDistributionsResponse\x12\xbd\x01\n&getTokenPerpetualDistributionLastClaim\x12H.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimRequest\x1aI.org.dash.platform.dapi.v0.GetTokenPerpetualDistributionLastClaimResponse\x12\x84\x01\n\x13getTokenTotalSupply\x12\x35.org.dash.platform.dapi.v0.GetTokenTotalSupplyRequest\x1a\x36.org.dash.platform.dapi.v0.GetTokenTotalSupplyResponse\x12o\n\x0cgetGroupInfo\x12..org.dash.platform.dapi.v0.GetGroupInfoRequest\x1a/.org.dash.platform.dapi.v0.GetGroupInfoResponse\x12r\n\rgetGroupInfos\x12/.org.dash.platform.dapi.v0.GetGroupInfosRequest\x1a\x30.org.dash.platform.dapi.v0.GetGroupInfosResponse\x12x\n\x0fgetGroupActions\x12\x31.org.dash.platform.dapi.v0.GetGroupActionsRequest\x1a\x32.org.dash.platform.dapi.v0.GetGroupActionsResponse\x12\x8a\x01\n\x15getGroupActionSigners\x12\x37.org.dash.platform.dapi.v0.GetGroupActionSignersRequest\x1a\x38.org.dash.platform.dapi.v0.GetGroupActionSignersResponse\x12u\n\x0egetAddressInfo\x12\x30.org.dash.platform.dapi.v0.GetAddressInfoRequest\x1a\x31.org.dash.platform.dapi.v0.GetAddressInfoResponse\x12~\n\x11getAddressesInfos\x12\x33.org.dash.platform.dapi.v0.GetAddressesInfosRequest\x1a\x34.org.dash.platform.dapi.v0.GetAddressesInfosResponse\x12\x8d\x01\n\x16getAddressesTrunkState\x12\x38.org.dash.platform.dapi.v0.GetAddressesTrunkStateRequest\x1a\x39.org.dash.platform.dapi.v0.GetAddressesTrunkStateResponse\x12\x90\x01\n\x17getAddressesBranchState\x12\x39.org.dash.platform.dapi.v0.GetAddressesBranchStateRequest\x1a:.org.dash.platform.dapi.v0.GetAddressesBranchStateResponse\x12\xa5\x01\n\x1egetRecentAddressBalanceChanges\x12@.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesRequest\x1a\x41.org.dash.platform.dapi.v0.GetRecentAddressBalanceChangesResponse\x12\xc0\x01\n\'getRecentCompactedAddressBalanceChanges\x12I.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesRequest\x1aJ.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse\x12\x96\x01\n\x19getShieldedEncryptedNotes\x12;.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesRequest\x1a<.org.dash.platform.dapi.v0.GetShieldedEncryptedNotesResponse\x12\x81\x01\n\x12getShieldedAnchors\x12\x34.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest\x1a\x35.org.dash.platform.dapi.v0.GetShieldedAnchorsResponse\x12\x87\x01\n\x14getShieldedPoolState\x12\x36.org.dash.platform.dapi.v0.GetShieldedPoolStateRequest\x1a\x37.org.dash.platform.dapi.v0.GetShieldedPoolStateResponse\x12\x8a\x01\n\x15getShieldedNullifiers\x12\x37.org.dash.platform.dapi.v0.GetShieldedNullifiersRequest\x1a\x38.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse\x12\x90\x01\n\x17getNullifiersTrunkState\x12\x39.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest\x1a:.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse\x12\x93\x01\n\x18getNullifiersBranchState\x12:.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest\x1a;.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse\x12\x96\x01\n\x19getRecentNullifierChanges\x12;.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest\x1a<.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse\x12\xb1\x01\n\"getRecentCompactedNullifierChanges\x12\x44.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest\x1a\x45.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponseb\x06proto3' , dependencies=[google_dot_protobuf_dot_wrappers__pb2.DESCRIPTOR,google_dot_protobuf_dot_struct__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,]) @@ -62,8 +62,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=58754, - serialized_end=58844, + serialized_start=61608, + serialized_end=61698, ) _sym_db.RegisterEnumDescriptor(_KEYPURPOSE) @@ -15542,6 +15542,793 @@ serialized_end=58752, ) + +_GETNULLIFIERSTRUNKSTATEREQUEST_GETNULLIFIERSTRUNKSTATEREQUESTV0 = _descriptor.Descriptor( + name='GetNullifiersTrunkStateRequestV0', + full_name='org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='pool_type', full_name='org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.pool_type', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='pool_identifier', full_name='org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.pool_identifier', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=58895, + serialized_end=58973, +) + +_GETNULLIFIERSTRUNKSTATEREQUEST = _descriptor.Descriptor( + name='GetNullifiersTrunkStateRequest', + full_name='org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='v0', full_name='org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.v0', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETNULLIFIERSTRUNKSTATEREQUEST_GETNULLIFIERSTRUNKSTATEREQUESTV0, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='version', full_name='org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.version', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=58755, + serialized_end=58984, +) + + +_GETNULLIFIERSTRUNKSTATERESPONSE_GETNULLIFIERSTRUNKSTATERESPONSEV0 = _descriptor.Descriptor( + name='GetNullifiersTrunkStateResponseV0', + full_name='org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='proof', full_name='org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.proof', index=0, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='metadata', full_name='org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.metadata', index=1, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=59131, + serialized_end=59278, +) + +_GETNULLIFIERSTRUNKSTATERESPONSE = _descriptor.Descriptor( + name='GetNullifiersTrunkStateResponse', + full_name='org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='v0', full_name='org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.v0', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETNULLIFIERSTRUNKSTATERESPONSE_GETNULLIFIERSTRUNKSTATERESPONSEV0, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='version', full_name='org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.version', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=58987, + serialized_end=59289, +) + + +_GETNULLIFIERSBRANCHSTATEREQUEST_GETNULLIFIERSBRANCHSTATEREQUESTV0 = _descriptor.Descriptor( + name='GetNullifiersBranchStateRequestV0', + full_name='org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='pool_type', full_name='org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.pool_type', index=0, + number=1, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='pool_identifier', full_name='org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.pool_identifier', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='key', full_name='org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.key', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='depth', full_name='org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.depth', index=3, + number=4, type=13, cpp_type=3, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='checkpoint_height', full_name='org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.checkpoint_height', index=4, + number=5, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=59436, + serialized_end=59570, +) + +_GETNULLIFIERSBRANCHSTATEREQUEST = _descriptor.Descriptor( + name='GetNullifiersBranchStateRequest', + full_name='org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='v0', full_name='org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.v0', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETNULLIFIERSBRANCHSTATEREQUEST_GETNULLIFIERSBRANCHSTATEREQUESTV0, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='version', full_name='org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.version', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=59292, + serialized_end=59581, +) + + +_GETNULLIFIERSBRANCHSTATERESPONSE_GETNULLIFIERSBRANCHSTATERESPONSEV0 = _descriptor.Descriptor( + name='GetNullifiersBranchStateResponseV0', + full_name='org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='merk_proof', full_name='org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.merk_proof', index=0, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=59730, + serialized_end=59786, +) + +_GETNULLIFIERSBRANCHSTATERESPONSE = _descriptor.Descriptor( + name='GetNullifiersBranchStateResponse', + full_name='org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='v0', full_name='org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.v0', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETNULLIFIERSBRANCHSTATERESPONSE_GETNULLIFIERSBRANCHSTATERESPONSEV0, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='version', full_name='org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.version', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=59584, + serialized_end=59797, +) + + +_BLOCKNULLIFIERCHANGES = _descriptor.Descriptor( + name='BlockNullifierChanges', + full_name='org.dash.platform.dapi.v0.BlockNullifierChanges', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='block_height', full_name='org.dash.platform.dapi.v0.BlockNullifierChanges.block_height', index=0, + number=1, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=b'0\001', file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='nullifiers', full_name='org.dash.platform.dapi.v0.BlockNullifierChanges.nullifiers', index=1, + number=2, type=12, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=59799, + serialized_end=59868, +) + + +_NULLIFIERUPDATEENTRIES = _descriptor.Descriptor( + name='NullifierUpdateEntries', + full_name='org.dash.platform.dapi.v0.NullifierUpdateEntries', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='block_changes', full_name='org.dash.platform.dapi.v0.NullifierUpdateEntries.block_changes', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=59870, + serialized_end=59967, +) + + +_GETRECENTNULLIFIERCHANGESREQUEST_GETRECENTNULLIFIERCHANGESREQUESTV0 = _descriptor.Descriptor( + name='GetRecentNullifierChangesRequestV0', + full_name='org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='start_height', full_name='org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.start_height', index=0, + number=1, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=b'0\001', file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='prove', full_name='org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.prove', index=1, + number=2, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=60116, + serialized_end=60193, +) + +_GETRECENTNULLIFIERCHANGESREQUEST = _descriptor.Descriptor( + name='GetRecentNullifierChangesRequest', + full_name='org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='v0', full_name='org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.v0', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETRECENTNULLIFIERCHANGESREQUEST_GETRECENTNULLIFIERCHANGESREQUESTV0, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='version', full_name='org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.version', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=59970, + serialized_end=60204, +) + + +_GETRECENTNULLIFIERCHANGESRESPONSE_GETRECENTNULLIFIERCHANGESRESPONSEV0 = _descriptor.Descriptor( + name='GetRecentNullifierChangesResponseV0', + full_name='org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='nullifier_update_entries', full_name='org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.nullifier_update_entries', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='proof', full_name='org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.proof', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='metadata', full_name='org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.metadata', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='result', full_name='org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.result', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=60357, + serialized_end=60605, +) + +_GETRECENTNULLIFIERCHANGESRESPONSE = _descriptor.Descriptor( + name='GetRecentNullifierChangesResponse', + full_name='org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='v0', full_name='org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.v0', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETRECENTNULLIFIERCHANGESRESPONSE_GETRECENTNULLIFIERCHANGESRESPONSEV0, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='version', full_name='org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.version', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=60207, + serialized_end=60616, +) + + +_COMPACTEDBLOCKNULLIFIERCHANGES = _descriptor.Descriptor( + name='CompactedBlockNullifierChanges', + full_name='org.dash.platform.dapi.v0.CompactedBlockNullifierChanges', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='start_block_height', full_name='org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.start_block_height', index=0, + number=1, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=b'0\001', file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='end_block_height', full_name='org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.end_block_height', index=1, + number=2, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=b'0\001', file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='nullifiers', full_name='org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.nullifiers', index=2, + number=3, type=12, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=60618, + serialized_end=60732, +) + + +_COMPACTEDNULLIFIERUPDATEENTRIES = _descriptor.Descriptor( + name='CompactedNullifierUpdateEntries', + full_name='org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='compacted_block_changes', full_name='org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.compacted_block_changes', index=0, + number=1, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=60734, + serialized_end=60859, +) + + +_GETRECENTCOMPACTEDNULLIFIERCHANGESREQUEST_GETRECENTCOMPACTEDNULLIFIERCHANGESREQUESTV0 = _descriptor.Descriptor( + name='GetRecentCompactedNullifierChangesRequestV0', + full_name='org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='start_block_height', full_name='org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.start_block_height', index=0, + number=1, type=4, cpp_type=4, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=b'0\001', file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='prove', full_name='org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.prove', index=1, + number=2, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=61035, + serialized_end=61127, +) + +_GETRECENTCOMPACTEDNULLIFIERCHANGESREQUEST = _descriptor.Descriptor( + name='GetRecentCompactedNullifierChangesRequest', + full_name='org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='v0', full_name='org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.v0', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETRECENTCOMPACTEDNULLIFIERCHANGESREQUEST_GETRECENTCOMPACTEDNULLIFIERCHANGESREQUESTV0, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='version', full_name='org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.version', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=60862, + serialized_end=61138, +) + + +_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSEV0 = _descriptor.Descriptor( + name='GetRecentCompactedNullifierChangesResponseV0', + full_name='org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='compacted_nullifier_update_entries', full_name='org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.compacted_nullifier_update_entries', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='proof', full_name='org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.proof', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='metadata', full_name='org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.metadata', index=2, + number=3, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='result', full_name='org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.result', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=61319, + serialized_end=61595, +) + +_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE = _descriptor.Descriptor( + name='GetRecentCompactedNullifierChangesResponse', + full_name='org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='v0', full_name='org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.v0', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSEV0, ], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + _descriptor.OneofDescriptor( + name='version', full_name='org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.version', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + ], + serialized_start=61141, + serialized_end=61606, +) + _GETIDENTITYREQUEST_GETIDENTITYREQUESTV0.containing_type = _GETIDENTITYREQUEST _GETIDENTITYREQUEST.fields_by_name['v0'].message_type = _GETIDENTITYREQUEST_GETIDENTITYREQUESTV0 _GETIDENTITYREQUEST.oneofs_by_name['version'].fields.append( @@ -17041,6 +17828,68 @@ _GETSHIELDEDNULLIFIERSRESPONSE.oneofs_by_name['version'].fields.append( _GETSHIELDEDNULLIFIERSRESPONSE.fields_by_name['v0']) _GETSHIELDEDNULLIFIERSRESPONSE.fields_by_name['v0'].containing_oneof = _GETSHIELDEDNULLIFIERSRESPONSE.oneofs_by_name['version'] +_GETNULLIFIERSTRUNKSTATEREQUEST_GETNULLIFIERSTRUNKSTATEREQUESTV0.containing_type = _GETNULLIFIERSTRUNKSTATEREQUEST +_GETNULLIFIERSTRUNKSTATEREQUEST.fields_by_name['v0'].message_type = _GETNULLIFIERSTRUNKSTATEREQUEST_GETNULLIFIERSTRUNKSTATEREQUESTV0 +_GETNULLIFIERSTRUNKSTATEREQUEST.oneofs_by_name['version'].fields.append( + _GETNULLIFIERSTRUNKSTATEREQUEST.fields_by_name['v0']) +_GETNULLIFIERSTRUNKSTATEREQUEST.fields_by_name['v0'].containing_oneof = _GETNULLIFIERSTRUNKSTATEREQUEST.oneofs_by_name['version'] +_GETNULLIFIERSTRUNKSTATERESPONSE_GETNULLIFIERSTRUNKSTATERESPONSEV0.fields_by_name['proof'].message_type = _PROOF +_GETNULLIFIERSTRUNKSTATERESPONSE_GETNULLIFIERSTRUNKSTATERESPONSEV0.fields_by_name['metadata'].message_type = _RESPONSEMETADATA +_GETNULLIFIERSTRUNKSTATERESPONSE_GETNULLIFIERSTRUNKSTATERESPONSEV0.containing_type = _GETNULLIFIERSTRUNKSTATERESPONSE +_GETNULLIFIERSTRUNKSTATERESPONSE.fields_by_name['v0'].message_type = _GETNULLIFIERSTRUNKSTATERESPONSE_GETNULLIFIERSTRUNKSTATERESPONSEV0 +_GETNULLIFIERSTRUNKSTATERESPONSE.oneofs_by_name['version'].fields.append( + _GETNULLIFIERSTRUNKSTATERESPONSE.fields_by_name['v0']) +_GETNULLIFIERSTRUNKSTATERESPONSE.fields_by_name['v0'].containing_oneof = _GETNULLIFIERSTRUNKSTATERESPONSE.oneofs_by_name['version'] +_GETNULLIFIERSBRANCHSTATEREQUEST_GETNULLIFIERSBRANCHSTATEREQUESTV0.containing_type = _GETNULLIFIERSBRANCHSTATEREQUEST +_GETNULLIFIERSBRANCHSTATEREQUEST.fields_by_name['v0'].message_type = _GETNULLIFIERSBRANCHSTATEREQUEST_GETNULLIFIERSBRANCHSTATEREQUESTV0 +_GETNULLIFIERSBRANCHSTATEREQUEST.oneofs_by_name['version'].fields.append( + _GETNULLIFIERSBRANCHSTATEREQUEST.fields_by_name['v0']) +_GETNULLIFIERSBRANCHSTATEREQUEST.fields_by_name['v0'].containing_oneof = _GETNULLIFIERSBRANCHSTATEREQUEST.oneofs_by_name['version'] +_GETNULLIFIERSBRANCHSTATERESPONSE_GETNULLIFIERSBRANCHSTATERESPONSEV0.containing_type = _GETNULLIFIERSBRANCHSTATERESPONSE +_GETNULLIFIERSBRANCHSTATERESPONSE.fields_by_name['v0'].message_type = _GETNULLIFIERSBRANCHSTATERESPONSE_GETNULLIFIERSBRANCHSTATERESPONSEV0 +_GETNULLIFIERSBRANCHSTATERESPONSE.oneofs_by_name['version'].fields.append( + _GETNULLIFIERSBRANCHSTATERESPONSE.fields_by_name['v0']) +_GETNULLIFIERSBRANCHSTATERESPONSE.fields_by_name['v0'].containing_oneof = _GETNULLIFIERSBRANCHSTATERESPONSE.oneofs_by_name['version'] +_NULLIFIERUPDATEENTRIES.fields_by_name['block_changes'].message_type = _BLOCKNULLIFIERCHANGES +_GETRECENTNULLIFIERCHANGESREQUEST_GETRECENTNULLIFIERCHANGESREQUESTV0.containing_type = _GETRECENTNULLIFIERCHANGESREQUEST +_GETRECENTNULLIFIERCHANGESREQUEST.fields_by_name['v0'].message_type = _GETRECENTNULLIFIERCHANGESREQUEST_GETRECENTNULLIFIERCHANGESREQUESTV0 +_GETRECENTNULLIFIERCHANGESREQUEST.oneofs_by_name['version'].fields.append( + _GETRECENTNULLIFIERCHANGESREQUEST.fields_by_name['v0']) +_GETRECENTNULLIFIERCHANGESREQUEST.fields_by_name['v0'].containing_oneof = _GETRECENTNULLIFIERCHANGESREQUEST.oneofs_by_name['version'] +_GETRECENTNULLIFIERCHANGESRESPONSE_GETRECENTNULLIFIERCHANGESRESPONSEV0.fields_by_name['nullifier_update_entries'].message_type = _NULLIFIERUPDATEENTRIES +_GETRECENTNULLIFIERCHANGESRESPONSE_GETRECENTNULLIFIERCHANGESRESPONSEV0.fields_by_name['proof'].message_type = _PROOF +_GETRECENTNULLIFIERCHANGESRESPONSE_GETRECENTNULLIFIERCHANGESRESPONSEV0.fields_by_name['metadata'].message_type = _RESPONSEMETADATA +_GETRECENTNULLIFIERCHANGESRESPONSE_GETRECENTNULLIFIERCHANGESRESPONSEV0.containing_type = _GETRECENTNULLIFIERCHANGESRESPONSE +_GETRECENTNULLIFIERCHANGESRESPONSE_GETRECENTNULLIFIERCHANGESRESPONSEV0.oneofs_by_name['result'].fields.append( + _GETRECENTNULLIFIERCHANGESRESPONSE_GETRECENTNULLIFIERCHANGESRESPONSEV0.fields_by_name['nullifier_update_entries']) +_GETRECENTNULLIFIERCHANGESRESPONSE_GETRECENTNULLIFIERCHANGESRESPONSEV0.fields_by_name['nullifier_update_entries'].containing_oneof = _GETRECENTNULLIFIERCHANGESRESPONSE_GETRECENTNULLIFIERCHANGESRESPONSEV0.oneofs_by_name['result'] +_GETRECENTNULLIFIERCHANGESRESPONSE_GETRECENTNULLIFIERCHANGESRESPONSEV0.oneofs_by_name['result'].fields.append( + _GETRECENTNULLIFIERCHANGESRESPONSE_GETRECENTNULLIFIERCHANGESRESPONSEV0.fields_by_name['proof']) +_GETRECENTNULLIFIERCHANGESRESPONSE_GETRECENTNULLIFIERCHANGESRESPONSEV0.fields_by_name['proof'].containing_oneof = _GETRECENTNULLIFIERCHANGESRESPONSE_GETRECENTNULLIFIERCHANGESRESPONSEV0.oneofs_by_name['result'] +_GETRECENTNULLIFIERCHANGESRESPONSE.fields_by_name['v0'].message_type = _GETRECENTNULLIFIERCHANGESRESPONSE_GETRECENTNULLIFIERCHANGESRESPONSEV0 +_GETRECENTNULLIFIERCHANGESRESPONSE.oneofs_by_name['version'].fields.append( + _GETRECENTNULLIFIERCHANGESRESPONSE.fields_by_name['v0']) +_GETRECENTNULLIFIERCHANGESRESPONSE.fields_by_name['v0'].containing_oneof = _GETRECENTNULLIFIERCHANGESRESPONSE.oneofs_by_name['version'] +_COMPACTEDNULLIFIERUPDATEENTRIES.fields_by_name['compacted_block_changes'].message_type = _COMPACTEDBLOCKNULLIFIERCHANGES +_GETRECENTCOMPACTEDNULLIFIERCHANGESREQUEST_GETRECENTCOMPACTEDNULLIFIERCHANGESREQUESTV0.containing_type = _GETRECENTCOMPACTEDNULLIFIERCHANGESREQUEST +_GETRECENTCOMPACTEDNULLIFIERCHANGESREQUEST.fields_by_name['v0'].message_type = _GETRECENTCOMPACTEDNULLIFIERCHANGESREQUEST_GETRECENTCOMPACTEDNULLIFIERCHANGESREQUESTV0 +_GETRECENTCOMPACTEDNULLIFIERCHANGESREQUEST.oneofs_by_name['version'].fields.append( + _GETRECENTCOMPACTEDNULLIFIERCHANGESREQUEST.fields_by_name['v0']) +_GETRECENTCOMPACTEDNULLIFIERCHANGESREQUEST.fields_by_name['v0'].containing_oneof = _GETRECENTCOMPACTEDNULLIFIERCHANGESREQUEST.oneofs_by_name['version'] +_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSEV0.fields_by_name['compacted_nullifier_update_entries'].message_type = _COMPACTEDNULLIFIERUPDATEENTRIES +_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSEV0.fields_by_name['proof'].message_type = _PROOF +_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSEV0.fields_by_name['metadata'].message_type = _RESPONSEMETADATA +_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSEV0.containing_type = _GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE +_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSEV0.oneofs_by_name['result'].fields.append( + _GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSEV0.fields_by_name['compacted_nullifier_update_entries']) +_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSEV0.fields_by_name['compacted_nullifier_update_entries'].containing_oneof = _GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSEV0.oneofs_by_name['result'] +_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSEV0.oneofs_by_name['result'].fields.append( + _GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSEV0.fields_by_name['proof']) +_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSEV0.fields_by_name['proof'].containing_oneof = _GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSEV0.oneofs_by_name['result'] +_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE.fields_by_name['v0'].message_type = _GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSEV0 +_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE.oneofs_by_name['version'].fields.append( + _GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE.fields_by_name['v0']) +_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE.fields_by_name['v0'].containing_oneof = _GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE.oneofs_by_name['version'] DESCRIPTOR.message_types_by_name['Proof'] = _PROOF DESCRIPTOR.message_types_by_name['ResponseMetadata'] = _RESPONSEMETADATA DESCRIPTOR.message_types_by_name['StateTransitionBroadcastError'] = _STATETRANSITIONBROADCASTERROR @@ -17173,6 +18022,18 @@ DESCRIPTOR.message_types_by_name['GetShieldedPoolStateResponse'] = _GETSHIELDEDPOOLSTATERESPONSE DESCRIPTOR.message_types_by_name['GetShieldedNullifiersRequest'] = _GETSHIELDEDNULLIFIERSREQUEST DESCRIPTOR.message_types_by_name['GetShieldedNullifiersResponse'] = _GETSHIELDEDNULLIFIERSRESPONSE +DESCRIPTOR.message_types_by_name['GetNullifiersTrunkStateRequest'] = _GETNULLIFIERSTRUNKSTATEREQUEST +DESCRIPTOR.message_types_by_name['GetNullifiersTrunkStateResponse'] = _GETNULLIFIERSTRUNKSTATERESPONSE +DESCRIPTOR.message_types_by_name['GetNullifiersBranchStateRequest'] = _GETNULLIFIERSBRANCHSTATEREQUEST +DESCRIPTOR.message_types_by_name['GetNullifiersBranchStateResponse'] = _GETNULLIFIERSBRANCHSTATERESPONSE +DESCRIPTOR.message_types_by_name['BlockNullifierChanges'] = _BLOCKNULLIFIERCHANGES +DESCRIPTOR.message_types_by_name['NullifierUpdateEntries'] = _NULLIFIERUPDATEENTRIES +DESCRIPTOR.message_types_by_name['GetRecentNullifierChangesRequest'] = _GETRECENTNULLIFIERCHANGESREQUEST +DESCRIPTOR.message_types_by_name['GetRecentNullifierChangesResponse'] = _GETRECENTNULLIFIERCHANGESRESPONSE +DESCRIPTOR.message_types_by_name['CompactedBlockNullifierChanges'] = _COMPACTEDBLOCKNULLIFIERCHANGES +DESCRIPTOR.message_types_by_name['CompactedNullifierUpdateEntries'] = _COMPACTEDNULLIFIERUPDATEENTRIES +DESCRIPTOR.message_types_by_name['GetRecentCompactedNullifierChangesRequest'] = _GETRECENTCOMPACTEDNULLIFIERCHANGESREQUEST +DESCRIPTOR.message_types_by_name['GetRecentCompactedNullifierChangesResponse'] = _GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE DESCRIPTOR.enum_types_by_name['KeyPurpose'] = _KEYPURPOSE _sym_db.RegisterFileDescriptor(DESCRIPTOR) @@ -19924,6 +20785,154 @@ _sym_db.RegisterMessage(GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatus) _sym_db.RegisterMessage(GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses) +GetNullifiersTrunkStateRequest = _reflection.GeneratedProtocolMessageType('GetNullifiersTrunkStateRequest', (_message.Message,), { + + 'GetNullifiersTrunkStateRequestV0' : _reflection.GeneratedProtocolMessageType('GetNullifiersTrunkStateRequestV0', (_message.Message,), { + 'DESCRIPTOR' : _GETNULLIFIERSTRUNKSTATEREQUEST_GETNULLIFIERSTRUNKSTATEREQUESTV0, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0) + }) + , + 'DESCRIPTOR' : _GETNULLIFIERSTRUNKSTATEREQUEST, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest) + }) +_sym_db.RegisterMessage(GetNullifiersTrunkStateRequest) +_sym_db.RegisterMessage(GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0) + +GetNullifiersTrunkStateResponse = _reflection.GeneratedProtocolMessageType('GetNullifiersTrunkStateResponse', (_message.Message,), { + + 'GetNullifiersTrunkStateResponseV0' : _reflection.GeneratedProtocolMessageType('GetNullifiersTrunkStateResponseV0', (_message.Message,), { + 'DESCRIPTOR' : _GETNULLIFIERSTRUNKSTATERESPONSE_GETNULLIFIERSTRUNKSTATERESPONSEV0, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0) + }) + , + 'DESCRIPTOR' : _GETNULLIFIERSTRUNKSTATERESPONSE, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse) + }) +_sym_db.RegisterMessage(GetNullifiersTrunkStateResponse) +_sym_db.RegisterMessage(GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0) + +GetNullifiersBranchStateRequest = _reflection.GeneratedProtocolMessageType('GetNullifiersBranchStateRequest', (_message.Message,), { + + 'GetNullifiersBranchStateRequestV0' : _reflection.GeneratedProtocolMessageType('GetNullifiersBranchStateRequestV0', (_message.Message,), { + 'DESCRIPTOR' : _GETNULLIFIERSBRANCHSTATEREQUEST_GETNULLIFIERSBRANCHSTATEREQUESTV0, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0) + }) + , + 'DESCRIPTOR' : _GETNULLIFIERSBRANCHSTATEREQUEST, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest) + }) +_sym_db.RegisterMessage(GetNullifiersBranchStateRequest) +_sym_db.RegisterMessage(GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0) + +GetNullifiersBranchStateResponse = _reflection.GeneratedProtocolMessageType('GetNullifiersBranchStateResponse', (_message.Message,), { + + 'GetNullifiersBranchStateResponseV0' : _reflection.GeneratedProtocolMessageType('GetNullifiersBranchStateResponseV0', (_message.Message,), { + 'DESCRIPTOR' : _GETNULLIFIERSBRANCHSTATERESPONSE_GETNULLIFIERSBRANCHSTATERESPONSEV0, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0) + }) + , + 'DESCRIPTOR' : _GETNULLIFIERSBRANCHSTATERESPONSE, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse) + }) +_sym_db.RegisterMessage(GetNullifiersBranchStateResponse) +_sym_db.RegisterMessage(GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0) + +BlockNullifierChanges = _reflection.GeneratedProtocolMessageType('BlockNullifierChanges', (_message.Message,), { + 'DESCRIPTOR' : _BLOCKNULLIFIERCHANGES, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.BlockNullifierChanges) + }) +_sym_db.RegisterMessage(BlockNullifierChanges) + +NullifierUpdateEntries = _reflection.GeneratedProtocolMessageType('NullifierUpdateEntries', (_message.Message,), { + 'DESCRIPTOR' : _NULLIFIERUPDATEENTRIES, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.NullifierUpdateEntries) + }) +_sym_db.RegisterMessage(NullifierUpdateEntries) + +GetRecentNullifierChangesRequest = _reflection.GeneratedProtocolMessageType('GetRecentNullifierChangesRequest', (_message.Message,), { + + 'GetRecentNullifierChangesRequestV0' : _reflection.GeneratedProtocolMessageType('GetRecentNullifierChangesRequestV0', (_message.Message,), { + 'DESCRIPTOR' : _GETRECENTNULLIFIERCHANGESREQUEST_GETRECENTNULLIFIERCHANGESREQUESTV0, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0) + }) + , + 'DESCRIPTOR' : _GETRECENTNULLIFIERCHANGESREQUEST, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest) + }) +_sym_db.RegisterMessage(GetRecentNullifierChangesRequest) +_sym_db.RegisterMessage(GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0) + +GetRecentNullifierChangesResponse = _reflection.GeneratedProtocolMessageType('GetRecentNullifierChangesResponse', (_message.Message,), { + + 'GetRecentNullifierChangesResponseV0' : _reflection.GeneratedProtocolMessageType('GetRecentNullifierChangesResponseV0', (_message.Message,), { + 'DESCRIPTOR' : _GETRECENTNULLIFIERCHANGESRESPONSE_GETRECENTNULLIFIERCHANGESRESPONSEV0, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0) + }) + , + 'DESCRIPTOR' : _GETRECENTNULLIFIERCHANGESRESPONSE, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse) + }) +_sym_db.RegisterMessage(GetRecentNullifierChangesResponse) +_sym_db.RegisterMessage(GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0) + +CompactedBlockNullifierChanges = _reflection.GeneratedProtocolMessageType('CompactedBlockNullifierChanges', (_message.Message,), { + 'DESCRIPTOR' : _COMPACTEDBLOCKNULLIFIERCHANGES, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.CompactedBlockNullifierChanges) + }) +_sym_db.RegisterMessage(CompactedBlockNullifierChanges) + +CompactedNullifierUpdateEntries = _reflection.GeneratedProtocolMessageType('CompactedNullifierUpdateEntries', (_message.Message,), { + 'DESCRIPTOR' : _COMPACTEDNULLIFIERUPDATEENTRIES, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries) + }) +_sym_db.RegisterMessage(CompactedNullifierUpdateEntries) + +GetRecentCompactedNullifierChangesRequest = _reflection.GeneratedProtocolMessageType('GetRecentCompactedNullifierChangesRequest', (_message.Message,), { + + 'GetRecentCompactedNullifierChangesRequestV0' : _reflection.GeneratedProtocolMessageType('GetRecentCompactedNullifierChangesRequestV0', (_message.Message,), { + 'DESCRIPTOR' : _GETRECENTCOMPACTEDNULLIFIERCHANGESREQUEST_GETRECENTCOMPACTEDNULLIFIERCHANGESREQUESTV0, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0) + }) + , + 'DESCRIPTOR' : _GETRECENTCOMPACTEDNULLIFIERCHANGESREQUEST, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest) + }) +_sym_db.RegisterMessage(GetRecentCompactedNullifierChangesRequest) +_sym_db.RegisterMessage(GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0) + +GetRecentCompactedNullifierChangesResponse = _reflection.GeneratedProtocolMessageType('GetRecentCompactedNullifierChangesResponse', (_message.Message,), { + + 'GetRecentCompactedNullifierChangesResponseV0' : _reflection.GeneratedProtocolMessageType('GetRecentCompactedNullifierChangesResponseV0', (_message.Message,), { + 'DESCRIPTOR' : _GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSEV0, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0) + }) + , + 'DESCRIPTOR' : _GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE, + '__module__' : 'platform_pb2' + # @@protoc_insertion_point(class_scope:org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse) + }) +_sym_db.RegisterMessage(GetRecentCompactedNullifierChangesResponse) +_sym_db.RegisterMessage(GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0) + _RESPONSEMETADATA.fields_by_name['height']._options = None _RESPONSEMETADATA.fields_by_name['time_ms']._options = None @@ -19980,6 +20989,11 @@ _COMPACTEDBLOCKADDRESSBALANCECHANGES.fields_by_name['end_block_height']._options = None _GETRECENTCOMPACTEDADDRESSBALANCECHANGESREQUEST_GETRECENTCOMPACTEDADDRESSBALANCECHANGESREQUESTV0.fields_by_name['start_block_height']._options = None _GETSHIELDEDPOOLSTATERESPONSE_GETSHIELDEDPOOLSTATERESPONSEV0.fields_by_name['total_balance']._options = None +_BLOCKNULLIFIERCHANGES.fields_by_name['block_height']._options = None +_GETRECENTNULLIFIERCHANGESREQUEST_GETRECENTNULLIFIERCHANGESREQUESTV0.fields_by_name['start_height']._options = None +_COMPACTEDBLOCKNULLIFIERCHANGES.fields_by_name['start_block_height']._options = None +_COMPACTEDBLOCKNULLIFIERCHANGES.fields_by_name['end_block_height']._options = None +_GETRECENTCOMPACTEDNULLIFIERCHANGESREQUEST_GETRECENTCOMPACTEDNULLIFIERCHANGESREQUESTV0.fields_by_name['start_block_height']._options = None _PLATFORM = _descriptor.ServiceDescriptor( name='Platform', @@ -19988,8 +21002,8 @@ index=0, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=58847, - serialized_end=67197, + serialized_start=61701, + serialized_end=70681, methods=[ _descriptor.MethodDescriptor( name='broadcastStateTransition', @@ -20561,6 +21575,46 @@ serialized_options=None, create_key=_descriptor._internal_create_key, ), + _descriptor.MethodDescriptor( + name='getNullifiersTrunkState', + full_name='org.dash.platform.dapi.v0.Platform.getNullifiersTrunkState', + index=57, + containing_service=None, + input_type=_GETNULLIFIERSTRUNKSTATEREQUEST, + output_type=_GETNULLIFIERSTRUNKSTATERESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='getNullifiersBranchState', + full_name='org.dash.platform.dapi.v0.Platform.getNullifiersBranchState', + index=58, + containing_service=None, + input_type=_GETNULLIFIERSBRANCHSTATEREQUEST, + output_type=_GETNULLIFIERSBRANCHSTATERESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='getRecentNullifierChanges', + full_name='org.dash.platform.dapi.v0.Platform.getRecentNullifierChanges', + index=59, + containing_service=None, + input_type=_GETRECENTNULLIFIERCHANGESREQUEST, + output_type=_GETRECENTNULLIFIERCHANGESRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='getRecentCompactedNullifierChanges', + full_name='org.dash.platform.dapi.v0.Platform.getRecentCompactedNullifierChanges', + index=60, + containing_service=None, + input_type=_GETRECENTCOMPACTEDNULLIFIERCHANGESREQUEST, + output_type=_GETRECENTCOMPACTEDNULLIFIERCHANGESRESPONSE, + serialized_options=None, + create_key=_descriptor._internal_create_key, + ), ]) _sym_db.RegisterServiceDescriptor(_PLATFORM) diff --git a/packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py b/packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py index 47dcf5b6802..44e720d97f9 100644 --- a/packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py +++ b/packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py @@ -299,6 +299,26 @@ def __init__(self, channel): request_serializer=platform__pb2.GetShieldedNullifiersRequest.SerializeToString, response_deserializer=platform__pb2.GetShieldedNullifiersResponse.FromString, ) + self.getNullifiersTrunkState = channel.unary_unary( + '/org.dash.platform.dapi.v0.Platform/getNullifiersTrunkState', + request_serializer=platform__pb2.GetNullifiersTrunkStateRequest.SerializeToString, + response_deserializer=platform__pb2.GetNullifiersTrunkStateResponse.FromString, + ) + self.getNullifiersBranchState = channel.unary_unary( + '/org.dash.platform.dapi.v0.Platform/getNullifiersBranchState', + request_serializer=platform__pb2.GetNullifiersBranchStateRequest.SerializeToString, + response_deserializer=platform__pb2.GetNullifiersBranchStateResponse.FromString, + ) + self.getRecentNullifierChanges = channel.unary_unary( + '/org.dash.platform.dapi.v0.Platform/getRecentNullifierChanges', + request_serializer=platform__pb2.GetRecentNullifierChangesRequest.SerializeToString, + response_deserializer=platform__pb2.GetRecentNullifierChangesResponse.FromString, + ) + self.getRecentCompactedNullifierChanges = channel.unary_unary( + '/org.dash.platform.dapi.v0.Platform/getRecentCompactedNullifierChanges', + request_serializer=platform__pb2.GetRecentCompactedNullifierChangesRequest.SerializeToString, + response_deserializer=platform__pb2.GetRecentCompactedNullifierChangesResponse.FromString, + ) class PlatformServicer(object): @@ -651,6 +671,30 @@ def getShieldedNullifiers(self, request, context): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def getNullifiersTrunkState(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def getNullifiersBranchState(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def getRecentNullifierChanges(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def getRecentCompactedNullifierChanges(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def add_PlatformServicer_to_server(servicer, server): rpc_method_handlers = { @@ -939,6 +983,26 @@ def add_PlatformServicer_to_server(servicer, server): request_deserializer=platform__pb2.GetShieldedNullifiersRequest.FromString, response_serializer=platform__pb2.GetShieldedNullifiersResponse.SerializeToString, ), + 'getNullifiersTrunkState': grpc.unary_unary_rpc_method_handler( + servicer.getNullifiersTrunkState, + request_deserializer=platform__pb2.GetNullifiersTrunkStateRequest.FromString, + response_serializer=platform__pb2.GetNullifiersTrunkStateResponse.SerializeToString, + ), + 'getNullifiersBranchState': grpc.unary_unary_rpc_method_handler( + servicer.getNullifiersBranchState, + request_deserializer=platform__pb2.GetNullifiersBranchStateRequest.FromString, + response_serializer=platform__pb2.GetNullifiersBranchStateResponse.SerializeToString, + ), + 'getRecentNullifierChanges': grpc.unary_unary_rpc_method_handler( + servicer.getRecentNullifierChanges, + request_deserializer=platform__pb2.GetRecentNullifierChangesRequest.FromString, + response_serializer=platform__pb2.GetRecentNullifierChangesResponse.SerializeToString, + ), + 'getRecentCompactedNullifierChanges': grpc.unary_unary_rpc_method_handler( + servicer.getRecentCompactedNullifierChanges, + request_deserializer=platform__pb2.GetRecentCompactedNullifierChangesRequest.FromString, + response_serializer=platform__pb2.GetRecentCompactedNullifierChangesResponse.SerializeToString, + ), } generic_handler = grpc.method_handlers_generic_handler( 'org.dash.platform.dapi.v0.Platform', rpc_method_handlers) @@ -1917,3 +1981,71 @@ def getShieldedNullifiers(request, platform__pb2.GetShieldedNullifiersResponse.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def getNullifiersTrunkState(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/org.dash.platform.dapi.v0.Platform/getNullifiersTrunkState', + platform__pb2.GetNullifiersTrunkStateRequest.SerializeToString, + platform__pb2.GetNullifiersTrunkStateResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def getNullifiersBranchState(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/org.dash.platform.dapi.v0.Platform/getNullifiersBranchState', + platform__pb2.GetNullifiersBranchStateRequest.SerializeToString, + platform__pb2.GetNullifiersBranchStateResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def getRecentNullifierChanges(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/org.dash.platform.dapi.v0.Platform/getRecentNullifierChanges', + platform__pb2.GetRecentNullifierChangesRequest.SerializeToString, + platform__pb2.GetRecentNullifierChangesResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def getRecentCompactedNullifierChanges(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/org.dash.platform.dapi.v0.Platform/getRecentCompactedNullifierChanges', + platform__pb2.GetRecentCompactedNullifierChangesRequest.SerializeToString, + platform__pb2.GetRecentCompactedNullifierChangesResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts b/packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts index 39802f2f414..13f08ba90ca 100644 --- a/packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts +++ b/packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts @@ -11114,6 +11114,580 @@ export namespace GetShieldedNullifiersResponse { } } +export class GetNullifiersTrunkStateRequest extends jspb.Message { + hasV0(): boolean; + clearV0(): void; + getV0(): GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 | undefined; + setV0(value?: GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0): void; + + getVersionCase(): GetNullifiersTrunkStateRequest.VersionCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetNullifiersTrunkStateRequest.AsObject; + static toObject(includeInstance: boolean, msg: GetNullifiersTrunkStateRequest): GetNullifiersTrunkStateRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetNullifiersTrunkStateRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetNullifiersTrunkStateRequest; + static deserializeBinaryFromReader(message: GetNullifiersTrunkStateRequest, reader: jspb.BinaryReader): GetNullifiersTrunkStateRequest; +} + +export namespace GetNullifiersTrunkStateRequest { + export type AsObject = { + v0?: GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.AsObject, + } + + export class GetNullifiersTrunkStateRequestV0 extends jspb.Message { + getPoolType(): number; + setPoolType(value: number): void; + + getPoolIdentifier(): Uint8Array | string; + getPoolIdentifier_asU8(): Uint8Array; + getPoolIdentifier_asB64(): string; + setPoolIdentifier(value: Uint8Array | string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetNullifiersTrunkStateRequestV0.AsObject; + static toObject(includeInstance: boolean, msg: GetNullifiersTrunkStateRequestV0): GetNullifiersTrunkStateRequestV0.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetNullifiersTrunkStateRequestV0, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetNullifiersTrunkStateRequestV0; + static deserializeBinaryFromReader(message: GetNullifiersTrunkStateRequestV0, reader: jspb.BinaryReader): GetNullifiersTrunkStateRequestV0; + } + + export namespace GetNullifiersTrunkStateRequestV0 { + export type AsObject = { + poolType: number, + poolIdentifier: Uint8Array | string, + } + } + + export enum VersionCase { + VERSION_NOT_SET = 0, + V0 = 1, + } +} + +export class GetNullifiersTrunkStateResponse extends jspb.Message { + hasV0(): boolean; + clearV0(): void; + getV0(): GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 | undefined; + setV0(value?: GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0): void; + + getVersionCase(): GetNullifiersTrunkStateResponse.VersionCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetNullifiersTrunkStateResponse.AsObject; + static toObject(includeInstance: boolean, msg: GetNullifiersTrunkStateResponse): GetNullifiersTrunkStateResponse.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetNullifiersTrunkStateResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetNullifiersTrunkStateResponse; + static deserializeBinaryFromReader(message: GetNullifiersTrunkStateResponse, reader: jspb.BinaryReader): GetNullifiersTrunkStateResponse; +} + +export namespace GetNullifiersTrunkStateResponse { + export type AsObject = { + v0?: GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.AsObject, + } + + export class GetNullifiersTrunkStateResponseV0 extends jspb.Message { + hasProof(): boolean; + clearProof(): void; + getProof(): Proof | undefined; + setProof(value?: Proof): void; + + hasMetadata(): boolean; + clearMetadata(): void; + getMetadata(): ResponseMetadata | undefined; + setMetadata(value?: ResponseMetadata): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetNullifiersTrunkStateResponseV0.AsObject; + static toObject(includeInstance: boolean, msg: GetNullifiersTrunkStateResponseV0): GetNullifiersTrunkStateResponseV0.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetNullifiersTrunkStateResponseV0, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetNullifiersTrunkStateResponseV0; + static deserializeBinaryFromReader(message: GetNullifiersTrunkStateResponseV0, reader: jspb.BinaryReader): GetNullifiersTrunkStateResponseV0; + } + + export namespace GetNullifiersTrunkStateResponseV0 { + export type AsObject = { + proof?: Proof.AsObject, + metadata?: ResponseMetadata.AsObject, + } + } + + export enum VersionCase { + VERSION_NOT_SET = 0, + V0 = 1, + } +} + +export class GetNullifiersBranchStateRequest extends jspb.Message { + hasV0(): boolean; + clearV0(): void; + getV0(): GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 | undefined; + setV0(value?: GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0): void; + + getVersionCase(): GetNullifiersBranchStateRequest.VersionCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetNullifiersBranchStateRequest.AsObject; + static toObject(includeInstance: boolean, msg: GetNullifiersBranchStateRequest): GetNullifiersBranchStateRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetNullifiersBranchStateRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetNullifiersBranchStateRequest; + static deserializeBinaryFromReader(message: GetNullifiersBranchStateRequest, reader: jspb.BinaryReader): GetNullifiersBranchStateRequest; +} + +export namespace GetNullifiersBranchStateRequest { + export type AsObject = { + v0?: GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.AsObject, + } + + export class GetNullifiersBranchStateRequestV0 extends jspb.Message { + getPoolType(): number; + setPoolType(value: number): void; + + getPoolIdentifier(): Uint8Array | string; + getPoolIdentifier_asU8(): Uint8Array; + getPoolIdentifier_asB64(): string; + setPoolIdentifier(value: Uint8Array | string): void; + + getKey(): Uint8Array | string; + getKey_asU8(): Uint8Array; + getKey_asB64(): string; + setKey(value: Uint8Array | string): void; + + getDepth(): number; + setDepth(value: number): void; + + getCheckpointHeight(): number; + setCheckpointHeight(value: number): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetNullifiersBranchStateRequestV0.AsObject; + static toObject(includeInstance: boolean, msg: GetNullifiersBranchStateRequestV0): GetNullifiersBranchStateRequestV0.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetNullifiersBranchStateRequestV0, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetNullifiersBranchStateRequestV0; + static deserializeBinaryFromReader(message: GetNullifiersBranchStateRequestV0, reader: jspb.BinaryReader): GetNullifiersBranchStateRequestV0; + } + + export namespace GetNullifiersBranchStateRequestV0 { + export type AsObject = { + poolType: number, + poolIdentifier: Uint8Array | string, + key: Uint8Array | string, + depth: number, + checkpointHeight: number, + } + } + + export enum VersionCase { + VERSION_NOT_SET = 0, + V0 = 1, + } +} + +export class GetNullifiersBranchStateResponse extends jspb.Message { + hasV0(): boolean; + clearV0(): void; + getV0(): GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 | undefined; + setV0(value?: GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0): void; + + getVersionCase(): GetNullifiersBranchStateResponse.VersionCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetNullifiersBranchStateResponse.AsObject; + static toObject(includeInstance: boolean, msg: GetNullifiersBranchStateResponse): GetNullifiersBranchStateResponse.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetNullifiersBranchStateResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetNullifiersBranchStateResponse; + static deserializeBinaryFromReader(message: GetNullifiersBranchStateResponse, reader: jspb.BinaryReader): GetNullifiersBranchStateResponse; +} + +export namespace GetNullifiersBranchStateResponse { + export type AsObject = { + v0?: GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.AsObject, + } + + export class GetNullifiersBranchStateResponseV0 extends jspb.Message { + getMerkProof(): Uint8Array | string; + getMerkProof_asU8(): Uint8Array; + getMerkProof_asB64(): string; + setMerkProof(value: Uint8Array | string): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetNullifiersBranchStateResponseV0.AsObject; + static toObject(includeInstance: boolean, msg: GetNullifiersBranchStateResponseV0): GetNullifiersBranchStateResponseV0.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetNullifiersBranchStateResponseV0, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetNullifiersBranchStateResponseV0; + static deserializeBinaryFromReader(message: GetNullifiersBranchStateResponseV0, reader: jspb.BinaryReader): GetNullifiersBranchStateResponseV0; + } + + export namespace GetNullifiersBranchStateResponseV0 { + export type AsObject = { + merkProof: Uint8Array | string, + } + } + + export enum VersionCase { + VERSION_NOT_SET = 0, + V0 = 1, + } +} + +export class BlockNullifierChanges extends jspb.Message { + getBlockHeight(): string; + setBlockHeight(value: string): void; + + clearNullifiersList(): void; + getNullifiersList(): Array; + getNullifiersList_asU8(): Array; + getNullifiersList_asB64(): Array; + setNullifiersList(value: Array): void; + addNullifiers(value: Uint8Array | string, index?: number): Uint8Array | string; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): BlockNullifierChanges.AsObject; + static toObject(includeInstance: boolean, msg: BlockNullifierChanges): BlockNullifierChanges.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: BlockNullifierChanges, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): BlockNullifierChanges; + static deserializeBinaryFromReader(message: BlockNullifierChanges, reader: jspb.BinaryReader): BlockNullifierChanges; +} + +export namespace BlockNullifierChanges { + export type AsObject = { + blockHeight: string, + nullifiersList: Array, + } +} + +export class NullifierUpdateEntries extends jspb.Message { + clearBlockChangesList(): void; + getBlockChangesList(): Array; + setBlockChangesList(value: Array): void; + addBlockChanges(value?: BlockNullifierChanges, index?: number): BlockNullifierChanges; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): NullifierUpdateEntries.AsObject; + static toObject(includeInstance: boolean, msg: NullifierUpdateEntries): NullifierUpdateEntries.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: NullifierUpdateEntries, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): NullifierUpdateEntries; + static deserializeBinaryFromReader(message: NullifierUpdateEntries, reader: jspb.BinaryReader): NullifierUpdateEntries; +} + +export namespace NullifierUpdateEntries { + export type AsObject = { + blockChangesList: Array, + } +} + +export class GetRecentNullifierChangesRequest extends jspb.Message { + hasV0(): boolean; + clearV0(): void; + getV0(): GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 | undefined; + setV0(value?: GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0): void; + + getVersionCase(): GetRecentNullifierChangesRequest.VersionCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetRecentNullifierChangesRequest.AsObject; + static toObject(includeInstance: boolean, msg: GetRecentNullifierChangesRequest): GetRecentNullifierChangesRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetRecentNullifierChangesRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetRecentNullifierChangesRequest; + static deserializeBinaryFromReader(message: GetRecentNullifierChangesRequest, reader: jspb.BinaryReader): GetRecentNullifierChangesRequest; +} + +export namespace GetRecentNullifierChangesRequest { + export type AsObject = { + v0?: GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.AsObject, + } + + export class GetRecentNullifierChangesRequestV0 extends jspb.Message { + getStartHeight(): string; + setStartHeight(value: string): void; + + getProve(): boolean; + setProve(value: boolean): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetRecentNullifierChangesRequestV0.AsObject; + static toObject(includeInstance: boolean, msg: GetRecentNullifierChangesRequestV0): GetRecentNullifierChangesRequestV0.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetRecentNullifierChangesRequestV0, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetRecentNullifierChangesRequestV0; + static deserializeBinaryFromReader(message: GetRecentNullifierChangesRequestV0, reader: jspb.BinaryReader): GetRecentNullifierChangesRequestV0; + } + + export namespace GetRecentNullifierChangesRequestV0 { + export type AsObject = { + startHeight: string, + prove: boolean, + } + } + + export enum VersionCase { + VERSION_NOT_SET = 0, + V0 = 1, + } +} + +export class GetRecentNullifierChangesResponse extends jspb.Message { + hasV0(): boolean; + clearV0(): void; + getV0(): GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 | undefined; + setV0(value?: GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0): void; + + getVersionCase(): GetRecentNullifierChangesResponse.VersionCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetRecentNullifierChangesResponse.AsObject; + static toObject(includeInstance: boolean, msg: GetRecentNullifierChangesResponse): GetRecentNullifierChangesResponse.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetRecentNullifierChangesResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetRecentNullifierChangesResponse; + static deserializeBinaryFromReader(message: GetRecentNullifierChangesResponse, reader: jspb.BinaryReader): GetRecentNullifierChangesResponse; +} + +export namespace GetRecentNullifierChangesResponse { + export type AsObject = { + v0?: GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.AsObject, + } + + export class GetRecentNullifierChangesResponseV0 extends jspb.Message { + hasNullifierUpdateEntries(): boolean; + clearNullifierUpdateEntries(): void; + getNullifierUpdateEntries(): NullifierUpdateEntries | undefined; + setNullifierUpdateEntries(value?: NullifierUpdateEntries): void; + + hasProof(): boolean; + clearProof(): void; + getProof(): Proof | undefined; + setProof(value?: Proof): void; + + hasMetadata(): boolean; + clearMetadata(): void; + getMetadata(): ResponseMetadata | undefined; + setMetadata(value?: ResponseMetadata): void; + + getResultCase(): GetRecentNullifierChangesResponseV0.ResultCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetRecentNullifierChangesResponseV0.AsObject; + static toObject(includeInstance: boolean, msg: GetRecentNullifierChangesResponseV0): GetRecentNullifierChangesResponseV0.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetRecentNullifierChangesResponseV0, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetRecentNullifierChangesResponseV0; + static deserializeBinaryFromReader(message: GetRecentNullifierChangesResponseV0, reader: jspb.BinaryReader): GetRecentNullifierChangesResponseV0; + } + + export namespace GetRecentNullifierChangesResponseV0 { + export type AsObject = { + nullifierUpdateEntries?: NullifierUpdateEntries.AsObject, + proof?: Proof.AsObject, + metadata?: ResponseMetadata.AsObject, + } + + export enum ResultCase { + RESULT_NOT_SET = 0, + NULLIFIER_UPDATE_ENTRIES = 1, + PROOF = 2, + } + } + + export enum VersionCase { + VERSION_NOT_SET = 0, + V0 = 1, + } +} + +export class CompactedBlockNullifierChanges extends jspb.Message { + getStartBlockHeight(): string; + setStartBlockHeight(value: string): void; + + getEndBlockHeight(): string; + setEndBlockHeight(value: string): void; + + clearNullifiersList(): void; + getNullifiersList(): Array; + getNullifiersList_asU8(): Array; + getNullifiersList_asB64(): Array; + setNullifiersList(value: Array): void; + addNullifiers(value: Uint8Array | string, index?: number): Uint8Array | string; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): CompactedBlockNullifierChanges.AsObject; + static toObject(includeInstance: boolean, msg: CompactedBlockNullifierChanges): CompactedBlockNullifierChanges.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: CompactedBlockNullifierChanges, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): CompactedBlockNullifierChanges; + static deserializeBinaryFromReader(message: CompactedBlockNullifierChanges, reader: jspb.BinaryReader): CompactedBlockNullifierChanges; +} + +export namespace CompactedBlockNullifierChanges { + export type AsObject = { + startBlockHeight: string, + endBlockHeight: string, + nullifiersList: Array, + } +} + +export class CompactedNullifierUpdateEntries extends jspb.Message { + clearCompactedBlockChangesList(): void; + getCompactedBlockChangesList(): Array; + setCompactedBlockChangesList(value: Array): void; + addCompactedBlockChanges(value?: CompactedBlockNullifierChanges, index?: number): CompactedBlockNullifierChanges; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): CompactedNullifierUpdateEntries.AsObject; + static toObject(includeInstance: boolean, msg: CompactedNullifierUpdateEntries): CompactedNullifierUpdateEntries.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: CompactedNullifierUpdateEntries, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): CompactedNullifierUpdateEntries; + static deserializeBinaryFromReader(message: CompactedNullifierUpdateEntries, reader: jspb.BinaryReader): CompactedNullifierUpdateEntries; +} + +export namespace CompactedNullifierUpdateEntries { + export type AsObject = { + compactedBlockChangesList: Array, + } +} + +export class GetRecentCompactedNullifierChangesRequest extends jspb.Message { + hasV0(): boolean; + clearV0(): void; + getV0(): GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 | undefined; + setV0(value?: GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0): void; + + getVersionCase(): GetRecentCompactedNullifierChangesRequest.VersionCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetRecentCompactedNullifierChangesRequest.AsObject; + static toObject(includeInstance: boolean, msg: GetRecentCompactedNullifierChangesRequest): GetRecentCompactedNullifierChangesRequest.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetRecentCompactedNullifierChangesRequest, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetRecentCompactedNullifierChangesRequest; + static deserializeBinaryFromReader(message: GetRecentCompactedNullifierChangesRequest, reader: jspb.BinaryReader): GetRecentCompactedNullifierChangesRequest; +} + +export namespace GetRecentCompactedNullifierChangesRequest { + export type AsObject = { + v0?: GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.AsObject, + } + + export class GetRecentCompactedNullifierChangesRequestV0 extends jspb.Message { + getStartBlockHeight(): string; + setStartBlockHeight(value: string): void; + + getProve(): boolean; + setProve(value: boolean): void; + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetRecentCompactedNullifierChangesRequestV0.AsObject; + static toObject(includeInstance: boolean, msg: GetRecentCompactedNullifierChangesRequestV0): GetRecentCompactedNullifierChangesRequestV0.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetRecentCompactedNullifierChangesRequestV0, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetRecentCompactedNullifierChangesRequestV0; + static deserializeBinaryFromReader(message: GetRecentCompactedNullifierChangesRequestV0, reader: jspb.BinaryReader): GetRecentCompactedNullifierChangesRequestV0; + } + + export namespace GetRecentCompactedNullifierChangesRequestV0 { + export type AsObject = { + startBlockHeight: string, + prove: boolean, + } + } + + export enum VersionCase { + VERSION_NOT_SET = 0, + V0 = 1, + } +} + +export class GetRecentCompactedNullifierChangesResponse extends jspb.Message { + hasV0(): boolean; + clearV0(): void; + getV0(): GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 | undefined; + setV0(value?: GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0): void; + + getVersionCase(): GetRecentCompactedNullifierChangesResponse.VersionCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetRecentCompactedNullifierChangesResponse.AsObject; + static toObject(includeInstance: boolean, msg: GetRecentCompactedNullifierChangesResponse): GetRecentCompactedNullifierChangesResponse.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetRecentCompactedNullifierChangesResponse, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetRecentCompactedNullifierChangesResponse; + static deserializeBinaryFromReader(message: GetRecentCompactedNullifierChangesResponse, reader: jspb.BinaryReader): GetRecentCompactedNullifierChangesResponse; +} + +export namespace GetRecentCompactedNullifierChangesResponse { + export type AsObject = { + v0?: GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.AsObject, + } + + export class GetRecentCompactedNullifierChangesResponseV0 extends jspb.Message { + hasCompactedNullifierUpdateEntries(): boolean; + clearCompactedNullifierUpdateEntries(): void; + getCompactedNullifierUpdateEntries(): CompactedNullifierUpdateEntries | undefined; + setCompactedNullifierUpdateEntries(value?: CompactedNullifierUpdateEntries): void; + + hasProof(): boolean; + clearProof(): void; + getProof(): Proof | undefined; + setProof(value?: Proof): void; + + hasMetadata(): boolean; + clearMetadata(): void; + getMetadata(): ResponseMetadata | undefined; + setMetadata(value?: ResponseMetadata): void; + + getResultCase(): GetRecentCompactedNullifierChangesResponseV0.ResultCase; + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): GetRecentCompactedNullifierChangesResponseV0.AsObject; + static toObject(includeInstance: boolean, msg: GetRecentCompactedNullifierChangesResponseV0): GetRecentCompactedNullifierChangesResponseV0.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: GetRecentCompactedNullifierChangesResponseV0, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): GetRecentCompactedNullifierChangesResponseV0; + static deserializeBinaryFromReader(message: GetRecentCompactedNullifierChangesResponseV0, reader: jspb.BinaryReader): GetRecentCompactedNullifierChangesResponseV0; + } + + export namespace GetRecentCompactedNullifierChangesResponseV0 { + export type AsObject = { + compactedNullifierUpdateEntries?: CompactedNullifierUpdateEntries.AsObject, + proof?: Proof.AsObject, + metadata?: ResponseMetadata.AsObject, + } + + export enum ResultCase { + RESULT_NOT_SET = 0, + COMPACTED_NULLIFIER_UPDATE_ENTRIES = 1, + PROOF = 2, + } + } + + export enum VersionCase { + VERSION_NOT_SET = 0, + V0 = 1, + } +} + export interface KeyPurposeMap { AUTHENTICATION: 0; ENCRYPTION: 1; diff --git a/packages/dapi-grpc/clients/platform/v0/web/platform_pb.js b/packages/dapi-grpc/clients/platform/v0/web/platform_pb.js index b3961b34a2e..edc3c51e800 100644 --- a/packages/dapi-grpc/clients/platform/v0/web/platform_pb.js +++ b/packages/dapi-grpc/clients/platform/v0/web/platform_pb.js @@ -31,12 +31,15 @@ goog.exportSymbol('proto.org.dash.platform.dapi.v0.AllKeys', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.BalanceAndNonce', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockAddressBalanceChanges', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockHeightCreditEntry', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.BlockNullifierChanges', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastStateTransitionRequest', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.BroadcastStateTransitionResponse', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.CompactedAddressBalanceChange', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.CompactedAddressBalanceChange.OperationCase', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.CompactedAddressBalanceUpdateEntries', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.CompactedBlockAddressBalanceChanges', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetAddressInfoRequest', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetAddressInfoRequest.GetAddressInfoRequestV0', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetAddressInfoRequest.VersionCase', null, { proto }); @@ -371,6 +374,18 @@ goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenInfoEntry', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.GetIdentityTokenInfosResponseV0.TokenInfos', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetIdentityTokenInfosResponse.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.VersionCase', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetPathElementsRequest', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetPathElementsRequest.GetPathElementsRequestV0', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetPathElementsRequest.VersionCase', null, { proto }); @@ -418,6 +433,20 @@ goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBala goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.GetRecentCompactedAddressBalanceChangesResponseV0.ResultCase', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedAddressBalanceChangesResponse.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.ResultCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.VersionCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.ResultCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.VersionCase', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.GetShieldedAnchorsRequestV0', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetShieldedAnchorsRequest.VersionCase', null, { proto }); @@ -546,6 +575,7 @@ goog.exportSymbol('proto.org.dash.platform.dapi.v0.GetVotePollsByEndDateResponse goog.exportSymbol('proto.org.dash.platform.dapi.v0.KeyPurpose', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.KeyRequestType', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.KeyRequestType.RequestCase', null, { proto }); +goog.exportSymbol('proto.org.dash.platform.dapi.v0.NullifierUpdateEntries', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.Proof', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.ResponseMetadata', null, { proto }); goog.exportSymbol('proto.org.dash.platform.dapi.v0.SearchKey', null, { proto }); @@ -8078,6 +8108,426 @@ if (goog.DEBUG && !COMPILED) { */ proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses.displayName = 'proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.GetShieldedNullifiersResponseV0.NullifierStatuses'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.displayName = 'proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.displayName = 'proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.displayName = 'proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.displayName = 'proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.displayName = 'proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.displayName = 'proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.displayName = 'proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.displayName = 'proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.org.dash.platform.dapi.v0.BlockNullifierChanges.repeatedFields_, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.BlockNullifierChanges, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.BlockNullifierChanges.displayName = 'proto.org.dash.platform.dapi.v0.BlockNullifierChanges'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.repeatedFields_, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.NullifierUpdateEntries, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.displayName = 'proto.org.dash.platform.dapi.v0.NullifierUpdateEntries'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.displayName = 'proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.displayName = 'proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.displayName = 'proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.displayName = 'proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.repeatedFields_, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.displayName = 'proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.repeatedFields_, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.displayName = 'proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.displayName = 'proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.displayName = 'proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.displayName = 'proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse'; +} +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0 = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.oneofGroups_); +}; +goog.inherits(proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.displayName = 'proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0'; +} @@ -84274,6 +84724,3900 @@ proto.org.dash.platform.dapi.v0.GetShieldedNullifiersResponse.prototype.hasV0 = }; + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest; + return proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.toObject = function(includeInstance, msg) { + var f, obj = { + poolType: jspb.Message.getFieldWithDefault(msg, 1, 0), + poolIdentifier: msg.getPoolIdentifier_asB64() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0; + return proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readUint32()); + msg.setPoolType(value); + break; + case 2: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setPoolIdentifier(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getPoolType(); + if (f !== 0) { + writer.writeUint32( + 1, + f + ); + } + f = message.getPoolIdentifier_asU8(); + if (f.length > 0) { + writer.writeBytes( + 2, + f + ); + } +}; + + +/** + * optional uint32 pool_type = 1; + * @return {number} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.prototype.getPoolType = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.prototype.setPoolType = function(value) { + return jspb.Message.setProto3IntField(this, 1, value); +}; + + +/** + * optional bytes pool_identifier = 2; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.prototype.getPoolIdentifier = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * optional bytes pool_identifier = 2; + * This is a type-conversion wrapper around `getPoolIdentifier()` + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.prototype.getPoolIdentifier_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getPoolIdentifier())); +}; + + +/** + * optional bytes pool_identifier = 2; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getPoolIdentifier()` + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.prototype.getPoolIdentifier_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getPoolIdentifier())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0.prototype.setPoolIdentifier = function(value) { + return jspb.Message.setProto3BytesField(this, 2, value); +}; + + +/** + * optional GetNullifiersTrunkStateRequestV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.GetNullifiersTrunkStateRequestV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} returns this +*/ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateRequest.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse; + return proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.toObject = function(includeInstance, msg) { + var f, obj = { + proof: (f = msg.getProof()) && proto.org.dash.platform.dapi.v0.Proof.toObject(includeInstance, f), + metadata: (f = msg.getMetadata()) && proto.org.dash.platform.dapi.v0.ResponseMetadata.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0; + return proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 2: + var value = new proto.org.dash.platform.dapi.v0.Proof; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.Proof.deserializeBinaryFromReader); + msg.setProof(value); + break; + case 3: + var value = new proto.org.dash.platform.dapi.v0.ResponseMetadata; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.ResponseMetadata.deserializeBinaryFromReader); + msg.setMetadata(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getProof(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.org.dash.platform.dapi.v0.Proof.serializeBinaryToWriter + ); + } + f = message.getMetadata(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.org.dash.platform.dapi.v0.ResponseMetadata.serializeBinaryToWriter + ); + } +}; + + +/** + * optional Proof proof = 2; + * @return {?proto.org.dash.platform.dapi.v0.Proof} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.getProof = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.Proof} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.Proof, 2)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.Proof|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.setProof = function(value) { + return jspb.Message.setWrapperField(this, 2, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.clearProof = function() { + return this.setProof(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.hasProof = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional ResponseMetadata metadata = 3; + * @return {?proto.org.dash.platform.dapi.v0.ResponseMetadata} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.getMetadata = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.ResponseMetadata} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.ResponseMetadata, 3)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.ResponseMetadata|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.setMetadata = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.clearMetadata = function() { + return this.setMetadata(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0.prototype.hasMetadata = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional GetNullifiersTrunkStateResponseV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.GetNullifiersTrunkStateResponseV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} returns this +*/ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersTrunkStateResponse.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest; + return proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.toObject = function(includeInstance, msg) { + var f, obj = { + poolType: jspb.Message.getFieldWithDefault(msg, 1, 0), + poolIdentifier: msg.getPoolIdentifier_asB64(), + key: msg.getKey_asB64(), + depth: jspb.Message.getFieldWithDefault(msg, 4, 0), + checkpointHeight: jspb.Message.getFieldWithDefault(msg, 5, 0) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0; + return proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readUint32()); + msg.setPoolType(value); + break; + case 2: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setPoolIdentifier(value); + break; + case 3: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setKey(value); + break; + case 4: + var value = /** @type {number} */ (reader.readUint32()); + msg.setDepth(value); + break; + case 5: + var value = /** @type {number} */ (reader.readUint64()); + msg.setCheckpointHeight(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getPoolType(); + if (f !== 0) { + writer.writeUint32( + 1, + f + ); + } + f = message.getPoolIdentifier_asU8(); + if (f.length > 0) { + writer.writeBytes( + 2, + f + ); + } + f = message.getKey_asU8(); + if (f.length > 0) { + writer.writeBytes( + 3, + f + ); + } + f = message.getDepth(); + if (f !== 0) { + writer.writeUint32( + 4, + f + ); + } + f = message.getCheckpointHeight(); + if (f !== 0) { + writer.writeUint64( + 5, + f + ); + } +}; + + +/** + * optional uint32 pool_type = 1; + * @return {number} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.getPoolType = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.setPoolType = function(value) { + return jspb.Message.setProto3IntField(this, 1, value); +}; + + +/** + * optional bytes pool_identifier = 2; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.getPoolIdentifier = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * optional bytes pool_identifier = 2; + * This is a type-conversion wrapper around `getPoolIdentifier()` + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.getPoolIdentifier_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getPoolIdentifier())); +}; + + +/** + * optional bytes pool_identifier = 2; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getPoolIdentifier()` + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.getPoolIdentifier_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getPoolIdentifier())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.setPoolIdentifier = function(value) { + return jspb.Message.setProto3BytesField(this, 2, value); +}; + + +/** + * optional bytes key = 3; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.getKey = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 3, "")); +}; + + +/** + * optional bytes key = 3; + * This is a type-conversion wrapper around `getKey()` + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.getKey_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getKey())); +}; + + +/** + * optional bytes key = 3; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getKey()` + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.getKey_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getKey())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.setKey = function(value) { + return jspb.Message.setProto3BytesField(this, 3, value); +}; + + +/** + * optional uint32 depth = 4; + * @return {number} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.getDepth = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 4, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.setDepth = function(value) { + return jspb.Message.setProto3IntField(this, 4, value); +}; + + +/** + * optional uint64 checkpoint_height = 5; + * @return {number} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.getCheckpointHeight = function() { + return /** @type {number} */ (jspb.Message.getFieldWithDefault(this, 5, 0)); +}; + + +/** + * @param {number} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0.prototype.setCheckpointHeight = function(value) { + return jspb.Message.setProto3IntField(this, 5, value); +}; + + +/** + * optional GetNullifiersBranchStateRequestV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.GetNullifiersBranchStateRequestV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} returns this +*/ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateRequest.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse; + return proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.toObject = function(includeInstance, msg) { + var f, obj = { + merkProof: msg.getMerkProof_asB64() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0; + return proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 2: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.setMerkProof(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getMerkProof_asU8(); + if (f.length > 0) { + writer.writeBytes( + 2, + f + ); + } +}; + + +/** + * optional bytes merk_proof = 2; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.prototype.getMerkProof = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * optional bytes merk_proof = 2; + * This is a type-conversion wrapper around `getMerkProof()` + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.prototype.getMerkProof_asB64 = function() { + return /** @type {string} */ (jspb.Message.bytesAsB64( + this.getMerkProof())); +}; + + +/** + * optional bytes merk_proof = 2; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getMerkProof()` + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.prototype.getMerkProof_asU8 = function() { + return /** @type {!Uint8Array} */ (jspb.Message.bytesAsU8( + this.getMerkProof())); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0.prototype.setMerkProof = function(value) { + return jspb.Message.setProto3BytesField(this, 2, value); +}; + + +/** + * optional GetNullifiersBranchStateResponseV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.GetNullifiersBranchStateResponseV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} returns this +*/ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse} returns this + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetNullifiersBranchStateResponse.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.repeatedFields_ = [2]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.BlockNullifierChanges.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.toObject = function(includeInstance, msg) { + var f, obj = { + blockHeight: jspb.Message.getFieldWithDefault(msg, 1, "0"), + nullifiersList: msg.getNullifiersList_asB64() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.BlockNullifierChanges; + return proto.org.dash.platform.dapi.v0.BlockNullifierChanges.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setBlockHeight(value); + break; + case 2: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.addNullifiers(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.BlockNullifierChanges.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getBlockHeight(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( + 1, + f + ); + } + f = message.getNullifiersList_asU8(); + if (f.length > 0) { + writer.writeRepeatedBytes( + 2, + f + ); + } +}; + + +/** + * optional uint64 block_height = 1; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.getBlockHeight = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} returns this + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.setBlockHeight = function(value) { + return jspb.Message.setProto3StringIntField(this, 1, value); +}; + + +/** + * repeated bytes nullifiers = 2; + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.getNullifiersList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 2)); +}; + + +/** + * repeated bytes nullifiers = 2; + * This is a type-conversion wrapper around `getNullifiersList()` + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.getNullifiersList_asB64 = function() { + return /** @type {!Array} */ (jspb.Message.bytesListAsB64( + this.getNullifiersList())); +}; + + +/** + * repeated bytes nullifiers = 2; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getNullifiersList()` + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.getNullifiersList_asU8 = function() { + return /** @type {!Array} */ (jspb.Message.bytesListAsU8( + this.getNullifiersList())); +}; + + +/** + * @param {!(Array|Array)} value + * @return {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} returns this + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.setNullifiersList = function(value) { + return jspb.Message.setField(this, 2, value || []); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @param {number=} opt_index + * @return {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} returns this + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.addNullifiers = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 2, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} returns this + */ +proto.org.dash.platform.dapi.v0.BlockNullifierChanges.prototype.clearNullifiersList = function() { + return this.setNullifiersList([]); +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.NullifierUpdateEntries} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.toObject = function(includeInstance, msg) { + var f, obj = { + blockChangesList: jspb.Message.toObjectList(msg.getBlockChangesList(), + proto.org.dash.platform.dapi.v0.BlockNullifierChanges.toObject, includeInstance) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.NullifierUpdateEntries} + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.NullifierUpdateEntries; + return proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.NullifierUpdateEntries} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.NullifierUpdateEntries} + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.BlockNullifierChanges; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.BlockNullifierChanges.deserializeBinaryFromReader); + msg.addBlockChanges(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.NullifierUpdateEntries} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getBlockChangesList(); + if (f.length > 0) { + writer.writeRepeatedMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.BlockNullifierChanges.serializeBinaryToWriter + ); + } +}; + + +/** + * repeated BlockNullifierChanges block_changes = 1; + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.prototype.getBlockChangesList = function() { + return /** @type{!Array} */ ( + jspb.Message.getRepeatedWrapperField(this, proto.org.dash.platform.dapi.v0.BlockNullifierChanges, 1)); +}; + + +/** + * @param {!Array} value + * @return {!proto.org.dash.platform.dapi.v0.NullifierUpdateEntries} returns this +*/ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.prototype.setBlockChangesList = function(value) { + return jspb.Message.setRepeatedWrapperField(this, 1, value); +}; + + +/** + * @param {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges=} opt_value + * @param {number=} opt_index + * @return {!proto.org.dash.platform.dapi.v0.BlockNullifierChanges} + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.prototype.addBlockChanges = function(opt_value, opt_index) { + return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.org.dash.platform.dapi.v0.BlockNullifierChanges, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.org.dash.platform.dapi.v0.NullifierUpdateEntries} returns this + */ +proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.prototype.clearBlockChangesList = function() { + return this.setBlockChangesList([]); +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest; + return proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.toObject = function(includeInstance, msg) { + var f, obj = { + startHeight: jspb.Message.getFieldWithDefault(msg, 1, "0"), + prove: jspb.Message.getBooleanFieldWithDefault(msg, 2, false) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0; + return proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setStartHeight(value); + break; + case 2: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setProve(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getStartHeight(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( + 1, + f + ); + } + f = message.getProve(); + if (f) { + writer.writeBool( + 2, + f + ); + } +}; + + +/** + * optional uint64 start_height = 1; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.prototype.getStartHeight = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.prototype.setStartHeight = function(value) { + return jspb.Message.setProto3StringIntField(this, 1, value); +}; + + +/** + * optional bool prove = 2; + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.prototype.getProve = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 2, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0.prototype.setProve = function(value) { + return jspb.Message.setProto3BooleanField(this, 2, value); +}; + + +/** + * optional GetRecentNullifierChangesRequestV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.GetRecentNullifierChangesRequestV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesRequest.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse; + return proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.serializeBinaryToWriter + ); + } +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.oneofGroups_ = [[1,2]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.ResultCase = { + RESULT_NOT_SET: 0, + NULLIFIER_UPDATE_ENTRIES: 1, + PROOF: 2 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.ResultCase} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.getResultCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.ResultCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.toObject = function(includeInstance, msg) { + var f, obj = { + nullifierUpdateEntries: (f = msg.getNullifierUpdateEntries()) && proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.toObject(includeInstance, f), + proof: (f = msg.getProof()) && proto.org.dash.platform.dapi.v0.Proof.toObject(includeInstance, f), + metadata: (f = msg.getMetadata()) && proto.org.dash.platform.dapi.v0.ResponseMetadata.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0; + return proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.NullifierUpdateEntries; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.deserializeBinaryFromReader); + msg.setNullifierUpdateEntries(value); + break; + case 2: + var value = new proto.org.dash.platform.dapi.v0.Proof; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.Proof.deserializeBinaryFromReader); + msg.setProof(value); + break; + case 3: + var value = new proto.org.dash.platform.dapi.v0.ResponseMetadata; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.ResponseMetadata.deserializeBinaryFromReader); + msg.setMetadata(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getNullifierUpdateEntries(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.NullifierUpdateEntries.serializeBinaryToWriter + ); + } + f = message.getProof(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.org.dash.platform.dapi.v0.Proof.serializeBinaryToWriter + ); + } + f = message.getMetadata(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.org.dash.platform.dapi.v0.ResponseMetadata.serializeBinaryToWriter + ); + } +}; + + +/** + * optional NullifierUpdateEntries nullifier_update_entries = 1; + * @return {?proto.org.dash.platform.dapi.v0.NullifierUpdateEntries} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.getNullifierUpdateEntries = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.NullifierUpdateEntries} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.NullifierUpdateEntries, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.NullifierUpdateEntries|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.setNullifierUpdateEntries = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.clearNullifierUpdateEntries = function() { + return this.setNullifierUpdateEntries(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.hasNullifierUpdateEntries = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional Proof proof = 2; + * @return {?proto.org.dash.platform.dapi.v0.Proof} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.getProof = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.Proof} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.Proof, 2)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.Proof|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.setProof = function(value) { + return jspb.Message.setOneofWrapperField(this, 2, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.clearProof = function() { + return this.setProof(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.hasProof = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional ResponseMetadata metadata = 3; + * @return {?proto.org.dash.platform.dapi.v0.ResponseMetadata} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.getMetadata = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.ResponseMetadata} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.ResponseMetadata, 3)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.ResponseMetadata|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.setMetadata = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.clearMetadata = function() { + return this.setMetadata(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0.prototype.hasMetadata = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional GetRecentNullifierChangesResponseV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.GetRecentNullifierChangesResponseV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentNullifierChangesResponse.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.repeatedFields_ = [3]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.toObject = function(includeInstance, msg) { + var f, obj = { + startBlockHeight: jspb.Message.getFieldWithDefault(msg, 1, "0"), + endBlockHeight: jspb.Message.getFieldWithDefault(msg, 2, "0"), + nullifiersList: msg.getNullifiersList_asB64() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges; + return proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setStartBlockHeight(value); + break; + case 2: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setEndBlockHeight(value); + break; + case 3: + var value = /** @type {!Uint8Array} */ (reader.readBytes()); + msg.addNullifiers(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getStartBlockHeight(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( + 1, + f + ); + } + f = message.getEndBlockHeight(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( + 2, + f + ); + } + f = message.getNullifiersList_asU8(); + if (f.length > 0) { + writer.writeRepeatedBytes( + 3, + f + ); + } +}; + + +/** + * optional uint64 start_block_height = 1; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.getStartBlockHeight = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} returns this + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.setStartBlockHeight = function(value) { + return jspb.Message.setProto3StringIntField(this, 1, value); +}; + + +/** + * optional uint64 end_block_height = 2; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.getEndBlockHeight = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} returns this + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.setEndBlockHeight = function(value) { + return jspb.Message.setProto3StringIntField(this, 2, value); +}; + + +/** + * repeated bytes nullifiers = 3; + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.getNullifiersList = function() { + return /** @type {!Array} */ (jspb.Message.getRepeatedField(this, 3)); +}; + + +/** + * repeated bytes nullifiers = 3; + * This is a type-conversion wrapper around `getNullifiersList()` + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.getNullifiersList_asB64 = function() { + return /** @type {!Array} */ (jspb.Message.bytesListAsB64( + this.getNullifiersList())); +}; + + +/** + * repeated bytes nullifiers = 3; + * Note that Uint8Array is not supported on all browsers. + * @see http://caniuse.com/Uint8Array + * This is a type-conversion wrapper around `getNullifiersList()` + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.getNullifiersList_asU8 = function() { + return /** @type {!Array} */ (jspb.Message.bytesListAsU8( + this.getNullifiersList())); +}; + + +/** + * @param {!(Array|Array)} value + * @return {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} returns this + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.setNullifiersList = function(value) { + return jspb.Message.setField(this, 3, value || []); +}; + + +/** + * @param {!(string|Uint8Array)} value + * @param {number=} opt_index + * @return {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} returns this + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.addNullifiers = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 3, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} returns this + */ +proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.prototype.clearNullifiersList = function() { + return this.setNullifiersList([]); +}; + + + +/** + * List of repeated fields within this message type. + * @private {!Array} + * @const + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.repeatedFields_ = [1]; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.toObject = function(includeInstance, msg) { + var f, obj = { + compactedBlockChangesList: jspb.Message.toObjectList(msg.getCompactedBlockChangesList(), + proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.toObject, includeInstance) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries; + return proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.deserializeBinaryFromReader); + msg.addCompactedBlockChanges(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getCompactedBlockChangesList(); + if (f.length > 0) { + writer.writeRepeatedMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges.serializeBinaryToWriter + ); + } +}; + + +/** + * repeated CompactedBlockNullifierChanges compacted_block_changes = 1; + * @return {!Array} + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.prototype.getCompactedBlockChangesList = function() { + return /** @type{!Array} */ ( + jspb.Message.getRepeatedWrapperField(this, proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges, 1)); +}; + + +/** + * @param {!Array} value + * @return {!proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} returns this +*/ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.prototype.setCompactedBlockChangesList = function(value) { + return jspb.Message.setRepeatedWrapperField(this, 1, value); +}; + + +/** + * @param {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges=} opt_value + * @param {number=} opt_index + * @return {!proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges} + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.prototype.addCompactedBlockChanges = function(opt_value, opt_index) { + return jspb.Message.addToRepeatedWrapperField(this, 1, opt_value, proto.org.dash.platform.dapi.v0.CompactedBlockNullifierChanges, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} returns this + */ +proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.prototype.clearCompactedBlockChangesList = function() { + return this.setCompactedBlockChangesList([]); +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest; + return proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.serializeBinaryToWriter + ); + } +}; + + + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.toObject = function(includeInstance, msg) { + var f, obj = { + startBlockHeight: jspb.Message.getFieldWithDefault(msg, 1, "0"), + prove: jspb.Message.getBooleanFieldWithDefault(msg, 2, false) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0; + return proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {string} */ (reader.readUint64String()); + msg.setStartBlockHeight(value); + break; + case 2: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setProve(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getStartBlockHeight(); + if (parseInt(f, 10) !== 0) { + writer.writeUint64String( + 1, + f + ); + } + f = message.getProve(); + if (f) { + writer.writeBool( + 2, + f + ); + } +}; + + +/** + * optional uint64 start_block_height = 1; + * @return {string} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.prototype.getStartBlockHeight = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, "0")); +}; + + +/** + * @param {string} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.prototype.setStartBlockHeight = function(value) { + return jspb.Message.setProto3StringIntField(this, 1, value); +}; + + +/** + * optional bool prove = 2; + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.prototype.getProve = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 2, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0.prototype.setProve = function(value) { + return jspb.Message.setProto3BooleanField(this, 2, value); +}; + + +/** + * optional GetRecentCompactedNullifierChangesRequestV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.GetRecentCompactedNullifierChangesRequestV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesRequest.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.oneofGroups_ = [[1]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.VersionCase = { + VERSION_NOT_SET: 0, + V0: 1 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.VersionCase} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.prototype.getVersionCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.VersionCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.toObject = function(includeInstance, msg) { + var f, obj = { + v0: (f = msg.getV0()) && proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse; + return proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.deserializeBinaryFromReader); + msg.setV0(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getV0(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.serializeBinaryToWriter + ); + } +}; + + + +/** + * Oneof group definitions for this message. Each group defines the field + * numbers belonging to that group. When of these fields' value is set, all + * other fields in the group are cleared. During deserialization, if multiple + * fields are encountered for a group, only the last value seen will be kept. + * @private {!Array>} + * @const + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.oneofGroups_ = [[1,2]]; + +/** + * @enum {number} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.ResultCase = { + RESULT_NOT_SET: 0, + COMPACTED_NULLIFIER_UPDATE_ENTRIES: 1, + PROOF: 2 +}; + +/** + * @return {proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.ResultCase} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.getResultCase = function() { + return /** @type {proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.ResultCase} */(jspb.Message.computeOneofCase(this, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.oneofGroups_[0])); +}; + + + +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.toObject = function(opt_includeInstance) { + return proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.toObject = function(includeInstance, msg) { + var f, obj = { + compactedNullifierUpdateEntries: (f = msg.getCompactedNullifierUpdateEntries()) && proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.toObject(includeInstance, f), + proof: (f = msg.getProof()) && proto.org.dash.platform.dapi.v0.Proof.toObject(includeInstance, f), + metadata: (f = msg.getMetadata()) && proto.org.dash.platform.dapi.v0.ResponseMetadata.toObject(includeInstance, f) + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0; + return proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = new proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.deserializeBinaryFromReader); + msg.setCompactedNullifierUpdateEntries(value); + break; + case 2: + var value = new proto.org.dash.platform.dapi.v0.Proof; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.Proof.deserializeBinaryFromReader); + msg.setProof(value); + break; + case 3: + var value = new proto.org.dash.platform.dapi.v0.ResponseMetadata; + reader.readMessage(value,proto.org.dash.platform.dapi.v0.ResponseMetadata.deserializeBinaryFromReader); + msg.setMetadata(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getCompactedNullifierUpdateEntries(); + if (f != null) { + writer.writeMessage( + 1, + f, + proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries.serializeBinaryToWriter + ); + } + f = message.getProof(); + if (f != null) { + writer.writeMessage( + 2, + f, + proto.org.dash.platform.dapi.v0.Proof.serializeBinaryToWriter + ); + } + f = message.getMetadata(); + if (f != null) { + writer.writeMessage( + 3, + f, + proto.org.dash.platform.dapi.v0.ResponseMetadata.serializeBinaryToWriter + ); + } +}; + + +/** + * optional CompactedNullifierUpdateEntries compacted_nullifier_update_entries = 1; + * @return {?proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.getCompactedNullifierUpdateEntries = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.CompactedNullifierUpdateEntries|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.setCompactedNullifierUpdateEntries = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.clearCompactedNullifierUpdateEntries = function() { + return this.setCompactedNullifierUpdateEntries(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.hasCompactedNullifierUpdateEntries = function() { + return jspb.Message.getField(this, 1) != null; +}; + + +/** + * optional Proof proof = 2; + * @return {?proto.org.dash.platform.dapi.v0.Proof} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.getProof = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.Proof} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.Proof, 2)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.Proof|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.setProof = function(value) { + return jspb.Message.setOneofWrapperField(this, 2, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.clearProof = function() { + return this.setProof(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.hasProof = function() { + return jspb.Message.getField(this, 2) != null; +}; + + +/** + * optional ResponseMetadata metadata = 3; + * @return {?proto.org.dash.platform.dapi.v0.ResponseMetadata} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.getMetadata = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.ResponseMetadata} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.ResponseMetadata, 3)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.ResponseMetadata|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.setMetadata = function(value) { + return jspb.Message.setWrapperField(this, 3, value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.clearMetadata = function() { + return this.setMetadata(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0.prototype.hasMetadata = function() { + return jspb.Message.getField(this, 3) != null; +}; + + +/** + * optional GetRecentCompactedNullifierChangesResponseV0 v0 = 1; + * @return {?proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.prototype.getV0 = function() { + return /** @type{?proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0} */ ( + jspb.Message.getWrapperField(this, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0, 1)); +}; + + +/** + * @param {?proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.GetRecentCompactedNullifierChangesResponseV0|undefined} value + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} returns this +*/ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.prototype.setV0 = function(value) { + return jspb.Message.setOneofWrapperField(this, 1, proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.oneofGroups_[0], value); +}; + + +/** + * Clears the message field making it undefined. + * @return {!proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse} returns this + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.prototype.clearV0 = function() { + return this.setV0(undefined); +}; + + +/** + * Returns whether this field is set. + * @return {boolean} + */ +proto.org.dash.platform.dapi.v0.GetRecentCompactedNullifierChangesResponse.prototype.hasV0 = function() { + return jspb.Message.getField(this, 1) != null; +}; + + /** * @enum {number} */ diff --git a/packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.d.ts b/packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.d.ts index 72393c9b9aa..9f5d03d9793 100644 --- a/packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.d.ts +++ b/packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.d.ts @@ -517,6 +517,42 @@ type PlatformgetShieldedNullifiers = { readonly responseType: typeof platform_pb.GetShieldedNullifiersResponse; }; +type PlatformgetNullifiersTrunkState = { + readonly methodName: string; + readonly service: typeof Platform; + readonly requestStream: false; + readonly responseStream: false; + readonly requestType: typeof platform_pb.GetNullifiersTrunkStateRequest; + readonly responseType: typeof platform_pb.GetNullifiersTrunkStateResponse; +}; + +type PlatformgetNullifiersBranchState = { + readonly methodName: string; + readonly service: typeof Platform; + readonly requestStream: false; + readonly responseStream: false; + readonly requestType: typeof platform_pb.GetNullifiersBranchStateRequest; + readonly responseType: typeof platform_pb.GetNullifiersBranchStateResponse; +}; + +type PlatformgetRecentNullifierChanges = { + readonly methodName: string; + readonly service: typeof Platform; + readonly requestStream: false; + readonly responseStream: false; + readonly requestType: typeof platform_pb.GetRecentNullifierChangesRequest; + readonly responseType: typeof platform_pb.GetRecentNullifierChangesResponse; +}; + +type PlatformgetRecentCompactedNullifierChanges = { + readonly methodName: string; + readonly service: typeof Platform; + readonly requestStream: false; + readonly responseStream: false; + readonly requestType: typeof platform_pb.GetRecentCompactedNullifierChangesRequest; + readonly responseType: typeof platform_pb.GetRecentCompactedNullifierChangesResponse; +}; + export class Platform { static readonly serviceName: string; static readonly broadcastStateTransition: PlatformbroadcastStateTransition; @@ -576,6 +612,10 @@ export class Platform { static readonly getShieldedAnchors: PlatformgetShieldedAnchors; static readonly getShieldedPoolState: PlatformgetShieldedPoolState; static readonly getShieldedNullifiers: PlatformgetShieldedNullifiers; + static readonly getNullifiersTrunkState: PlatformgetNullifiersTrunkState; + static readonly getNullifiersBranchState: PlatformgetNullifiersBranchState; + static readonly getRecentNullifierChanges: PlatformgetRecentNullifierChanges; + static readonly getRecentCompactedNullifierChanges: PlatformgetRecentCompactedNullifierChanges; } export type ServiceError = { message: string, code: number; metadata: grpc.Metadata } @@ -1123,5 +1163,41 @@ export class PlatformClient { requestMessage: platform_pb.GetShieldedNullifiersRequest, callback: (error: ServiceError|null, responseMessage: platform_pb.GetShieldedNullifiersResponse|null) => void ): UnaryResponse; + getNullifiersTrunkState( + requestMessage: platform_pb.GetNullifiersTrunkStateRequest, + metadata: grpc.Metadata, + callback: (error: ServiceError|null, responseMessage: platform_pb.GetNullifiersTrunkStateResponse|null) => void + ): UnaryResponse; + getNullifiersTrunkState( + requestMessage: platform_pb.GetNullifiersTrunkStateRequest, + callback: (error: ServiceError|null, responseMessage: platform_pb.GetNullifiersTrunkStateResponse|null) => void + ): UnaryResponse; + getNullifiersBranchState( + requestMessage: platform_pb.GetNullifiersBranchStateRequest, + metadata: grpc.Metadata, + callback: (error: ServiceError|null, responseMessage: platform_pb.GetNullifiersBranchStateResponse|null) => void + ): UnaryResponse; + getNullifiersBranchState( + requestMessage: platform_pb.GetNullifiersBranchStateRequest, + callback: (error: ServiceError|null, responseMessage: platform_pb.GetNullifiersBranchStateResponse|null) => void + ): UnaryResponse; + getRecentNullifierChanges( + requestMessage: platform_pb.GetRecentNullifierChangesRequest, + metadata: grpc.Metadata, + callback: (error: ServiceError|null, responseMessage: platform_pb.GetRecentNullifierChangesResponse|null) => void + ): UnaryResponse; + getRecentNullifierChanges( + requestMessage: platform_pb.GetRecentNullifierChangesRequest, + callback: (error: ServiceError|null, responseMessage: platform_pb.GetRecentNullifierChangesResponse|null) => void + ): UnaryResponse; + getRecentCompactedNullifierChanges( + requestMessage: platform_pb.GetRecentCompactedNullifierChangesRequest, + metadata: grpc.Metadata, + callback: (error: ServiceError|null, responseMessage: platform_pb.GetRecentCompactedNullifierChangesResponse|null) => void + ): UnaryResponse; + getRecentCompactedNullifierChanges( + requestMessage: platform_pb.GetRecentCompactedNullifierChangesRequest, + callback: (error: ServiceError|null, responseMessage: platform_pb.GetRecentCompactedNullifierChangesResponse|null) => void + ): UnaryResponse; } diff --git a/packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.js b/packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.js index 6b53127c4d0..6b7801b08d4 100644 --- a/packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.js +++ b/packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.js @@ -523,6 +523,42 @@ Platform.getShieldedNullifiers = { responseType: platform_pb.GetShieldedNullifiersResponse }; +Platform.getNullifiersTrunkState = { + methodName: "getNullifiersTrunkState", + service: Platform, + requestStream: false, + responseStream: false, + requestType: platform_pb.GetNullifiersTrunkStateRequest, + responseType: platform_pb.GetNullifiersTrunkStateResponse +}; + +Platform.getNullifiersBranchState = { + methodName: "getNullifiersBranchState", + service: Platform, + requestStream: false, + responseStream: false, + requestType: platform_pb.GetNullifiersBranchStateRequest, + responseType: platform_pb.GetNullifiersBranchStateResponse +}; + +Platform.getRecentNullifierChanges = { + methodName: "getRecentNullifierChanges", + service: Platform, + requestStream: false, + responseStream: false, + requestType: platform_pb.GetRecentNullifierChangesRequest, + responseType: platform_pb.GetRecentNullifierChangesResponse +}; + +Platform.getRecentCompactedNullifierChanges = { + methodName: "getRecentCompactedNullifierChanges", + service: Platform, + requestStream: false, + responseStream: false, + requestType: platform_pb.GetRecentCompactedNullifierChangesRequest, + responseType: platform_pb.GetRecentCompactedNullifierChangesResponse +}; + exports.Platform = Platform; function PlatformClient(serviceHost, options) { @@ -2297,5 +2333,129 @@ PlatformClient.prototype.getShieldedNullifiers = function getShieldedNullifiers( }; }; +PlatformClient.prototype.getNullifiersTrunkState = function getNullifiersTrunkState(requestMessage, metadata, callback) { + if (arguments.length === 2) { + callback = arguments[1]; + } + var client = grpc.unary(Platform.getNullifiersTrunkState, { + request: requestMessage, + host: this.serviceHost, + metadata: metadata, + transport: this.options.transport, + debug: this.options.debug, + onEnd: function (response) { + if (callback) { + if (response.status !== grpc.Code.OK) { + var err = new Error(response.statusMessage); + err.code = response.status; + err.metadata = response.trailers; + callback(err, null); + } else { + callback(null, response.message); + } + } + } + }); + return { + cancel: function () { + callback = null; + client.close(); + } + }; +}; + +PlatformClient.prototype.getNullifiersBranchState = function getNullifiersBranchState(requestMessage, metadata, callback) { + if (arguments.length === 2) { + callback = arguments[1]; + } + var client = grpc.unary(Platform.getNullifiersBranchState, { + request: requestMessage, + host: this.serviceHost, + metadata: metadata, + transport: this.options.transport, + debug: this.options.debug, + onEnd: function (response) { + if (callback) { + if (response.status !== grpc.Code.OK) { + var err = new Error(response.statusMessage); + err.code = response.status; + err.metadata = response.trailers; + callback(err, null); + } else { + callback(null, response.message); + } + } + } + }); + return { + cancel: function () { + callback = null; + client.close(); + } + }; +}; + +PlatformClient.prototype.getRecentNullifierChanges = function getRecentNullifierChanges(requestMessage, metadata, callback) { + if (arguments.length === 2) { + callback = arguments[1]; + } + var client = grpc.unary(Platform.getRecentNullifierChanges, { + request: requestMessage, + host: this.serviceHost, + metadata: metadata, + transport: this.options.transport, + debug: this.options.debug, + onEnd: function (response) { + if (callback) { + if (response.status !== grpc.Code.OK) { + var err = new Error(response.statusMessage); + err.code = response.status; + err.metadata = response.trailers; + callback(err, null); + } else { + callback(null, response.message); + } + } + } + }); + return { + cancel: function () { + callback = null; + client.close(); + } + }; +}; + +PlatformClient.prototype.getRecentCompactedNullifierChanges = function getRecentCompactedNullifierChanges(requestMessage, metadata, callback) { + if (arguments.length === 2) { + callback = arguments[1]; + } + var client = grpc.unary(Platform.getRecentCompactedNullifierChanges, { + request: requestMessage, + host: this.serviceHost, + metadata: metadata, + transport: this.options.transport, + debug: this.options.debug, + onEnd: function (response) { + if (callback) { + if (response.status !== grpc.Code.OK) { + var err = new Error(response.statusMessage); + err.code = response.status; + err.metadata = response.trailers; + callback(err, null); + } else { + callback(null, response.message); + } + } + } + }); + return { + cancel: function () { + callback = null; + client.close(); + } + }; +}; + exports.PlatformClient = PlatformClient; diff --git a/packages/rs-dapi/src/services/platform_service/mod.rs b/packages/rs-dapi/src/services/platform_service/mod.rs index 14df3c3a525..91fb75687d6 100644 --- a/packages/rs-dapi/src/services/platform_service/mod.rs +++ b/packages/rs-dapi/src/services/platform_service/mod.rs @@ -580,4 +580,28 @@ impl Platform for PlatformServiceImpl { dapi_grpc::platform::v0::GetShieldedNullifiersRequest, dapi_grpc::platform::v0::GetShieldedNullifiersResponse ); + + drive_method!( + get_nullifiers_trunk_state, + dapi_grpc::platform::v0::GetNullifiersTrunkStateRequest, + dapi_grpc::platform::v0::GetNullifiersTrunkStateResponse + ); + + drive_method!( + get_nullifiers_branch_state, + dapi_grpc::platform::v0::GetNullifiersBranchStateRequest, + dapi_grpc::platform::v0::GetNullifiersBranchStateResponse + ); + + drive_method!( + get_recent_nullifier_changes, + dapi_grpc::platform::v0::GetRecentNullifierChangesRequest, + dapi_grpc::platform::v0::GetRecentNullifierChangesResponse + ); + + drive_method!( + get_recent_compacted_nullifier_changes, + dapi_grpc::platform::v0::GetRecentCompactedNullifierChangesRequest, + dapi_grpc::platform::v0::GetRecentCompactedNullifierChangesResponse + ); } diff --git a/packages/rs-sdk/src/platform/fetch.rs b/packages/rs-sdk/src/platform/fetch.rs index 5b2faee5cf7..c3290e462c3 100644 --- a/packages/rs-sdk/src/platform/fetch.rs +++ b/packages/rs-sdk/src/platform/fetch.rs @@ -385,6 +385,14 @@ impl Fetch for drive_proof_verifier::types::ShieldedNullifierStatuses { type Request = platform_proto::GetShieldedNullifiersRequest; } +impl Fetch for drive_proof_verifier::types::RecentNullifierChanges { + type Request = platform_proto::GetRecentNullifierChangesRequest; +} + +impl Fetch for drive_proof_verifier::types::RecentCompactedNullifierChanges { + type Request = platform_proto::GetRecentCompactedNullifierChangesRequest; +} + /// Refetch the data contract from the network, update the context provider /// cache, and return a new [DocumentQuery] with the fresh contract. /// From 1a08a9a7d499361c098addabfb3f002549490f64 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 24 Feb 2026 08:06:21 +0700 Subject: [PATCH 28/40] more work --- packages/rs-dapi-client/src/transport/grpc.rs | 36 + packages/rs-drive-proof-verifier/src/types.rs | 26 + packages/rs-sdk/src/mock/requests.rs | 29 +- packages/rs-sdk/src/platform.rs | 1 + .../rs-sdk/src/platform/address_sync/mod.rs | 2 +- packages/rs-sdk/src/platform/fetch.rs | 4 + .../rs-sdk/src/platform/nullifier_sync/mod.rs | 753 ++++++++++++++++++ .../src/platform/nullifier_sync/provider.rs | 42 + .../src/platform/nullifier_sync/types.rs | 160 ++++ packages/rs-sdk/src/platform/query.rs | 27 +- 10 files changed, 1070 insertions(+), 10 deletions(-) create mode 100644 packages/rs-sdk/src/platform/nullifier_sync/mod.rs create mode 100644 packages/rs-sdk/src/platform/nullifier_sync/provider.rs create mode 100644 packages/rs-sdk/src/platform/nullifier_sync/types.rs diff --git a/packages/rs-dapi-client/src/transport/grpc.rs b/packages/rs-dapi-client/src/transport/grpc.rs index 61ba91046ad..fccfc93dd09 100644 --- a/packages/rs-dapi-client/src/transport/grpc.rs +++ b/packages/rs-dapi-client/src/transport/grpc.rs @@ -488,6 +488,42 @@ impl_transport_request_grpc!( get_shielded_nullifiers ); +// rpc getRecentNullifierChanges(GetRecentNullifierChangesRequest) returns (GetRecentNullifierChangesResponse); +impl_transport_request_grpc!( + platform_proto::GetRecentNullifierChangesRequest, + platform_proto::GetRecentNullifierChangesResponse, + PlatformGrpcClient, + RequestSettings::default(), + get_recent_nullifier_changes +); + +// rpc getRecentCompactedNullifierChanges(GetRecentCompactedNullifierChangesRequest) returns (GetRecentCompactedNullifierChangesResponse); +impl_transport_request_grpc!( + platform_proto::GetRecentCompactedNullifierChangesRequest, + platform_proto::GetRecentCompactedNullifierChangesResponse, + PlatformGrpcClient, + RequestSettings::default(), + get_recent_compacted_nullifier_changes +); + +// rpc getNullifiersTrunkState(GetNullifiersTrunkStateRequest) returns (GetNullifiersTrunkStateResponse); +impl_transport_request_grpc!( + platform_proto::GetNullifiersTrunkStateRequest, + platform_proto::GetNullifiersTrunkStateResponse, + PlatformGrpcClient, + RequestSettings::default(), + get_nullifiers_trunk_state +); + +// rpc getNullifiersBranchState(GetNullifiersBranchStateRequest) returns (GetNullifiersBranchStateResponse); +impl_transport_request_grpc!( + platform_proto::GetNullifiersBranchStateRequest, + platform_proto::GetNullifiersBranchStateResponse, + PlatformGrpcClient, + RequestSettings::default(), + get_nullifiers_branch_state +); + // Link to each core gRPC request what client and method to use: impl_transport_request_grpc!( diff --git a/packages/rs-drive-proof-verifier/src/types.rs b/packages/rs-drive-proof-verifier/src/types.rs index d6577516a83..d267e10b913 100644 --- a/packages/rs-drive-proof-verifier/src/types.rs +++ b/packages/rs-drive-proof-verifier/src/types.rs @@ -877,6 +877,32 @@ pub struct ShieldedEncryptedNotesQuery { )] pub struct ShieldedNullifiersQuery(pub Vec>); +/// Query parameters for nullifier trunk state retrieval. +/// +/// Used with the `GetNullifiersTrunkStateRequest` RPC to fetch the top levels +/// of the nullifier tree for privacy-preserving synchronization. +#[derive(Debug, Clone)] +#[cfg_attr( + feature = "mocks", + derive(Encode, Decode, PlatformSerialize, PlatformDeserialize), + platform_serialize(unversioned) +)] +pub struct NullifiersTrunkQuery { + /// The shielded pool type (0 = credit, 1 = main token, 2 = individual token). + pub pool_type: u32, + /// Optional 32-byte identifier for individual token pools. + pub pool_identifier: Option>, +} + +impl Default for NullifiersTrunkQuery { + fn default() -> Self { + Self { + pool_type: 0, + pool_identifier: None, + } + } +} + /// Nullifier changes for a single block. #[derive(Debug, Clone)] #[cfg_attr( diff --git a/packages/rs-sdk/src/mock/requests.rs b/packages/rs-sdk/src/mock/requests.rs index e9483182d41..e50d752ccd8 100644 --- a/packages/rs-sdk/src/mock/requests.rs +++ b/packages/rs-sdk/src/mock/requests.rs @@ -35,11 +35,13 @@ use drive_proof_verifier::types::token_status::TokenStatuses; use drive::grovedb::GroveTrunkQueryResult; use drive_proof_verifier::types::{ AddressInfo, Contenders, ContestedResources, CurrentQuorumsInfo, ElementFetchRequestItem, - IdentityBalanceAndRevision, IndexMap, MasternodeProtocolVote, PlatformAddressTrunkState, - PrefundedSpecializedBalance, ProposerBlockCounts, RecentAddressBalanceChanges, - RecentCompactedAddressBalanceChanges, RetrievedValues, ShieldedAnchors, ShieldedEncryptedNote, - ShieldedEncryptedNotes, ShieldedNullifierStatus, ShieldedNullifierStatuses, ShieldedPoolState, - TotalCreditsInPlatform, VotePollsGroupedByTimestamp, Voters, + IdentityBalanceAndRevision, IndexMap, MasternodeProtocolVote, NullifiersTrunkState, + PlatformAddressTrunkState, PrefundedSpecializedBalance, ProposerBlockCounts, + RecentAddressBalanceChanges, RecentCompactedAddressBalanceChanges, + RecentCompactedNullifierChanges, RecentNullifierChanges, RetrievedValues, ShieldedAnchors, + ShieldedEncryptedNote, ShieldedEncryptedNotes, ShieldedNullifierStatus, + ShieldedNullifierStatuses, ShieldedPoolState, TotalCreditsInPlatform, + VotePollsGroupedByTimestamp, Voters, }; use std::{collections::BTreeMap, hash::Hash}; @@ -514,6 +516,8 @@ impl_mock_response!(ShieldedEncryptedNotes); impl_mock_response!(ShieldedEncryptedNote); impl_mock_response!(ShieldedNullifierStatuses); impl_mock_response!(ShieldedNullifierStatus); +impl_mock_response!(RecentNullifierChanges); +impl_mock_response!(RecentCompactedNullifierChanges); /// MockResponse for GroveTrunkQueryResult - panics when called because the Tree type /// doesn't support serialization. Address sync operations should not be mocked. @@ -544,3 +548,18 @@ impl MockResponse for PlatformAddressTrunkState { unimplemented!("PlatformAddressTrunkState does not support mock deserialization - the Tree type is not serializable") } } + +/// MockResponse for NullifiersTrunkState - panics when called because the underlying +/// Tree type doesn't support serialization. Nullifier sync operations should not be mocked. +impl MockResponse for NullifiersTrunkState { + fn mock_serialize(&self, _sdk: &MockDashPlatformSdk) -> Vec { + unimplemented!("NullifiersTrunkState does not support mock serialization - the Tree type is not serializable") + } + + fn mock_deserialize(_sdk: &MockDashPlatformSdk, _buf: &[u8]) -> Self + where + Self: Sized, + { + unimplemented!("NullifiersTrunkState does not support mock deserialization - the Tree type is not serializable") + } +} diff --git a/packages/rs-sdk/src/platform.rs b/packages/rs-sdk/src/platform.rs index e7c7b4aa05d..84c80b3fe8f 100644 --- a/packages/rs-sdk/src/platform.rs +++ b/packages/rs-sdk/src/platform.rs @@ -16,6 +16,7 @@ mod fetch_many; mod fetch_unproved; pub mod group_actions; pub mod identities_contract_keys_query; +pub mod nullifier_sync; pub mod query; pub mod tokens; pub mod transition; diff --git a/packages/rs-sdk/src/platform/address_sync/mod.rs b/packages/rs-sdk/src/platform/address_sync/mod.rs index 0c5b41bd4c2..dda5a166154 100644 --- a/packages/rs-sdk/src/platform/address_sync/mod.rs +++ b/packages/rs-sdk/src/platform/address_sync/mod.rs @@ -37,7 +37,7 @@ //! ``` mod provider; -mod tracker; +pub(crate) mod tracker; mod types; pub use provider::AddressProvider; diff --git a/packages/rs-sdk/src/platform/fetch.rs b/packages/rs-sdk/src/platform/fetch.rs index c3290e462c3..b2dc7d27e52 100644 --- a/packages/rs-sdk/src/platform/fetch.rs +++ b/packages/rs-sdk/src/platform/fetch.rs @@ -385,6 +385,10 @@ impl Fetch for drive_proof_verifier::types::ShieldedNullifierStatuses { type Request = platform_proto::GetShieldedNullifiersRequest; } +impl Fetch for drive_proof_verifier::types::NullifiersTrunkState { + type Request = platform_proto::GetNullifiersTrunkStateRequest; +} + impl Fetch for drive_proof_verifier::types::RecentNullifierChanges { type Request = platform_proto::GetRecentNullifierChangesRequest; } diff --git a/packages/rs-sdk/src/platform/nullifier_sync/mod.rs b/packages/rs-sdk/src/platform/nullifier_sync/mod.rs new file mode 100644 index 00000000000..4abef703172 --- /dev/null +++ b/packages/rs-sdk/src/platform/nullifier_sync/mod.rs @@ -0,0 +1,753 @@ +//! Nullifier synchronization using trunk/branch chunk queries with incremental catch-up. +//! +//! This module provides privacy-preserving nullifier status checking for wallets. +//! It combines two strategies: +//! +//! 1. **Tree scan** (trunk/branch): Privacy-preserving bulk query of the nullifier +//! Merkle tree. Used for initial sync or when the last sync is stale. +//! +//! 2. **Incremental catch-up** (compacted + recent blocks): Fetches nullifier +//! changes block-by-block from a known height to chain tip. Fast for frequent +//! re-syncs. +//! +//! # Sync Modes +//! +//! The behavior depends on [`NullifierSyncConfig::last_sync_height`]: +//! +//! - **`None` or `Some(0)`** — Full tree scan, then incremental catch-up from +//! the tree snapshot to chain tip. +//! - **`Some(height)`** — Incremental-only from that height (unless the height +//! is too old per `full_rescan_after_time_s`, in which case a full scan runs). +//! +//! # Example +//! +//! ```rust,ignore +//! use dash_sdk::Sdk; +//! use dash_sdk::platform::nullifier_sync::NullifierSyncConfig; +//! +//! let nullifiers: Vec<[u8; 32]> = vec![/* ... */]; +//! +//! // First sync — full tree scan + catch-up +//! let result = sdk.sync_nullifiers(&nullifiers, None).await?; +//! let saved_height = result.new_sync_height; +//! +//! // Subsequent sync — incremental only +//! let config = NullifierSyncConfig { +//! last_sync_height: Some(saved_height), +//! ..Default::default() +//! }; +//! let result = sdk.sync_nullifiers(&nullifiers, Some(config)).await?; +//! let saved_height = result.new_sync_height; // store for next time +//! ``` + +mod provider; +mod types; + +pub use provider::NullifierProvider; +pub use types::{NullifierKey, NullifierSyncConfig, NullifierSyncMetrics, NullifierSyncResult}; + +use crate::error::Error; +use crate::platform::address_sync::tracker::KeyLeafTracker; +use crate::platform::Fetch; +use crate::sync::retry; +use crate::Sdk; +use dapi_grpc::platform::v0::{ + get_nullifiers_branch_state_request, get_nullifiers_branch_state_response, + get_recent_compacted_nullifier_changes_request, get_recent_nullifier_changes_request, + GetNullifiersBranchStateRequest, GetRecentCompactedNullifierChangesRequest, + GetRecentNullifierChangesRequest, +}; +use drive::drive::Drive; +use drive::grovedb::{ + calculate_max_tree_depth_from_count, GroveBranchQueryResult, GroveTrunkQueryResult, LeafInfo, +}; +use drive_proof_verifier::types::{ + NullifiersTrunkQuery, NullifiersTrunkState, RecentCompactedNullifierChanges, + RecentNullifierChanges, +}; +use futures::stream::{FuturesUnordered, StreamExt}; +use rs_dapi_client::{ + DapiRequest, ExecutionError, ExecutionResponse, InnerInto, IntoInner, RequestSettings, +}; +use std::collections::{BTreeSet, HashSet}; +use tracing::{debug, trace, warn}; + +use dpp::version::PlatformVersion; + +type LeafBoundaryKey = Vec; + +/// Server limit for compacted nullifier changes per request. +const COMPACTED_BATCH_LIMIT: usize = 25; +/// Server limit for recent nullifier changes per request. +const RECENT_BATCH_LIMIT: usize = 100; + +/// Synchronize nullifier statuses using trunk/branch chunk queries with +/// incremental block-based catch-up. +/// +/// See [module docs](self) for full description of sync modes. +/// +/// # Arguments +/// - `sdk`: The SDK instance for making network requests. +/// - `provider`: An implementation of [`NullifierProvider`] that supplies nullifier keys. +/// - `config`: Optional configuration; uses defaults if `None`. +/// +/// # Returns +/// - `Ok(NullifierSyncResult)`: Contains found (spent) and absent (unspent) nullifiers, +/// plus `new_sync_height` to pass back on the next call. +/// - `Err(Error)`: If the sync fails after exhausting retries. +pub async fn sync_nullifiers( + sdk: &Sdk, + provider: &P, + config: Option, +) -> Result { + let config = config.unwrap_or_default(); + let platform_version = sdk.version(); + + let nullifiers = provider.nullifiers_to_check(); + + let mut result = NullifierSyncResult::new(); + + if nullifiers.is_empty() { + return Ok(result); + } + + // Decide whether to do a full tree scan or incremental-only + let incremental_start = match config.last_sync_height { + Some(height) if height > 0 => { + // Caller has a previous sync height — check if it's fresh enough + if config.full_rescan_after_time_s > 0 { + // TODO: could probe chain tip timestamp here to compare + // For now, if full_rescan_after_time_s > 0, always do full scan + // (the caller can set full_rescan_after_time_s = 0 to skip this) + None + } else { + // Always do incremental when height is provided and threshold is 0 + Some(height) + } + } + _ => None, + }; + + let catch_up_from = if let Some(start_height) = incremental_start { + // Incremental-only mode — skip the tree scan + debug!( + "Nullifier sync: incremental-only from height {}", + start_height + ); + start_height + } else { + // Full tree scan + let scan_height = + full_tree_scan(sdk, &config, &nullifiers, &mut result, platform_version).await?; + scan_height + }; + + // Incremental catch-up from catch_up_from to chain tip + let nullifier_set: HashSet = nullifiers.iter().copied().collect(); + let final_height = incremental_catch_up( + sdk, + &nullifier_set, + catch_up_from, + &mut result, + config.request_settings, + ) + .await?; + + result.new_sync_height = final_height; + + Ok(result) +} + +/// Perform the full trunk/branch tree scan. +/// +/// Returns the checkpoint height from the trunk query. +async fn full_tree_scan( + sdk: &Sdk, + config: &NullifierSyncConfig, + nullifiers: &[NullifierKey], + result: &mut NullifierSyncResult, + platform_version: &PlatformVersion, +) -> Result { + // Step 1: Execute trunk query + let (trunk_result, checkpoint_height) = + execute_trunk_query(sdk, config, config.request_settings, &mut result.metrics).await?; + result.checkpoint_height = checkpoint_height; + + trace!( + "Nullifier trunk query returned {} elements, {} leaf_keys", + trunk_result.elements.len(), + trunk_result.leaf_keys.len() + ); + + // Step 2: Process trunk result + let mut tracker = KeyLeafTracker::new(); + process_trunk_result(&trunk_result, nullifiers, result, &mut tracker); + + // Step 3: Iterative branch queries + let min_query_depth = platform_version + .drive + .methods + .shielded + .nullifiers_query_min_depth; + let max_query_depth = platform_version + .drive + .methods + .shielded + .nullifiers_query_max_depth; + + let mut iterations = 0; + while !tracker.is_empty() && iterations < config.max_iterations { + iterations += 1; + result.metrics.iterations = iterations; + + let leaves_to_query = get_privacy_adjusted_leaves( + &tracker, + &trunk_result, + config.min_privacy_count, + min_query_depth, + max_query_depth, + ); + + if leaves_to_query.is_empty() { + break; + } + + debug!( + "Iteration {}: querying {} leaves for {} remaining nullifiers", + iterations, + leaves_to_query.len(), + tracker.remaining_count() + ); + + let branch_results = execute_branch_queries( + sdk, + config, + &leaves_to_query, + checkpoint_height, + &mut result.metrics, + config.max_concurrent_requests, + config.request_settings, + platform_version, + ) + .await?; + + for (leaf_key, branch_result) in branch_results { + process_branch_result(&branch_result, &leaf_key, result, &mut tracker); + } + } + + if iterations >= config.max_iterations { + warn!( + "Nullifier sync reached max iterations ({}) with {} keys remaining", + config.max_iterations, + tracker.remaining_count() + ); + } + + Ok(checkpoint_height) +} + +/// Perform incremental block-based catch-up using compacted + recent nullifier +/// changes RPCs. +/// +/// Returns the final sync height (highest block height seen + 1). +async fn incremental_catch_up( + sdk: &Sdk, + nullifier_set: &HashSet, + start_height: u64, + result: &mut NullifierSyncResult, + settings: RequestSettings, +) -> Result { + let mut current_height = start_height; + + // Phase 1 — Compacted (historical) catch-up + loop { + let request = GetRecentCompactedNullifierChangesRequest { + version: Some( + get_recent_compacted_nullifier_changes_request::Version::V0( + get_recent_compacted_nullifier_changes_request::GetRecentCompactedNullifierChangesRequestV0 { + start_block_height: current_height, + prove: true, + }, + ), + ), + }; + + let changes: Option = + RecentCompactedNullifierChanges::fetch_with_settings(sdk, request, settings).await?; + + let entries = match changes { + Some(c) => c.into_inner(), + None => break, + }; + + if entries.is_empty() { + break; + } + + let entry_count = entries.len(); + result.metrics.compacted_queries += 1; + + for entry in &entries { + for nf_bytes in &entry.nullifiers { + if nullifier_set.contains(nf_bytes) { + result.found.insert(*nf_bytes); + } + } + if entry.end_block_height + 1 > current_height { + current_height = entry.end_block_height + 1; + } + } + + if entry_count < COMPACTED_BATCH_LIMIT { + break; + } + } + + // Phase 2 — Recent (per-block) changes + loop { + let request = GetRecentNullifierChangesRequest { + version: Some(get_recent_nullifier_changes_request::Version::V0( + get_recent_nullifier_changes_request::GetRecentNullifierChangesRequestV0 { + start_height: current_height, + prove: true, + }, + )), + }; + + let changes: Option = + RecentNullifierChanges::fetch_with_settings(sdk, request, settings).await?; + + let entries = match changes { + Some(c) => c.into_inner(), + None => break, + }; + + if entries.is_empty() { + break; + } + + let entry_count = entries.len(); + result.metrics.recent_queries += 1; + + for entry in &entries { + for nf_bytes in &entry.nullifiers { + if nullifier_set.contains(nf_bytes) { + result.found.insert(*nf_bytes); + } + } + if entry.block_height + 1 > current_height { + current_height = entry.block_height + 1; + } + } + + if entry_count < RECENT_BATCH_LIMIT { + break; + } + } + + Ok(current_height) +} + +// ── Tree scan helpers ──────────────────────────────────────────────── + +/// Execute the trunk query and return the verified result. +async fn execute_trunk_query( + sdk: &Sdk, + config: &NullifierSyncConfig, + settings: RequestSettings, + metrics: &mut NullifierSyncMetrics, +) -> Result<(GroveTrunkQueryResult, u64), Error> { + let trunk_query = NullifiersTrunkQuery { + pool_type: config.pool_type, + pool_identifier: config.pool_identifier.clone(), + }; + + let (trunk_state, metadata) = + NullifiersTrunkState::fetch_with_metadata(sdk, trunk_query, Some(settings)).await?; + + metrics.trunk_queries += 1; + + let trunk_state = trunk_state.ok_or_else(|| { + Error::InvalidProvedResponse("Nullifier trunk query returned no state".to_string()) + })?; + + metrics.total_elements_seen += trunk_state.elements.len(); + + Ok((trunk_state.into_inner(), metadata.height)) +} + +/// Process the trunk query result. +fn process_trunk_result( + trunk_result: &GroveTrunkQueryResult, + nullifiers: &[NullifierKey], + result: &mut NullifierSyncResult, + tracker: &mut KeyLeafTracker, +) { + for key in nullifiers { + let key_vec = key.to_vec(); + + if trunk_result.elements.contains_key(&key_vec) { + // Nullifier found in tree — the note is spent + result.found.insert(*key); + } else if let Some((leaf_key, info)) = trunk_result.trace_key_to_leaf(&key_vec) { + // Not in trunk elements, but traces to a leaf subtree + tracker.add_key(key_vec, leaf_key, info); + } else { + // Proven absent — the note is unspent + result.absent.insert(*key); + } + } +} + +/// Get privacy-adjusted leaves to query. +/// +/// For leaves with count below min_privacy_count, find an ancestor with sufficient count. +fn get_privacy_adjusted_leaves( + tracker: &KeyLeafTracker, + trunk_result: &GroveTrunkQueryResult, + min_privacy_count: u64, + min_query_depth: u8, + max_query_depth: u8, +) -> Vec<(LeafBoundaryKey, LeafInfo, u8)> { + let active_leaves = tracker.active_leaves(); + let mut result = Vec::new(); + let mut seen_ancestors: BTreeSet = BTreeSet::new(); + + for (leaf_key, info) in active_leaves { + let count = info.count.unwrap_or(0); + let tree_depth = calculate_max_tree_depth_from_count(count); + let clamped_depth = tree_depth.clamp(min_query_depth, max_query_depth); + + if count >= min_privacy_count { + if seen_ancestors.insert(leaf_key.clone()) { + result.push((leaf_key, info, clamped_depth)); + } + } else if let Some((levels_up, ancestor_count, ancestor_key, ancestor_hash)) = + trunk_result.get_ancestor(&leaf_key, min_privacy_count) + { + if seen_ancestors.insert(ancestor_key.clone()) { + let ancestor_info = LeafInfo { + hash: ancestor_hash, + count: Some(ancestor_count), + }; + let depth = tree_depth + .saturating_sub(levels_up) + .clamp(min_query_depth, max_query_depth); + result.push((ancestor_key, ancestor_info, depth)); + } + } else { + // No suitable ancestor found, use the leaf anyway + if seen_ancestors.insert(leaf_key.clone()) { + result.push((leaf_key, info, clamped_depth)); + } + } + } + + result +} + +/// Execute branch queries in parallel. +async fn execute_branch_queries( + sdk: &Sdk, + config: &NullifierSyncConfig, + leaves: &[(LeafBoundaryKey, LeafInfo, u8)], + checkpoint_height: u64, + metrics: &mut NullifierSyncMetrics, + max_concurrent: usize, + settings: RequestSettings, + platform_version: &PlatformVersion, +) -> Result, Error> { + let mut futures = FuturesUnordered::new(); + let mut results = Vec::new(); + + for (leaf_key, info, depth) in leaves.iter().cloned() { + let sdk = sdk.clone(); + let expected_hash = info.hash; + let depth_u32 = depth as u32; + let pool_type = config.pool_type; + let pool_identifier = config.pool_identifier.clone(); + + futures.push(async move { + execute_single_branch_query( + &sdk, + pool_type, + pool_identifier.as_deref(), + leaf_key.clone(), + depth_u32, + expected_hash, + checkpoint_height, + settings, + platform_version, + ) + .await + .map(|result| (leaf_key, result)) + }); + + // Limit concurrency + if futures.len() >= max_concurrent { + if let Some(result) = futures.next().await { + match result { + Ok((key, branch_result)) => { + metrics.branch_queries += 1; + results.push((key, branch_result)); + } + Err(e) => { + warn!("Nullifier branch query failed: {:?}", e); + } + } + } + } + } + + // Collect remaining futures + while let Some(result) = futures.next().await { + match result { + Ok((key, branch_result)) => { + metrics.branch_queries += 1; + results.push((key, branch_result)); + } + Err(e) => { + warn!("Nullifier branch query failed: {:?}", e); + } + } + } + + Ok(results) +} + +/// Execute a single branch query with retry logic. +async fn execute_single_branch_query( + sdk: &Sdk, + pool_type: u32, + pool_identifier: Option<&[u8]>, + key: LeafBoundaryKey, + depth: u32, + expected_hash: [u8; 32], + checkpoint_height: u64, + settings: RequestSettings, + platform_version: &PlatformVersion, +) -> Result { + let pool_id_owned = pool_identifier.map(|p| p.to_vec()); + + let request = GetNullifiersBranchStateRequest { + version: Some(get_nullifiers_branch_state_request::Version::V0( + get_nullifiers_branch_state_request::GetNullifiersBranchStateRequestV0 { + pool_type, + pool_identifier: pool_id_owned.clone().unwrap_or_default(), + key: key.clone(), + depth, + checkpoint_height, + }, + )), + }; + + let fut = |settings: RequestSettings| { + let request = request.clone(); + let key = key.clone(); + let pool_id_owned = pool_id_owned.clone(); + async move { + let ExecutionResponse { + address, + retries, + inner: response, + } = request + .execute(sdk, settings) + .await + .map_err(|execution_error| execution_error.inner_into())?; + + // Extract merk proof + let proof_bytes = match response.version { + Some(get_nullifiers_branch_state_response::Version::V0(v0)) => v0.merk_proof, + None => { + return Err(ExecutionError { + inner: Error::Proof(drive_proof_verifier::Error::EmptyVersion), + address: Some(address), + retries, + }); + } + }; + + // Verify the proof + let branch_result = Drive::verify_nullifiers_branch_query( + &proof_bytes, + pool_type, + pool_id_owned.as_deref(), + key, + depth as u8, + expected_hash, + platform_version, + ) + .map_err(|e| ExecutionError { + inner: e.into(), + address: Some(address.clone()), + retries, + })?; + + Ok(ExecutionResponse { + inner: branch_result, + address, + retries, + }) + } + }; + + let settings = sdk.dapi_client_settings.override_by(settings); + + retry(sdk.address_list(), settings, fut).await.into_inner() +} + +/// Process a branch query result for nullifier presence. +fn process_branch_result( + branch_result: &GroveBranchQueryResult, + queried_leaf_key: &[u8], + result: &mut NullifierSyncResult, + tracker: &mut KeyLeafTracker, +) { + let target_keys = tracker.keys_for_leaf(queried_leaf_key); + + for target_key in target_keys { + if branch_result.elements.contains_key(&target_key) { + // Nullifier found — note is spent + if let Ok(nf) = <[u8; 32]>::try_from(target_key.as_slice()) { + result.found.insert(nf); + } + tracker.key_found(&target_key); + } else if let Some((new_leaf_key, info)) = branch_result.trace_key_to_leaf(&target_key) { + // Traces to a deeper leaf — need another iteration + tracker.update_leaf(&target_key, new_leaf_key, info); + } else { + // Proven absent — note is unspent + if let Ok(nf) = <[u8; 32]>::try_from(target_key.as_slice()) { + result.absent.insert(nf); + } + tracker.key_found(&target_key); // Remove from tracking + } + } + + result.metrics.total_elements_seen += branch_result.elements.len(); +} + +// ── SDK integration ────────────────────────────────────────────────── + +impl Sdk { + /// Synchronize nullifier statuses with incremental catch-up support. + /// + /// This is the main entry point for nullifier synchronization. It handles + /// both full tree scans and incremental block-based catch-up, depending on + /// the configuration. + /// + /// # Sync Modes + /// + /// - **Full scan** (default): Queries the nullifier Merkle tree using + /// privacy-preserving trunk/branch chunk queries, then catches up to + /// chain tip using block-based incremental queries. + /// + /// - **Incremental**: When `last_sync_height` is set in the config, skips + /// the tree scan and only fetches nullifier changes since that height. + /// + /// # Arguments + /// - `provider`: An implementation of [`NullifierProvider`] that supplies nullifier keys. + /// - `config`: Optional configuration; uses defaults if `None`. + /// + /// # Returns + /// - `Ok(NullifierSyncResult)`: Contains found (spent) and absent (unspent) nullifiers, + /// plus `new_sync_height` to store for the next call. + /// - `Err(Error)`: If the sync fails after exhausting retries. + /// + /// # Example + /// + /// ```rust,ignore + /// use dash_sdk::Sdk; + /// use dash_sdk::platform::nullifier_sync::NullifierSyncConfig; + /// + /// let sdk = Sdk::new(/* ... */); + /// let nullifiers: Vec<[u8; 32]> = vec![/* known nullifiers */]; + /// + /// // First call — full scan + /// let result = sdk.sync_nullifiers(&nullifiers, None).await?; + /// let height = result.new_sync_height; + /// + /// // Next call — incremental only + /// let config = NullifierSyncConfig { + /// last_sync_height: Some(height), + /// ..Default::default() + /// }; + /// let result = sdk.sync_nullifiers(&nullifiers, Some(config)).await?; + /// ``` + pub async fn sync_nullifiers( + &self, + provider: &P, + config: Option, + ) -> Result { + sync_nullifiers(self, provider, config).await + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_vec_provider() { + let nullifiers: Vec = vec![[0u8; 32], [1u8; 32]]; + let result = nullifiers.nullifiers_to_check(); + assert_eq!(result.len(), 2); + } + + #[test] + fn test_btreeset_provider() { + let mut set = BTreeSet::new(); + set.insert([0u8; 32]); + set.insert([1u8; 32]); + let result = set.nullifiers_to_check(); + assert_eq!(result.len(), 2); + } + + #[test] + fn test_slice_provider() { + let nullifiers = [[0u8; 32], [1u8; 32]]; + let slice: &[NullifierKey] = &nullifiers; + let result = slice.nullifiers_to_check(); + assert_eq!(result.len(), 2); + } + + #[test] + fn test_empty_provider_returns_empty() { + let nullifiers: Vec = vec![]; + let result = nullifiers.nullifiers_to_check(); + assert!(result.is_empty()); + } + + #[test] + fn test_default_config() { + let config = NullifierSyncConfig::default(); + assert_eq!(config.min_privacy_count, 32); + assert_eq!(config.max_concurrent_requests, 10); + assert_eq!(config.max_iterations, 50); + assert_eq!(config.pool_type, 0); + assert!(config.pool_identifier.is_none()); + assert!(config.last_sync_height.is_none()); + assert_eq!(config.full_rescan_after_time_s, 0); + } + + #[test] + fn test_result_default() { + let result = NullifierSyncResult::new(); + assert!(result.found.is_empty()); + assert!(result.absent.is_empty()); + assert_eq!(result.checkpoint_height, 0); + assert_eq!(result.new_sync_height, 0); + assert_eq!(result.metrics.total_queries(), 0); + } + + #[test] + fn test_metrics_total_queries() { + let mut metrics = NullifierSyncMetrics::default(); + metrics.trunk_queries = 1; + metrics.branch_queries = 3; + metrics.compacted_queries = 2; + metrics.recent_queries = 1; + assert_eq!(metrics.total_queries(), 7); + } +} diff --git a/packages/rs-sdk/src/platform/nullifier_sync/provider.rs b/packages/rs-sdk/src/platform/nullifier_sync/provider.rs new file mode 100644 index 00000000000..c9f90154ade --- /dev/null +++ b/packages/rs-sdk/src/platform/nullifier_sync/provider.rs @@ -0,0 +1,42 @@ +//! Nullifier provider trait for nullifier synchronization. + +use super::types::NullifierKey; +use std::collections::BTreeSet; + +/// Trait for providing nullifier keys to check against the nullifier tree. +/// +/// Unlike [`AddressProvider`](crate::platform::address_sync::AddressProvider), +/// this trait is simpler — no gap limit, no index, no callbacks that extend the set. +/// It just provides a fixed set of nullifier keys to check. +/// +/// # Example +/// +/// ```rust,ignore +/// use dash_sdk::platform::nullifier_sync::NullifierProvider; +/// +/// let nullifiers: Vec<[u8; 32]> = vec![[0u8; 32], [1u8; 32]]; +/// // Vec<[u8; 32]> implements NullifierProvider directly +/// let result = sdk.sync_nullifiers(&nullifiers, None).await?; +/// ``` +pub trait NullifierProvider: Send { + /// Get the set of nullifier keys to check. + fn nullifiers_to_check(&self) -> Vec; +} + +impl NullifierProvider for Vec { + fn nullifiers_to_check(&self) -> Vec { + self.clone() + } +} + +impl NullifierProvider for BTreeSet { + fn nullifiers_to_check(&self) -> Vec { + self.iter().copied().collect() + } +} + +impl NullifierProvider for &[NullifierKey] { + fn nullifiers_to_check(&self) -> Vec { + self.to_vec() + } +} diff --git a/packages/rs-sdk/src/platform/nullifier_sync/types.rs b/packages/rs-sdk/src/platform/nullifier_sync/types.rs new file mode 100644 index 00000000000..e80afd26f27 --- /dev/null +++ b/packages/rs-sdk/src/platform/nullifier_sync/types.rs @@ -0,0 +1,160 @@ +//! Types for nullifier synchronization. + +use rs_dapi_client::RequestSettings; +use std::collections::BTreeSet; + +/// A 32-byte nullifier key. +pub type NullifierKey = [u8; 32]; + +/// Configuration for nullifier synchronization. +#[derive(Debug, Clone)] +pub struct NullifierSyncConfig { + /// Minimum privacy count - subtrees smaller than this will be expanded + /// to include ancestor subtrees for better privacy. + /// + /// Default: 32 + pub min_privacy_count: u64, + + /// Maximum concurrent branch queries. + /// + /// Default: 10 + pub max_concurrent_requests: usize, + + /// Maximum number of iterations (safety limit). + /// + /// Default: 50 + pub max_iterations: usize, + + /// The shielded pool type (0 = credit, 1 = main token, 2 = individual token). + /// + /// Default: 0 (credit pool) + pub pool_type: u32, + + /// Optional 32-byte identifier for individual token pools. + /// + /// Default: None + pub pool_identifier: Option>, + + /// Last sync height from a previous call. + /// + /// - `None` or `Some(0)` — perform a full trunk/branch tree scan, then + /// incremental block-based catch-up from the trunk snapshot to chain tip. + /// - `Some(height)` — if the height is recent enough (within + /// [`full_rescan_after_time_s`](Self::full_rescan_after_time_s) seconds + /// of current time), skip the tree scan and only do incremental + /// block-based catch-up from that height. + /// + /// The caller should store [`NullifierSyncResult::new_sync_height`] after + /// each call and pass it back here on the next call. + pub last_sync_height: Option, + + /// Maximum age in seconds before a full tree rescan is forced. + /// + /// When [`last_sync_height`](Self::last_sync_height) is provided, the + /// function compares the metadata timestamp of a lightweight probe against + /// the last sync time. If the gap exceeds this threshold, a full rescan + /// is performed instead of incremental catch-up. + /// + /// Set to `0` to always do incremental when a height is provided (the + /// caller can reset `last_sync_height` to `None` when they want a full + /// rescan). + /// + /// Default: 0 (always incremental when height is provided) + pub full_rescan_after_time_s: u64, + + /// Request settings for nullifier sync queries. + pub request_settings: RequestSettings, +} + +impl Default for NullifierSyncConfig { + fn default() -> Self { + Self { + min_privacy_count: 32, + max_concurrent_requests: 10, + max_iterations: 50, + pool_type: 0, + pool_identifier: None, + last_sync_height: None, + full_rescan_after_time_s: 0, + request_settings: RequestSettings::default(), + } + } +} + +/// Result of nullifier synchronization. +#[derive(Debug)] +pub struct NullifierSyncResult { + /// Nullifiers found in the tree (spent). + pub found: BTreeSet, + + /// Nullifiers proven absent from the tree (unspent). + pub absent: BTreeSet, + + /// Metrics about the sync process. + pub metrics: NullifierSyncMetrics, + + /// The checkpoint height from the trunk/branch scan. + /// + /// This is the block height at which the tree snapshot was taken. + /// Only meaningful when a full tree scan was performed. + pub checkpoint_height: u64, + + /// The new sync height to pass back on the next call as + /// [`NullifierSyncConfig::last_sync_height`]. + /// + /// This is the highest block height seen from the incremental phase + /// (or the checkpoint height if no incremental phase ran). The caller + /// should store this and pass it back on the next call. + pub new_sync_height: u64, +} + +impl NullifierSyncResult { + /// Create a new empty result. + pub fn new() -> Self { + Self { + found: BTreeSet::new(), + absent: BTreeSet::new(), + metrics: NullifierSyncMetrics::default(), + checkpoint_height: 0, + new_sync_height: 0, + } + } +} + +impl Default for NullifierSyncResult { + fn default() -> Self { + Self::new() + } +} + +/// Metrics about the nullifier synchronization process. +#[derive(Debug, Default, Clone)] +pub struct NullifierSyncMetrics { + /// Number of trunk queries (0 for incremental-only, 1 for full scan). + pub trunk_queries: usize, + + /// Number of branch queries. + pub branch_queries: usize, + + /// Total elements seen across all proofs. + pub total_elements_seen: usize, + + /// Total proof bytes received. + pub total_proof_bytes: usize, + + /// Number of branch iterations (0 = trunk only, 1+ = trunk plus branch rounds). + pub iterations: usize, + + /// Number of compacted incremental queries. + pub compacted_queries: usize, + + /// Number of recent incremental queries. + pub recent_queries: usize, +} + +impl NullifierSyncMetrics { + /// Get total number of queries (trunk + branch + incremental). + pub fn total_queries(&self) -> usize { + self.trunk_queries + self.branch_queries + self.compacted_queries + self.recent_queries + } +} diff --git a/packages/rs-sdk/src/platform/query.rs b/packages/rs-sdk/src/platform/query.rs index 2d4e9e78682..070c91cf41d 100644 --- a/packages/rs-sdk/src/platform/query.rs +++ b/packages/rs-sdk/src/platform/query.rs @@ -28,9 +28,10 @@ use dapi_grpc::platform::v0::{ GetTotalCreditsInPlatformRequest, KeyRequestType, }; use dapi_grpc::platform::v0::{ - get_shielded_anchors_request, get_shielded_encrypted_notes_request, - get_shielded_nullifiers_request, get_shielded_pool_state_request, get_status_request, - GetContestedResourceIdentityVotesRequest, GetPrefundedSpecializedBalanceRequest, + get_nullifiers_trunk_state_request, get_shielded_anchors_request, + get_shielded_encrypted_notes_request, get_shielded_nullifiers_request, + get_shielded_pool_state_request, get_status_request, GetContestedResourceIdentityVotesRequest, + GetNullifiersTrunkStateRequest, GetPrefundedSpecializedBalanceRequest, GetShieldedAnchorsRequest, GetShieldedEncryptedNotesRequest, GetShieldedNullifiersRequest, GetShieldedPoolStateRequest, GetStatusRequest, GetTokenDirectPurchasePricesRequest, GetTokenPerpetualDistributionLastClaimRequest, GetVotePollsByEndDateRequest, SpecificKeys, @@ -47,7 +48,8 @@ use drive::query::vote_polls_by_document_type_query::VotePollsByDocumentTypeQuer use drive::query::{DriveDocumentQuery, VotePollsByEndDateDriveQuery}; use drive_proof_verifier::from_request::TryFromRequest; use drive_proof_verifier::types::{ - KeysInPath, NoParamQuery, ShieldedEncryptedNotesQuery, ShieldedNullifiersQuery, + KeysInPath, NoParamQuery, NullifiersTrunkQuery, ShieldedEncryptedNotesQuery, + ShieldedNullifiersQuery, }; use rs_dapi_client::transport::TransportRequest; use std::collections::BTreeSet; @@ -1052,3 +1054,20 @@ impl Query for ShieldedNullifiersQuery { }) } } + +impl Query for NullifiersTrunkQuery { + fn query(self, prove: bool) -> Result { + if !prove { + unimplemented!("queries without proofs are not supported yet"); + } + + Ok(GetNullifiersTrunkStateRequest { + version: Some(get_nullifiers_trunk_state_request::Version::V0( + get_nullifiers_trunk_state_request::GetNullifiersTrunkStateRequestV0 { + pool_type: self.pool_type, + pool_identifier: self.pool_identifier.unwrap_or_default(), + }, + )), + }) + } +} From 4f2b77b59b72df8419f4c6c5e32c58b4da267d15 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 24 Feb 2026 14:46:15 +0700 Subject: [PATCH 29/40] more work --- Cargo.lock | 30 +-- packages/rs-dpp/Cargo.toml | 2 +- packages/rs-drive-abci/Cargo.toml | 4 +- packages/rs-drive/Cargo.toml | 12 +- packages/rs-platform-version/Cargo.toml | 2 +- .../drive_abci_validation_versions/v8.rs | 43 ++++ packages/rs-sdk/Cargo.toml | 2 +- .../rs-sdk/src/platform/nullifier_sync/mod.rs | 206 +++++++++++------- .../src/platform/nullifier_sync/provider.rs | 2 +- .../src/platform/nullifier_sync/types.rs | 51 ++--- 10 files changed, 225 insertions(+), 129 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d51930e7731..1568bab25ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2614,7 +2614,7 @@ dependencies = [ [[package]] name = "grovedb" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" +source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" dependencies = [ "axum 0.8.8", "bincode", @@ -2652,7 +2652,7 @@ dependencies = [ [[package]] name = "grovedb-bulk-append-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" +source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" dependencies = [ "bincode", "blake3", @@ -2668,7 +2668,7 @@ dependencies = [ [[package]] name = "grovedb-commitment-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" +source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" dependencies = [ "incrementalmerkletree", "orchard", @@ -2680,7 +2680,7 @@ dependencies = [ [[package]] name = "grovedb-costs" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" +source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" dependencies = [ "integer-encoding", "intmap", @@ -2690,7 +2690,7 @@ dependencies = [ [[package]] name = "grovedb-dense-fixed-sized-merkle-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" +source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" dependencies = [ "bincode", "blake3", @@ -2703,7 +2703,7 @@ dependencies = [ [[package]] name = "grovedb-element" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" +source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" dependencies = [ "bincode", "bincode_derive", @@ -2718,7 +2718,7 @@ dependencies = [ [[package]] name = "grovedb-epoch-based-storage-flags" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" +source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" dependencies = [ "grovedb-costs", "hex", @@ -2730,7 +2730,7 @@ dependencies = [ [[package]] name = "grovedb-merk" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" +source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" dependencies = [ "bincode", "bincode_derive", @@ -2756,7 +2756,7 @@ dependencies = [ [[package]] name = "grovedb-merkle-mountain-range" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" +source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" dependencies = [ "bincode", "blake3", @@ -2767,7 +2767,7 @@ dependencies = [ [[package]] name = "grovedb-path" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" +source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" dependencies = [ "hex", ] @@ -2775,7 +2775,7 @@ dependencies = [ [[package]] name = "grovedb-query" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" +source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" dependencies = [ "bincode", "byteorder", @@ -2791,7 +2791,7 @@ dependencies = [ [[package]] name = "grovedb-storage" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" +source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" dependencies = [ "blake3", "grovedb-costs", @@ -2810,7 +2810,7 @@ dependencies = [ [[package]] name = "grovedb-version" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" +source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" dependencies = [ "thiserror 2.0.18", "versioned-feature-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2819,7 +2819,7 @@ dependencies = [ [[package]] name = "grovedb-visualize" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" +source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" dependencies = [ "hex", "itertools 0.14.0", @@ -2828,7 +2828,7 @@ dependencies = [ [[package]] name = "grovedbg-types" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=679ea5a230a9d2e584ac2949ecac179a179a0444#679ea5a230a9d2e584ac2949ecac179a179a0444" +source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" dependencies = [ "serde", "serde_with 3.16.1", diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index 3307f8b3653..4b96153d1dc 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -71,7 +71,7 @@ strum = { version = "0.26", features = ["derive"] } json-schema-compatibility-validator = { path = '../rs-json-schema-compatibility-validator', optional = true } once_cell = "1.19.0" tracing = { version = "0.1.41" } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444", optional = true } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18", optional = true } [dev-dependencies] tokio = { version = "1.40", features = ["full"] } diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index 3bc43af9483..8c1fdeb72c0 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -82,7 +82,7 @@ derive_more = { version = "1.0", features = ["from", "deref", "deref_mut"] } async-trait = "0.1.77" console-subscriber = { version = "0.4", optional = true } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f", optional = true } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444" } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18" } sha2 = "0.10" nonempty = "0.11" @@ -105,7 +105,7 @@ dpp = { path = "../rs-dpp", default-features = false, features = [ drive = { path = "../rs-drive", features = ["fixtures-and-mocks"] } drive-proof-verifier = { path = "../rs-drive-proof-verifier" } strategy-tests = { path = "../strategy-tests" } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444", features = ["client"] } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18", features = ["client"] } assert_matches = "1.5.0" drive-abci = { path = ".", features = ["testing-config", "mocks"] } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f" } diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index 89beb64afce..30176528eb7 100644 --- a/packages/rs-drive/Cargo.toml +++ b/packages/rs-drive/Cargo.toml @@ -52,12 +52,12 @@ enum-map = { version = "2.0.3", optional = true } intmap = { version = "3.0.1", features = ["serde"], optional = true } chrono = { version = "0.4.35", optional = true } itertools = { version = "0.13", optional = true } -grovedb = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444", optional = true, default-features = false } -grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444", optional = true } -grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444" } -grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444", optional = true } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444" } -grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444" } +grovedb = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18", optional = true, default-features = false } +grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18", optional = true } +grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18" } +grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18", optional = true } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18" } +grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18" } [dev-dependencies] criterion = "0.5" diff --git a/packages/rs-platform-version/Cargo.toml b/packages/rs-platform-version/Cargo.toml index bd8b8cad15c..c8dac616980 100644 --- a/packages/rs-platform-version/Cargo.toml +++ b/packages/rs-platform-version/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT" thiserror = { version = "2.0.12" } bincode = { version = "=2.0.1" } versioned-feature-core = { git = "https://github.com/dashpay/versioned-feature-core", version = "1.0.0" } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444" } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18" } [features] mock-versions = [] diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v8.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v8.rs index 421541526c8..74d32eb6ef9 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v8.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v8.rs @@ -205,10 +205,51 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V8: DriveAbciValidationVersions = state: 0, transform_into_action: 0, }, + shield_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: Some(0), + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + shielded_transfer_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: Some(0), + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + unshield_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: Some(0), + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + shield_from_asset_lock_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, + shielded_withdrawal_state_transition: DriveAbciStateTransitionValidationVersion { + basic_structure: None, + advanced_structure: None, + identity_signatures: None, + nonce: None, + state: 0, + transform_into_action: 0, + }, }, has_nonce_validation: 1, has_address_witness_validation: 0, validate_address_witnesses: 0, + validate_shielded_proof: 0, process_state_transition: 0, state_transition_to_execution_event_for_check_tx: 0, penalties: PenaltyAmounts { @@ -217,9 +258,11 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V8: DriveAbciValidationVersions = validation_of_added_keys_structure_failure: 10000000, validation_of_added_keys_proof_of_possession_failure: 50000000, address_funds_insufficient_balance: 10000000, + shielded_proof_verification_failure: 50000000, }, event_constants: DriveAbciValidationConstants { maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, + minimum_pool_notes_for_outgoing: 250, }, }; diff --git a/packages/rs-sdk/Cargo.toml b/packages/rs-sdk/Cargo.toml index e48d4d9be22..a51e7639bd5 100644 --- a/packages/rs-sdk/Cargo.toml +++ b/packages/rs-sdk/Cargo.toml @@ -18,7 +18,7 @@ drive = { path = "../rs-drive", default-features = false, features = [ platform-wallet = { path = "../rs-platform-wallet", optional = true } drive-proof-verifier = { path = "../rs-drive-proof-verifier", default-features = false } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "679ea5a230a9d2e584ac2949ecac179a179a0444", features = ["client", "sqlite"], optional = true } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18", features = ["client", "sqlite"], optional = true } dash-context-provider = { path = "../rs-context-provider", default-features = false } dash-platform-macros = { path = "../rs-dash-platform-macros" } http = { version = "1.1" } diff --git a/packages/rs-sdk/src/platform/nullifier_sync/mod.rs b/packages/rs-sdk/src/platform/nullifier_sync/mod.rs index 4abef703172..7eda799fbf1 100644 --- a/packages/rs-sdk/src/platform/nullifier_sync/mod.rs +++ b/packages/rs-sdk/src/platform/nullifier_sync/mod.rs @@ -12,32 +12,32 @@ //! //! # Sync Modes //! -//! The behavior depends on [`NullifierSyncConfig::last_sync_height`]: +//! The behavior depends on the `last_sync_timestamp` parameter passed to +//! [`sync_nullifiers`]: //! -//! - **`None` or `Some(0)`** — Full tree scan, then incremental catch-up from -//! the tree snapshot to chain tip. -//! - **`Some(height)`** — Incremental-only from that height (unless the height -//! is too old per `full_rescan_after_time_s`, in which case a full scan runs). +//! - **`None`** — Full tree scan, then incremental catch-up from the tree +//! snapshot to chain tip. +//! - **`Some(timestamp)`** — Incremental-only from `last_sync_height` +//! (unless the elapsed time exceeds +//! [`NullifierSyncConfig::full_rescan_after_time_s`], in which case a full +//! scan runs). //! //! # Example //! //! ```rust,ignore //! use dash_sdk::Sdk; -//! use dash_sdk::platform::nullifier_sync::NullifierSyncConfig; //! //! let nullifiers: Vec<[u8; 32]> = vec![/* ... */]; //! //! // First sync — full tree scan + catch-up -//! let result = sdk.sync_nullifiers(&nullifiers, None).await?; -//! let saved_height = result.new_sync_height; +//! let result = sdk.sync_nullifiers(&nullifiers, None, None, None).await?; +//! let saved_height = result.new_sync_height; // store for next call +//! let saved_timestamp = result.new_sync_timestamp; // store for next call //! -//! // Subsequent sync — incremental only -//! let config = NullifierSyncConfig { -//! last_sync_height: Some(saved_height), -//! ..Default::default() -//! }; -//! let result = sdk.sync_nullifiers(&nullifiers, Some(config)).await?; -//! let saved_height = result.new_sync_height; // store for next time +//! // Subsequent sync — incremental only (unless too old per full_rescan_after_time_s) +//! let result = sdk.sync_nullifiers(&nullifiers, None, Some(saved_height), Some(saved_timestamp)).await?; +//! let saved_height = result.new_sync_height; +//! let saved_timestamp = result.new_sync_timestamp; //! ``` mod provider; @@ -90,15 +90,27 @@ const RECENT_BATCH_LIMIT: usize = 100; /// - `sdk`: The SDK instance for making network requests. /// - `provider`: An implementation of [`NullifierProvider`] that supplies nullifier keys. /// - `config`: Optional configuration; uses defaults if `None`. +/// - `last_sync_height`: Optional block height from the previous sync's +/// [`NullifierSyncResult::new_sync_height`]. Used as the starting point for +/// incremental-only catch-up. +/// - `last_sync_timestamp`: Optional block time (Unix seconds) from the previous +/// sync's [`NullifierSyncResult::new_sync_timestamp`]. When provided together +/// with a non-zero [`NullifierSyncConfig::full_rescan_after_time_s`], the +/// function compares `now - last_sync_timestamp` to decide whether a full tree +/// rescan is needed or incremental-only catch-up suffices. +/// Pass `None` to always perform a full tree scan. /// /// # Returns -/// - `Ok(NullifierSyncResult)`: Contains found (spent) and absent (unspent) nullifiers, -/// plus `new_sync_height` to pass back on the next call. +/// - `Ok(NullifierSyncResult)`: Contains found (spent) and absent (unspent) +/// nullifiers, plus `new_sync_height` and `new_sync_timestamp` to persist +/// for the next call. /// - `Err(Error)`: If the sync fails after exhausting retries. pub async fn sync_nullifiers( sdk: &Sdk, provider: &P, config: Option, + last_sync_height: Option, + last_sync_timestamp: Option, ) -> Result { let config = config.unwrap_or_default(); let platform_version = sdk.version(); @@ -111,25 +123,35 @@ pub async fn sync_nullifiers( return Ok(result); } - // Decide whether to do a full tree scan or incremental-only - let incremental_start = match config.last_sync_height { - Some(height) if height > 0 => { - // Caller has a previous sync height — check if it's fresh enough - if config.full_rescan_after_time_s > 0 { - // TODO: could probe chain tip timestamp here to compare - // For now, if full_rescan_after_time_s > 0, always do full scan - // (the caller can set full_rescan_after_time_s = 0 to skip this) - None + // Decide whether to do a full tree scan or incremental-only. + // + // Incremental-only is chosen when ALL of these are true: + // 1. last_sync_timestamp is provided + // 2. full_rescan_after_time_s > 0 + // 3. elapsed time since last sync < full_rescan_after_time_s + let needs_full_scan = match last_sync_timestamp { + Some(last_ts) if config.full_rescan_after_time_s > 0 => { + let now_secs = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_secs()) + .unwrap_or(0); + let elapsed = now_secs.saturating_sub(last_ts); + if elapsed >= config.full_rescan_after_time_s { + debug!( + "Nullifier sync: full rescan needed (elapsed {}s >= threshold {}s)", + elapsed, config.full_rescan_after_time_s + ); + true } else { - // Always do incremental when height is provided and threshold is 0 - Some(height) + false } } - _ => None, + _ => true, }; - let catch_up_from = if let Some(start_height) = incremental_start { + let catch_up_from = if !needs_full_scan { // Incremental-only mode — skip the tree scan + let start_height = last_sync_height.unwrap_or(0); debug!( "Nullifier sync: incremental-only from height {}", start_height @@ -137,14 +159,15 @@ pub async fn sync_nullifiers( start_height } else { // Full tree scan - let scan_height = + let (scan_height, block_time_ms) = full_tree_scan(sdk, &config, &nullifiers, &mut result, platform_version).await?; + result.new_sync_timestamp = block_time_ms / 1000; scan_height }; // Incremental catch-up from catch_up_from to chain tip let nullifier_set: HashSet = nullifiers.iter().copied().collect(); - let final_height = incremental_catch_up( + incremental_catch_up( sdk, &nullifier_set, catch_up_from, @@ -153,23 +176,21 @@ pub async fn sync_nullifiers( ) .await?; - result.new_sync_height = final_height; - Ok(result) } /// Perform the full trunk/branch tree scan. /// -/// Returns the checkpoint height from the trunk query. +/// Returns `(checkpoint_height, block_time_ms)` from the trunk query. async fn full_tree_scan( sdk: &Sdk, config: &NullifierSyncConfig, nullifiers: &[NullifierKey], result: &mut NullifierSyncResult, platform_version: &PlatformVersion, -) -> Result { +) -> Result<(u64, u64), Error> { // Step 1: Execute trunk query - let (trunk_result, checkpoint_height) = + let (trunk_result, checkpoint_height, block_time_ms) = execute_trunk_query(sdk, config, config.request_settings, &mut result.metrics).await?; result.checkpoint_height = checkpoint_height; @@ -244,21 +265,22 @@ async fn full_tree_scan( ); } - Ok(checkpoint_height) + Ok((checkpoint_height, block_time_ms)) } /// Perform incremental block-based catch-up using compacted + recent nullifier /// changes RPCs. /// -/// Returns the final sync height (highest block height seen + 1). +/// Updates `result.new_sync_height` and `result.new_sync_timestamp`. async fn incremental_catch_up( sdk: &Sdk, nullifier_set: &HashSet, start_height: u64, result: &mut NullifierSyncResult, settings: RequestSettings, -) -> Result { +) -> Result<(), Error> { let mut current_height = start_height; + let mut had_successful_query = false; // Phase 1 — Compacted (historical) catch-up loop { @@ -273,20 +295,35 @@ async fn incremental_catch_up( ), }; - let changes: Option = - RecentCompactedNullifierChanges::fetch_with_settings(sdk, request, settings).await?; + let (changes, metadata): (Option, _) = + match RecentCompactedNullifierChanges::fetch_with_metadata(sdk, request, Some(settings)) + .await + { + Ok(result) => result, + Err(e) if !had_successful_query => { + debug!( + "Compacted nullifier changes query failed (non-fatal): {}", + e + ); + break; + } + Err(e) => return Err(e), + }; let entries = match changes { Some(c) => c.into_inner(), None => break, }; + result.new_sync_timestamp = metadata.time_ms / 1000; + if entries.is_empty() { break; } let entry_count = entries.len(); result.metrics.compacted_queries += 1; + had_successful_query = true; for entry in &entries { for nf_bytes in &entry.nullifiers { @@ -294,8 +331,8 @@ async fn incremental_catch_up( result.found.insert(*nf_bytes); } } - if entry.end_block_height + 1 > current_height { - current_height = entry.end_block_height + 1; + if entry.end_block_height.saturating_add(1) > current_height { + current_height = entry.end_block_height.saturating_add(1); } } @@ -315,20 +352,30 @@ async fn incremental_catch_up( )), }; - let changes: Option = - RecentNullifierChanges::fetch_with_settings(sdk, request, settings).await?; + let (changes, metadata): (Option, _) = + match RecentNullifierChanges::fetch_with_metadata(sdk, request, Some(settings)).await { + Ok(result) => result, + Err(e) if !had_successful_query => { + debug!("Recent nullifier changes query failed (non-fatal): {}", e); + break; + } + Err(e) => return Err(e), + }; let entries = match changes { Some(c) => c.into_inner(), None => break, }; + result.new_sync_timestamp = metadata.time_ms / 1000; + if entries.is_empty() { break; } let entry_count = entries.len(); result.metrics.recent_queries += 1; + had_successful_query = true; for entry in &entries { for nf_bytes in &entry.nullifiers { @@ -336,8 +383,8 @@ async fn incremental_catch_up( result.found.insert(*nf_bytes); } } - if entry.block_height + 1 > current_height { - current_height = entry.block_height + 1; + if entry.block_height.saturating_add(1) > current_height { + current_height = entry.block_height.saturating_add(1); } } @@ -346,18 +393,21 @@ async fn incremental_catch_up( } } - Ok(current_height) + result.new_sync_height = current_height; + Ok(()) } // ── Tree scan helpers ──────────────────────────────────────────────── /// Execute the trunk query and return the verified result. +/// +/// Returns `(trunk_result, checkpoint_height, block_time_ms)`. async fn execute_trunk_query( sdk: &Sdk, config: &NullifierSyncConfig, settings: RequestSettings, metrics: &mut NullifierSyncMetrics, -) -> Result<(GroveTrunkQueryResult, u64), Error> { +) -> Result<(GroveTrunkQueryResult, u64, u64), Error> { let trunk_query = NullifiersTrunkQuery { pool_type: config.pool_type, pool_identifier: config.pool_identifier.clone(), @@ -374,7 +424,7 @@ async fn execute_trunk_query( metrics.total_elements_seen += trunk_state.elements.len(); - Ok((trunk_state.into_inner(), metadata.height)) + Ok((trunk_state.into_inner(), metadata.height, metadata.time_ms)) } /// Process the trunk query result. @@ -635,52 +685,60 @@ impl Sdk { /// /// This is the main entry point for nullifier synchronization. It handles /// both full tree scans and incremental block-based catch-up, depending on - /// the configuration. - /// - /// # Sync Modes + /// the parameters. /// - /// - **Full scan** (default): Queries the nullifier Merkle tree using - /// privacy-preserving trunk/branch chunk queries, then catches up to - /// chain tip using block-based incremental queries. - /// - /// - **Incremental**: When `last_sync_height` is set in the config, skips - /// the tree scan and only fetches nullifier changes since that height. + /// On subsequent calls, pass [`NullifierSyncResult::new_sync_height`] as + /// `last_sync_height` and [`NullifierSyncResult::new_sync_timestamp`] as + /// `last_sync_timestamp` so the function can decide whether a full tree + /// rescan is needed or incremental-only catch-up suffices. /// /// # Arguments /// - `provider`: An implementation of [`NullifierProvider`] that supplies nullifier keys. /// - `config`: Optional configuration; uses defaults if `None`. + /// - `last_sync_height`: Optional block height from the previous sync's + /// [`NullifierSyncResult::new_sync_height`]. Used as the starting point + /// for incremental-only catch-up. + /// - `last_sync_timestamp`: Optional block time (Unix seconds) from the + /// previous sync's [`NullifierSyncResult::new_sync_timestamp`]. + /// Pass `None` to always perform a full tree scan. /// /// # Returns - /// - `Ok(NullifierSyncResult)`: Contains found (spent) and absent (unspent) nullifiers, - /// plus `new_sync_height` to store for the next call. + /// - `Ok(NullifierSyncResult)`: Contains found (spent) and absent (unspent) + /// nullifiers, `new_sync_height` and `new_sync_timestamp` to store for + /// the next call. /// - `Err(Error)`: If the sync fails after exhausting retries. /// /// # Example /// /// ```rust,ignore /// use dash_sdk::Sdk; - /// use dash_sdk::platform::nullifier_sync::NullifierSyncConfig; /// /// let sdk = Sdk::new(/* ... */); /// let nullifiers: Vec<[u8; 32]> = vec![/* known nullifiers */]; /// /// // First call — full scan - /// let result = sdk.sync_nullifiers(&nullifiers, None).await?; - /// let height = result.new_sync_height; + /// let result = sdk.sync_nullifiers(&nullifiers, None, None, None).await?; + /// let height = result.new_sync_height; // → last_sync_height param + /// let timestamp = result.new_sync_timestamp; // → last_sync_timestamp param /// - /// // Next call — incremental only - /// let config = NullifierSyncConfig { - /// last_sync_height: Some(height), - /// ..Default::default() - /// }; - /// let result = sdk.sync_nullifiers(&nullifiers, Some(config)).await?; + /// // Next call — incremental only if within threshold + /// let result = sdk.sync_nullifiers(&nullifiers, None, Some(height), Some(timestamp)).await?; /// ``` pub async fn sync_nullifiers( &self, provider: &P, config: Option, + last_sync_height: Option, + last_sync_timestamp: Option, ) -> Result { - sync_nullifiers(self, provider, config).await + sync_nullifiers( + self, + provider, + config, + last_sync_height, + last_sync_timestamp, + ) + .await } } @@ -727,8 +785,7 @@ mod tests { assert_eq!(config.max_iterations, 50); assert_eq!(config.pool_type, 0); assert!(config.pool_identifier.is_none()); - assert!(config.last_sync_height.is_none()); - assert_eq!(config.full_rescan_after_time_s, 0); + assert_eq!(config.full_rescan_after_time_s, 7 * 24 * 60 * 60); } #[test] @@ -738,6 +795,7 @@ mod tests { assert!(result.absent.is_empty()); assert_eq!(result.checkpoint_height, 0); assert_eq!(result.new_sync_height, 0); + assert_eq!(result.new_sync_timestamp, 0); assert_eq!(result.metrics.total_queries(), 0); } diff --git a/packages/rs-sdk/src/platform/nullifier_sync/provider.rs b/packages/rs-sdk/src/platform/nullifier_sync/provider.rs index c9f90154ade..659bea58cf0 100644 --- a/packages/rs-sdk/src/platform/nullifier_sync/provider.rs +++ b/packages/rs-sdk/src/platform/nullifier_sync/provider.rs @@ -16,7 +16,7 @@ use std::collections::BTreeSet; /// /// let nullifiers: Vec<[u8; 32]> = vec![[0u8; 32], [1u8; 32]]; /// // Vec<[u8; 32]> implements NullifierProvider directly -/// let result = sdk.sync_nullifiers(&nullifiers, None).await?; +/// let result = sdk.sync_nullifiers(&nullifiers, None, None, None).await?; /// ``` pub trait NullifierProvider: Send { /// Get the set of nullifier keys to check. diff --git a/packages/rs-sdk/src/platform/nullifier_sync/types.rs b/packages/rs-sdk/src/platform/nullifier_sync/types.rs index e80afd26f27..d1a72db6238 100644 --- a/packages/rs-sdk/src/platform/nullifier_sync/types.rs +++ b/packages/rs-sdk/src/platform/nullifier_sync/types.rs @@ -35,31 +35,16 @@ pub struct NullifierSyncConfig { /// Default: None pub pool_identifier: Option>, - /// Last sync height from a previous call. - /// - /// - `None` or `Some(0)` — perform a full trunk/branch tree scan, then - /// incremental block-based catch-up from the trunk snapshot to chain tip. - /// - `Some(height)` — if the height is recent enough (within - /// [`full_rescan_after_time_s`](Self::full_rescan_after_time_s) seconds - /// of current time), skip the tree scan and only do incremental - /// block-based catch-up from that height. - /// - /// The caller should store [`NullifierSyncResult::new_sync_height`] after - /// each call and pass it back here on the next call. - pub last_sync_height: Option, - /// Maximum age in seconds before a full tree rescan is forced. /// - /// When [`last_sync_height`](Self::last_sync_height) is provided, the - /// function compares the metadata timestamp of a lightweight probe against - /// the last sync time. If the gap exceeds this threshold, a full rescan - /// is performed instead of incremental catch-up. + /// When `last_sync_timestamp` is passed to [`sync_nullifiers`](super::sync_nullifiers), + /// the function compares `now - last_sync_timestamp` against this threshold. + /// If the elapsed time exceeds this value, a full tree rescan is performed + /// instead of incremental-only catch-up. /// - /// Set to `0` to always do incremental when a height is provided (the - /// caller can reset `last_sync_height` to `None` when they want a full - /// rescan). + /// Set to `0` to always do a full tree scan regardless of the timestamp. /// - /// Default: 0 (always incremental when height is provided) + /// Default: 604800 (7 days) pub full_rescan_after_time_s: u64, /// Request settings for nullifier sync queries. @@ -74,8 +59,7 @@ impl Default for NullifierSyncConfig { max_iterations: 50, pool_type: 0, pool_identifier: None, - last_sync_height: None, - full_rescan_after_time_s: 0, + full_rescan_after_time_s: 7 * 24 * 60 * 60, request_settings: RequestSettings::default(), } } @@ -99,13 +83,23 @@ pub struct NullifierSyncResult { /// Only meaningful when a full tree scan was performed. pub checkpoint_height: u64, - /// The new sync height to pass back on the next call as - /// [`NullifierSyncConfig::last_sync_height`]. + /// The highest block height seen from the incremental phase + /// (or the checkpoint height if no incremental phase ran). /// - /// This is the highest block height seen from the incremental phase - /// (or the checkpoint height if no incremental phase ran). The caller - /// should store this and pass it back on the next call. + /// After each sync the caller should persist two values: + /// 1. This `new_sync_height` — pass it back as `last_sync_height` on the + /// next call to [`sync_nullifiers`](super::sync_nullifiers). + /// 2. [`new_sync_timestamp`](Self::new_sync_timestamp) — pass it as the + /// `last_sync_timestamp` parameter of [`sync_nullifiers`](super::sync_nullifiers). pub new_sync_height: u64, + + /// Platform block time (Unix seconds) at the point of the latest response. + /// + /// Store this value and pass it back as `last_sync_timestamp` on the next + /// call to [`sync_nullifiers`](super::sync_nullifiers). The function compares + /// it against the current wall-clock time to decide whether a full tree + /// rescan is needed. + pub new_sync_timestamp: u64, } impl NullifierSyncResult { @@ -117,6 +111,7 @@ impl NullifierSyncResult { metrics: NullifierSyncMetrics::default(), checkpoint_height: 0, new_sync_height: 0, + new_sync_timestamp: 0, } } } From 4d7b9be50a3d07c56d72a2721a8307cf2713c833 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Tue, 24 Feb 2026 19:13:37 +0700 Subject: [PATCH 30/40] small fix --- .pnp.cjs | 45 +++++++++++------- ... ajv-npm-8.18.0-6e5e062765-bfed9de827.zip} | Bin 403399 -> 404799 bytes ...st-uri-npm-3.1.0-57fa0b3f3c-818b2c96dc.zip | Bin 0 -> 36384 bytes ...tion-npm-5.27.14-6b646dcae2-bf8194000e.zip | Bin 161804 -> 0 bytes ...ation-npm-5.31.1-810ce63c49-1fff0b2827.zip | Bin 0 -> 164057 bytes packages/rs-sdk/src/sdk.rs | 5 +- 6 files changed, 31 insertions(+), 19 deletions(-) rename .yarn/cache/{ajv-npm-8.12.0-3bf6e30741-b406f3b79b.zip => ajv-npm-8.18.0-6e5e062765-bfed9de827.zip} (50%) create mode 100644 .yarn/cache/fast-uri-npm-3.1.0-57fa0b3f3c-818b2c96dc.zip delete mode 100644 .yarn/cache/systeminformation-npm-5.27.14-6b646dcae2-bf8194000e.zip create mode 100644 .yarn/cache/systeminformation-npm-5.31.1-810ce63c49-1fff0b2827.zip diff --git a/.pnp.cjs b/.pnp.cjs index 9fbc5f58490..61adf25446b 100755 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -2538,7 +2538,7 @@ const RAW_RUNTIME_STATE = ["@dashevo/wasm-dpp", "workspace:packages/wasm-dpp"],\ ["@grpc/grpc-js", "npm:1.14.3"],\ ["@pshenmic/zeromq", "npm:6.0.0-beta.22"],\ - ["ajv", "npm:8.12.0"],\ + ["ajv", "npm:8.18.0"],\ ["bs58", "npm:4.0.1"],\ ["cbor", "npm:8.1.0"],\ ["chai", "npm:4.3.10"],\ @@ -3118,7 +3118,7 @@ const RAW_RUNTIME_STATE = ["@types/bs58", "npm:4.0.4"],\ ["@types/node", "npm:20.19.30"],\ ["@yarnpkg/pnpify", "npm:4.0.0-rc.42"],\ - ["ajv", "npm:8.12.0"],\ + ["ajv", "npm:8.18.0"],\ ["assert", "npm:2.0.0"],\ ["bs58", "npm:4.0.1"],\ ["buffer", "npm:6.0.3"],\ @@ -6738,14 +6738,14 @@ const RAW_RUNTIME_STATE = ],\ "linkType": "HARD"\ }],\ - ["npm:8.12.0", {\ - "packageLocation": "./.yarn/cache/ajv-npm-8.12.0-3bf6e30741-b406f3b79b.zip/node_modules/ajv/",\ + ["npm:8.18.0", {\ + "packageLocation": "./.yarn/cache/ajv-npm-8.18.0-6e5e062765-bfed9de827.zip/node_modules/ajv/",\ "packageDependencies": [\ - ["ajv", "npm:8.12.0"],\ + ["ajv", "npm:8.18.0"],\ ["fast-deep-equal", "npm:3.1.3"],\ + ["fast-uri", "npm:3.1.0"],\ ["json-schema-traverse", "npm:1.0.0"],\ - ["require-from-string", "npm:2.0.2"],\ - ["uri-js", "npm:4.4.1"]\ + ["require-from-string", "npm:2.0.2"]\ ],\ "linkType": "HARD"\ }]\ @@ -6762,7 +6762,7 @@ const RAW_RUNTIME_STATE = "packageLocation": "./.yarn/__virtual__/ajv-formats-virtual-dfbb778217/0/cache/ajv-formats-npm-2.1.1-3cec02eae9-70c263ded2.zip/node_modules/ajv-formats/",\ "packageDependencies": [\ ["@types/ajv", null],\ - ["ajv", "npm:8.12.0"],\ + ["ajv", "npm:8.18.0"],\ ["ajv-formats", "virtual:4954c4a72ee1ac7afec22da3b17d9a937f807567fbfd843f7fb4d48a0c27456b3fd63f5453a6ffa910bcac753ec013f5554ffe0d1c324703fa4d0658622f21bd#npm:2.1.1"]\ ],\ "packagePeers": [\ @@ -6784,7 +6784,7 @@ const RAW_RUNTIME_STATE = "packageLocation": "./.yarn/__virtual__/ajv-keywords-virtual-bf8e723e64/0/cache/ajv-keywords-npm-5.1.0-ee670a3944-5021f96ab7.zip/node_modules/ajv-keywords/",\ "packageDependencies": [\ ["@types/ajv", null],\ - ["ajv", "npm:8.12.0"],\ + ["ajv", "npm:8.18.0"],\ ["ajv-keywords", "virtual:4954c4a72ee1ac7afec22da3b17d9a937f807567fbfd843f7fb4d48a0c27456b3fd63f5453a6ffa910bcac753ec013f5554ffe0d1c324703fa4d0658622f21bd#npm:5.1.0"],\ ["fast-deep-equal", "npm:3.1.3"]\ ],\ @@ -9583,7 +9583,7 @@ const RAW_RUNTIME_STATE = ["@dashevo/withdrawals-contract", "workspace:packages/withdrawals-contract"],\ ["@oclif/core", "npm:3.26.5"],\ ["@oclif/plugin-help", "npm:6.0.5"],\ - ["ajv", "npm:8.12.0"],\ + ["ajv", "npm:8.18.0"],\ ["ajv-formats", "virtual:4954c4a72ee1ac7afec22da3b17d9a937f807567fbfd843f7fb4d48a0c27456b3fd63f5453a6ffa910bcac753ec013f5554ffe0d1c324703fa4d0658622f21bd#npm:2.1.1"],\ ["awilix", "npm:4.3.4"],\ ["begoo", "npm:2.0.2"],\ @@ -9622,7 +9622,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.27.14"],\ + ["systeminformation", "npm:5.31.1"],\ ["table", "npm:6.8.1"],\ ["tar", "npm:7.5.9"],\ ["wrap-ansi", "npm:7.0.0"]\ @@ -11844,6 +11844,15 @@ const RAW_RUNTIME_STATE = "linkType": "HARD"\ }]\ ]],\ + ["fast-uri", [\ + ["npm:3.1.0", {\ + "packageLocation": "./.yarn/cache/fast-uri-npm-3.1.0-57fa0b3f3c-818b2c96dc.zip/node_modules/fast-uri/",\ + "packageDependencies": [\ + ["fast-uri", "npm:3.1.0"]\ + ],\ + "linkType": "HARD"\ + }]\ + ]],\ ["fastest-levenshtein", [\ ["npm:1.0.12", {\ "packageLocation": "./.yarn/cache/fastest-levenshtein-npm-1.0.12-a32b4ef51e-e1a013698d.zip/node_modules/fastest-levenshtein/",\ @@ -19161,7 +19170,7 @@ const RAW_RUNTIME_STATE = "packageLocation": "./.yarn/cache/schema-utils-npm-4.2.0-e822c5b02e-808784735e.zip/node_modules/schema-utils/",\ "packageDependencies": [\ ["@types/json-schema", "npm:7.0.15"],\ - ["ajv", "npm:8.12.0"],\ + ["ajv", "npm:8.18.0"],\ ["ajv-formats", "virtual:4954c4a72ee1ac7afec22da3b17d9a937f807567fbfd843f7fb4d48a0c27456b3fd63f5453a6ffa910bcac753ec013f5554ffe0d1c324703fa4d0658622f21bd#npm:2.1.1"],\ ["ajv-keywords", "virtual:4954c4a72ee1ac7afec22da3b17d9a937f807567fbfd843f7fb4d48a0c27456b3fd63f5453a6ffa910bcac753ec013f5554ffe0d1c324703fa4d0658622f21bd#npm:5.1.0"],\ ["schema-utils", "npm:4.2.0"]\ @@ -19172,7 +19181,7 @@ const RAW_RUNTIME_STATE = "packageLocation": "./.yarn/cache/schema-utils-npm-4.3.0-6f0a75e2e2-86c5a7c72a.zip/node_modules/schema-utils/",\ "packageDependencies": [\ ["@types/json-schema", "npm:7.0.15"],\ - ["ajv", "npm:8.12.0"],\ + ["ajv", "npm:8.18.0"],\ ["ajv-formats", "virtual:4954c4a72ee1ac7afec22da3b17d9a937f807567fbfd843f7fb4d48a0c27456b3fd63f5453a6ffa910bcac753ec013f5554ffe0d1c324703fa4d0658622f21bd#npm:2.1.1"],\ ["ajv-keywords", "virtual:4954c4a72ee1ac7afec22da3b17d9a937f807567fbfd843f7fb4d48a0c27456b3fd63f5453a6ffa910bcac753ec013f5554ffe0d1c324703fa4d0658622f21bd#npm:5.1.0"],\ ["schema-utils", "npm:4.3.0"]\ @@ -19183,7 +19192,7 @@ const RAW_RUNTIME_STATE = "packageLocation": "./.yarn/cache/schema-utils-npm-4.3.3-4954c4a72e-dba77a46ad.zip/node_modules/schema-utils/",\ "packageDependencies": [\ ["@types/json-schema", "npm:7.0.15"],\ - ["ajv", "npm:8.12.0"],\ + ["ajv", "npm:8.18.0"],\ ["ajv-formats", "virtual:4954c4a72ee1ac7afec22da3b17d9a937f807567fbfd843f7fb4d48a0c27456b3fd63f5453a6ffa910bcac753ec013f5554ffe0d1c324703fa4d0658622f21bd#npm:2.1.1"],\ ["ajv-keywords", "virtual:4954c4a72ee1ac7afec22da3b17d9a937f807567fbfd843f7fb4d48a0c27456b3fd63f5453a6ffa910bcac753ec013f5554ffe0d1c324703fa4d0658622f21bd#npm:5.1.0"],\ ["schema-utils", "npm:4.3.3"]\ @@ -20478,10 +20487,10 @@ const RAW_RUNTIME_STATE = }]\ ]],\ ["systeminformation", [\ - ["npm:5.27.14", {\ - "packageLocation": "./.yarn/unplugged/systeminformation-npm-5.27.14-6b646dcae2/node_modules/systeminformation/",\ + ["npm:5.31.1", {\ + "packageLocation": "./.yarn/unplugged/systeminformation-npm-5.31.1-810ce63c49/node_modules/systeminformation/",\ "packageDependencies": [\ - ["systeminformation", "npm:5.27.14"]\ + ["systeminformation", "npm:5.31.1"]\ ],\ "linkType": "HARD"\ }]\ @@ -20490,7 +20499,7 @@ const RAW_RUNTIME_STATE = ["npm:6.8.1", {\ "packageLocation": "./.yarn/cache/table-npm-6.8.1-83abb79e20-512c4f2bfb.zip/node_modules/table/",\ "packageDependencies": [\ - ["ajv", "npm:8.12.0"],\ + ["ajv", "npm:8.18.0"],\ ["lodash.truncate", "npm:4.4.2"],\ ["slice-ansi", "npm:4.0.0"],\ ["string-width", "npm:4.2.3"],\ diff --git a/.yarn/cache/ajv-npm-8.12.0-3bf6e30741-b406f3b79b.zip b/.yarn/cache/ajv-npm-8.18.0-6e5e062765-bfed9de827.zip similarity index 50% rename from .yarn/cache/ajv-npm-8.12.0-3bf6e30741-b406f3b79b.zip rename to .yarn/cache/ajv-npm-8.18.0-6e5e062765-bfed9de827.zip index 0d623ca47df5608ed97c147e17fef3f290fce039..ff78d4b5d26a1cbf7db38172a7404b542ecdda54 100644 GIT binary patch delta 151915 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�WeoUP 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 QsCYJ2n3}X13fXM`2XCyj;Q#;t delta 150918 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 ( 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 y-*xey&(*KcA&OYo^P3>$R(&sY<2mbf2_> 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¼&j5Cu*R? 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¨+urzDogO6L?*r~ya}dC9Mm?WKKD#U;eB8oh24DoR`e_!+jtokxjMup2R5 zQVJN#I1B;O9Sy%TN0Y`0Bl=a9fhn+)n*ivXYP)-LzLN~hBo?m*X_e8pIHnXP7?E&C zw}{coMrZ+)3Lxc3I>vZK-GF#ip@yrR^CHHmuFU}ELyM{OH;N=N8KrioJY1Msi#S-X z-qzUXDl9<#M&SkQ7y{*u2S7)mRW*!Ck%;$PnZQ|pA61exv!SUUrmq{8L)A1so{zEZcq)V+ zFb1G&KY26nwt~peX&MYddw&-z)T>UKj3J{F-lF1ypq`inYAXV)@C2BBfGl*!)8(Sv;s%bDZO!b}M>KevwXw~*QHVBH>mG=8q$_e3t zkZ(#=NC~nL!KLhtS5IW2Z3XfIOC6#0`mOQ;O5++qpqE@Iruss6V3mTY9?M0xFHBj0h%Gh7 zi~_I)N~M|s>~MtT!7`_=qLU~iyS0iEsX`INd~gwHcgi)j*c;X>s|F-93}wb^%1n~j zC{6VV;AF z(i)8vqbx(MW-#;9xK3{nbp$<=2ShixM%)K&P^PJ+;pPu3RZLYsz=JkG%y08fG`-Zd zuy;gt*ODQ(a{ z3hla(5)L9gh<1N-uKn`L!fExQgSKSZMN1eCy9^*!;(Wl$G(cNYqNn+v0)tQENa;ye z4HlhMeyTUDq~3=!RXAdFI~M@Vb18{~buegYgCWNJhn+MJ`F+rA#Rf*QF3|CzQEX(e zk%rJOE27u@2beTU)`YDARWs50okp$}>k9YBEDOuq2o>KN4SXdt5cR~!vpjZAQ5CpA zT2cin0o}M<+iR~=Dg06O&F*8+5Ekv@U+^H%T3vxP(Wo7r6Rk0dkzjZwU8ZP(^#^%F zs#9WUrWckCms?kXc5!nJ1eFt|>0L95wOZnhc)^O@!ZzuWw_|5k_(`(4g*PAU1;o20 zqkXm0dg*-pg)5<4moG43DRXI#WYZ2&wT5^bj@1CC@+S=DIx(o$Ko=65G?BP)0@Q(| z4T_a8Z)D>bxLi3!?tlI^-V47`ZkQM*BmZAWd!!gSv6N_spiTmzP^x1gr?N{Fcfv|L zNunAs6aZLGNupZDO^$~3JYz^

EP{d> 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 literal 0 HcmV?d00001 diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index bdfd001c2eb..d15bfa5f8c8 100644 --- a/packages/rs-sdk/src/sdk.rs +++ b/packages/rs-sdk/src/sdk.rs @@ -246,7 +246,10 @@ impl Sdk { /// respective tolerance will be None regardless of method, to allow disabling staleness checks globally. fn freshness_criteria(&self, method_name: &str) -> (Option, Option) { match method_name { - "get_addresses_trunk_state" | "get_addresses_branch_state" => ( + "get_addresses_trunk_state" + | "get_addresses_branch_state" + | "get_nullifiers_trunk_state" + | "get_nullifiers_branch_state" => ( None, self.metadata_time_tolerance_ms .and(Some(ADDRESS_STATE_TIME_TOLERANCE_MS)), From 34da9a1cb86e267aa80c54f414fa46db424b3cc9 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 25 Feb 2026 07:27:25 +0700 Subject: [PATCH 31/40] more work --- Cargo.lock | 30 +++--- packages/rs-dpp/Cargo.toml | 2 +- packages/rs-dpp/src/errors/consensus/codes.rs | 1 + .../insufficient_shielded_fee_error.rs | 36 ++++++++ .../errors/consensus/state/shielded/mod.rs | 2 + .../src/errors/consensus/state/state_error.rs | 4 + packages/rs-drive-abci/Cargo.toml | 4 +- .../processor/traits/shielded_proof.rs | 92 +++++++++++++++++++ .../state_transition/processor/v0/mod.rs | 29 ++++-- packages/rs-drive/Cargo.toml | 12 +-- .../src/drive/initialization/v3/mod.rs | 2 +- .../src/drive/shielded/estimated_costs.rs | 14 +-- packages/rs-drive/src/drive/shielded/paths.rs | 3 + packages/rs-drive/src/fees/op.rs | 12 +-- .../grove_insert_empty_tree/v0/mod.rs | 8 +- packages/rs-platform-version/Cargo.toml | 2 +- .../drive_abci_validation_versions/mod.rs | 4 + .../drive_abci_validation_versions/v1.rs | 2 + .../drive_abci_validation_versions/v2.rs | 2 + .../drive_abci_validation_versions/v3.rs | 2 + .../drive_abci_validation_versions/v4.rs | 2 + .../drive_abci_validation_versions/v5.rs | 2 + .../drive_abci_validation_versions/v6.rs | 2 + .../drive_abci_validation_versions/v7.rs | 2 + .../drive_abci_validation_versions/v8.rs | 2 + packages/rs-sdk/Cargo.toml | 2 +- 26 files changed, 223 insertions(+), 52 deletions(-) create mode 100644 packages/rs-dpp/src/errors/consensus/state/shielded/insufficient_shielded_fee_error.rs diff --git a/Cargo.lock b/Cargo.lock index 1568bab25ca..47405d25fa5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2614,7 +2614,7 @@ dependencies = [ [[package]] name = "grovedb" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" +source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" dependencies = [ "axum 0.8.8", "bincode", @@ -2652,7 +2652,7 @@ dependencies = [ [[package]] name = "grovedb-bulk-append-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" +source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" dependencies = [ "bincode", "blake3", @@ -2668,7 +2668,7 @@ dependencies = [ [[package]] name = "grovedb-commitment-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" +source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" dependencies = [ "incrementalmerkletree", "orchard", @@ -2680,7 +2680,7 @@ dependencies = [ [[package]] name = "grovedb-costs" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" +source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" dependencies = [ "integer-encoding", "intmap", @@ -2690,7 +2690,7 @@ dependencies = [ [[package]] name = "grovedb-dense-fixed-sized-merkle-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" +source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" dependencies = [ "bincode", "blake3", @@ -2703,7 +2703,7 @@ dependencies = [ [[package]] name = "grovedb-element" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" +source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" dependencies = [ "bincode", "bincode_derive", @@ -2718,7 +2718,7 @@ dependencies = [ [[package]] name = "grovedb-epoch-based-storage-flags" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" +source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" dependencies = [ "grovedb-costs", "hex", @@ -2730,7 +2730,7 @@ dependencies = [ [[package]] name = "grovedb-merk" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" +source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" dependencies = [ "bincode", "bincode_derive", @@ -2756,7 +2756,7 @@ dependencies = [ [[package]] name = "grovedb-merkle-mountain-range" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" +source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" dependencies = [ "bincode", "blake3", @@ -2767,7 +2767,7 @@ dependencies = [ [[package]] name = "grovedb-path" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" +source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" dependencies = [ "hex", ] @@ -2775,7 +2775,7 @@ dependencies = [ [[package]] name = "grovedb-query" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" +source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" dependencies = [ "bincode", "byteorder", @@ -2791,7 +2791,7 @@ dependencies = [ [[package]] name = "grovedb-storage" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" +source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" dependencies = [ "blake3", "grovedb-costs", @@ -2810,7 +2810,7 @@ dependencies = [ [[package]] name = "grovedb-version" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" +source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" dependencies = [ "thiserror 2.0.18", "versioned-feature-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2819,7 +2819,7 @@ dependencies = [ [[package]] name = "grovedb-visualize" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" +source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" dependencies = [ "hex", "itertools 0.14.0", @@ -2828,7 +2828,7 @@ dependencies = [ [[package]] name = "grovedbg-types" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=56120fb5d0f8abfa9038e018115cdb11c51cde18#56120fb5d0f8abfa9038e018115cdb11c51cde18" +source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" dependencies = [ "serde", "serde_with 3.16.1", diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index 4b96153d1dc..3827b7d7156 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -71,7 +71,7 @@ strum = { version = "0.26", features = ["derive"] } json-schema-compatibility-validator = { path = '../rs-json-schema-compatibility-validator', optional = true } once_cell = "1.19.0" tracing = { version = "0.1.41" } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18", optional = true } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de", optional = true } [dev-dependencies] tokio = { version = "1.40", features = ["full"] } diff --git a/packages/rs-dpp/src/errors/consensus/codes.rs b/packages/rs-dpp/src/errors/consensus/codes.rs index 294f2c3ad68..ca5c8800b77 100644 --- a/packages/rs-dpp/src/errors/consensus/codes.rs +++ b/packages/rs-dpp/src/errors/consensus/codes.rs @@ -383,6 +383,7 @@ impl ErrorWithCode for StateError { Self::NullifierAlreadySpentError(_) => 40901, Self::InvalidShieldedProofError(_) => 40902, Self::InsufficientPoolNotesError(_) => 40903, + Self::InsufficientShieldedFeeError(_) => 40904, } } } diff --git a/packages/rs-dpp/src/errors/consensus/state/shielded/insufficient_shielded_fee_error.rs b/packages/rs-dpp/src/errors/consensus/state/shielded/insufficient_shielded_fee_error.rs new file mode 100644 index 00000000000..4bfcd288404 --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/state/shielded/insufficient_shielded_fee_error.rs @@ -0,0 +1,36 @@ +use crate::consensus::state::state_error::StateError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[platform_serialize(unversioned)] +#[error("Insufficient shielded transaction fee: {message}")] +pub struct InsufficientShieldedFeeError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + message: String, +} + +impl InsufficientShieldedFeeError { + pub fn new(message: String) -> Self { + Self { message } + } + + pub fn message(&self) -> &str { + &self.message + } +} + +impl From for ConsensusError { + fn from(err: InsufficientShieldedFeeError) -> Self { + Self::StateError(StateError::InsufficientShieldedFeeError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/state/shielded/mod.rs b/packages/rs-dpp/src/errors/consensus/state/shielded/mod.rs index 5382da893ad..816eb366ac1 100644 --- a/packages/rs-dpp/src/errors/consensus/state/shielded/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/state/shielded/mod.rs @@ -1,9 +1,11 @@ pub mod insufficient_pool_notes_error; +pub mod insufficient_shielded_fee_error; pub mod invalid_anchor_error; pub mod invalid_shielded_proof_error; pub mod nullifier_already_spent_error; pub use insufficient_pool_notes_error::*; +pub use insufficient_shielded_fee_error::*; pub use invalid_anchor_error::*; pub use invalid_shielded_proof_error::*; pub use nullifier_already_spent_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/state/state_error.rs b/packages/rs-dpp/src/errors/consensus/state/state_error.rs index 89a5aa803f2..672c709198a 100644 --- a/packages/rs-dpp/src/errors/consensus/state/state_error.rs +++ b/packages/rs-dpp/src/errors/consensus/state/state_error.rs @@ -5,6 +5,7 @@ use thiserror::Error; use crate::consensus::state::address_funds::{AddressDoesNotExistError, AddressInvalidNonceError, AddressNotEnoughFundsError, AddressesNotEnoughFundsError}; use crate::consensus::state::shielded::insufficient_pool_notes_error::InsufficientPoolNotesError; +use crate::consensus::state::shielded::insufficient_shielded_fee_error::InsufficientShieldedFeeError; use crate::consensus::state::shielded::invalid_anchor_error::InvalidAnchorError; use crate::consensus::state::shielded::invalid_shielded_proof_error::InvalidShieldedProofError; use crate::consensus::state::shielded::nullifier_already_spent_error::NullifierAlreadySpentError; @@ -350,6 +351,9 @@ pub enum StateError { #[error(transparent)] InsufficientPoolNotesError(InsufficientPoolNotesError), + + #[error(transparent)] + InsufficientShieldedFeeError(InsufficientShieldedFeeError), } impl From for ConsensusError { diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index 8c1fdeb72c0..2793bd06305 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -82,7 +82,7 @@ derive_more = { version = "1.0", features = ["from", "deref", "deref_mut"] } async-trait = "0.1.77" console-subscriber = { version = "0.4", optional = true } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f", optional = true } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18" } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de" } sha2 = "0.10" nonempty = "0.11" @@ -105,7 +105,7 @@ dpp = { path = "../rs-dpp", default-features = false, features = [ drive = { path = "../rs-drive", features = ["fixtures-and-mocks"] } drive-proof-verifier = { path = "../rs-drive-proof-verifier" } strategy-tests = { path = "../strategy-tests" } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18", features = ["client"] } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de", features = ["client"] } assert_matches = "1.5.0" drive-abci = { path = ".", features = ["testing-config", "mocks"] } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f" } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/shielded_proof.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/shielded_proof.rs index 006b9457b13..4076852ace2 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/shielded_proof.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/shielded_proof.rs @@ -1,6 +1,7 @@ use crate::error::execution::ExecutionError; use crate::error::Error; use crate::execution::validation::state_transition::state_transitions::shielded_common::reconstruct_and_verify_bundle; +use dpp::consensus::state::shielded::insufficient_shielded_fee_error::InsufficientShieldedFeeError; use dpp::consensus::state::state_error::StateError; use dpp::state_transition::StateTransition; use dpp::validation::SimpleConsensusValidationResult; @@ -37,6 +38,97 @@ impl StateTransitionHasShieldedProofValidationV0 for StateTransition { } } +/// A trait for validating that a shielded state transition includes sufficient fees. +/// +/// The fee is derived from the public `value_balance` field (no ZK proof execution needed): +/// - ShieldedTransfer: fee = value_balance +/// - Unshield: fee = value_balance - amount +/// - ShieldedWithdrawal: fee = value_balance - amount +/// - Shield: fee paid by transparent address inputs (skipped here) +pub(crate) trait StateTransitionShieldedMinimumFeeValidationV0 { + fn validate_minimum_shielded_fee( + &self, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl StateTransitionShieldedMinimumFeeValidationV0 for StateTransition { + fn validate_minimum_shielded_fee( + &self, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .validation_and_processing + .validate_minimum_shielded_fee + { + 0 => { + let fee: i64 = match self { + // Shield: fee is paid from transparent address inputs, not from value_balance. + StateTransition::Shield(_) => { + return Ok(SimpleConsensusValidationResult::new()) + } + // ShieldedTransfer: value_balance (u64) IS the fee. + StateTransition::ShieldedTransfer(st) => match st { + dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition::V0(v0) => { + v0.value_balance as i64 + } + }, + // Unshield: fee = value_balance - amount. + StateTransition::Unshield(st) => match st { + dpp::state_transition::unshield_transition::UnshieldTransition::V0( + v0, + ) => { + if v0.value_balance <= 0 || (v0.value_balance as u64) <= v0.amount { + 0 + } else { + (v0.value_balance as u64 - v0.amount) as i64 + } + } + }, + // ShieldedWithdrawal: fee = value_balance - amount. + StateTransition::ShieldedWithdrawal(st) => match st { + dpp::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition::V0(v0) => { + if v0.value_balance <= 0 || (v0.value_balance as u64) <= v0.amount { + 0 + } else { + (v0.value_balance as u64 - v0.amount) as i64 + } + } + }, + // Other transitions don't go through shielded proof validation. + _ => return Ok(SimpleConsensusValidationResult::new()), + }; + + let minimum_shielded_fee = platform_version + .drive_abci + .validation_and_processing + .event_constants + .minimum_shielded_fee as i64; + + if fee < minimum_shielded_fee { + Ok(SimpleConsensusValidationResult::new_with_error( + StateError::InsufficientShieldedFeeError( + InsufficientShieldedFeeError::new(format!( + "shielded transition fee {} is below minimum required fee {}", + fee, minimum_shielded_fee + )), + ) + .into(), + )) + } else { + Ok(SimpleConsensusValidationResult::new()) + } + } + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "StateTransition::validate_minimum_shielded_fee".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} + impl StateTransitionShieldedProofValidationV0 for StateTransition { fn validate_shielded_proof( &self, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs index f6e63d312df..109bacbc78a 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/v0/mod.rs @@ -18,7 +18,8 @@ use crate::execution::validation::state_transition::processor::is_allowed::State use crate::execution::validation::state_transition::processor::prefunded_specialized_balance::StateTransitionPrefundedSpecializedBalanceValidationV0; use crate::execution::validation::state_transition::processor::state::StateTransitionStateValidation; use crate::execution::validation::state_transition::processor::traits::shielded_proof::{ - StateTransitionHasShieldedProofValidationV0, StateTransitionShieldedProofValidationV0, + StateTransitionHasShieldedProofValidationV0, StateTransitionShieldedMinimumFeeValidationV0, + StateTransitionShieldedProofValidationV0, }; use crate::execution::validation::state_transition::transformer::StateTransitionActionTransformer; use crate::execution::validation::state_transition::ValidationMode; @@ -162,15 +163,6 @@ pub(super) fn process_state_transition_v0<'a, C: CoreRPCLike>( } } - // Verify ZK proof for shielded transitions (stateless, like signature verification). - // This happens before any state reads to reject invalid proofs cheaply. - if state_transition.has_shielded_proof_validation() { - let result = state_transition.validate_shielded_proof(platform_version)?; - if !result.is_valid() { - return Ok(ConsensusValidationResult::::new_with_errors(result.errors)); - } - } - // For identity credit withdrawal and identity credit transfers we have a balance pre-check that includes a // processing amount and the transfer amount. // For other state transitions we only check a min balance for an amount set per version. @@ -227,6 +219,23 @@ pub(super) fn process_state_transition_v0<'a, C: CoreRPCLike>( None }; + // Validate minimum fee for shielded transitions (stateless, uses public value_balance). + // This is cheaper than proof verification so we check it first. + if state_transition.has_shielded_proof_validation() { + let result = state_transition.validate_minimum_shielded_fee(platform_version)?; + if !result.is_valid() { + return Ok(ConsensusValidationResult::::new_with_errors(result.errors)); + } + } + + // Verify ZK proof for shielded transitions (stateless, like signature verification). + if state_transition.has_shielded_proof_validation() { + let result = state_transition.validate_shielded_proof(platform_version)?; + if !result.is_valid() { + return Ok(ConsensusValidationResult::::new_with_errors(result.errors)); + } + } + // Only identity update and data contract create have advanced structure validation without state if state_transition.has_advanced_structure_validation_without_state() { // Currently only used for Identity Update, Data Contract Create and Identity Create From Addresses diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index 30176528eb7..776231f4e7c 100644 --- a/packages/rs-drive/Cargo.toml +++ b/packages/rs-drive/Cargo.toml @@ -52,12 +52,12 @@ enum-map = { version = "2.0.3", optional = true } intmap = { version = "3.0.1", features = ["serde"], optional = true } chrono = { version = "0.4.35", optional = true } itertools = { version = "0.13", optional = true } -grovedb = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18", optional = true, default-features = false } -grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18", optional = true } -grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18" } -grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18", optional = true } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18" } -grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18" } +grovedb = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de", optional = true, default-features = false } +grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de", optional = true } +grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de" } +grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de", optional = true } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de" } +grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de" } [dev-dependencies] criterion = "0.5" diff --git a/packages/rs-drive/src/drive/initialization/v3/mod.rs b/packages/rs-drive/src/drive/initialization/v3/mod.rs index 6675b95589a..68773d95eab 100644 --- a/packages/rs-drive/src/drive/initialization/v3/mod.rs +++ b/packages/rs-drive/src/drive/initialization/v3/mod.rs @@ -85,7 +85,7 @@ impl Drive { batch.add_insert( shielded_credit_pool_path_vec(), vec![SHIELDED_NOTES_KEY], - Element::empty_commitment_tree(11), + Element::empty_commitment_tree(SHIELDED_NOTES_CHUNK_POWER), ); // 3. Nullifiers tree (ProvableCountTree) diff --git a/packages/rs-drive/src/drive/shielded/estimated_costs.rs b/packages/rs-drive/src/drive/shielded/estimated_costs.rs index 435767de497..398252899aa 100644 --- a/packages/rs-drive/src/drive/shielded/estimated_costs.rs +++ b/packages/rs-drive/src/drive/shielded/estimated_costs.rs @@ -1,6 +1,6 @@ use crate::drive::shielded::paths::{ shielded_credit_pool_anchors_path, shielded_credit_pool_notes_path, - shielded_credit_pool_nullifiers_path, shielded_credit_pool_path, + shielded_credit_pool_nullifiers_path, shielded_credit_pool_path, SHIELDED_NOTES_CHUNK_POWER, }; use crate::drive::{Drive, RootTree}; use grovedb::batch::KeyInfoPath; @@ -10,8 +10,10 @@ use grovedb::EstimatedSumTrees::SomeSumTrees; use grovedb::{EstimatedLayerInformation, TreeType}; use std::collections::HashMap; -/// Average size of a note value: 32 cmx + 692 encrypted note = 724 bytes -const AVERAGE_NOTE_VALUE_SIZE: u32 = 724; +/// Average size of a note value: 32 cmx + 32 nullifier + 216 encrypted note = 280 bytes +/// (encrypted note = 32 epk + 104 enc_ciphertext + 80 out_ciphertext, using DashMemo 36-byte memos) +/// The cmx is prepended by GroveDB's commitment_tree_insert_op for client retrieval. +const AVERAGE_NOTE_VALUE_SIZE: u32 = 280; /// Size of a nullifier key (32 bytes) const NULLIFIER_KEY_SIZE: u8 = 32; @@ -104,8 +106,8 @@ impl Drive { estimated_costs_only_with_layer_info.insert( KeyInfoPath::from_known_path(shielded_credit_pool_notes_path()), EstimatedLayerInformation { - tree_type: TreeType::CommitmentTree, - estimated_layer_count: EstimatedLevel(10, false), + tree_type: TreeType::CommitmentTree(SHIELDED_NOTES_CHUNK_POWER), + estimated_layer_count: EstimatedLevel(16, false), estimated_layer_sizes: AllItems(8, AVERAGE_NOTE_VALUE_SIZE, None), }, ); @@ -116,7 +118,7 @@ impl Drive { KeyInfoPath::from_known_path(shielded_credit_pool_nullifiers_path()), EstimatedLayerInformation { tree_type: TreeType::NormalTree, - estimated_layer_count: EstimatedLevel(10, false), + estimated_layer_count: EstimatedLevel(16, false), estimated_layer_sizes: AllItems(NULLIFIER_KEY_SIZE, 0, None), }, ); diff --git a/packages/rs-drive/src/drive/shielded/paths.rs b/packages/rs-drive/src/drive/shielded/paths.rs index 5d4be51c73d..8698b2dd3b1 100644 --- a/packages/rs-drive/src/drive/shielded/paths.rs +++ b/packages/rs-drive/src/drive/shielded/paths.rs @@ -18,6 +18,9 @@ pub const SHIELDED_TOTAL_BALANCE_KEY: u8 = 5; /// Key for the anchors tree inside a shielded pool pub const SHIELDED_ANCHORS_IN_POOL_KEY: u8 = 6; +/// Chunk power for the notes CommitmentTree (2^11 = 2048 items per chunk) +pub const SHIELDED_NOTES_CHUNK_POWER: u8 = 11; + /// Path to the shielded credit pool: [AddressBalances, "s"] pub fn shielded_credit_pool_path() -> [&'static [u8]; 2] { [ diff --git a/packages/rs-drive/src/fees/op.rs b/packages/rs-drive/src/fees/op.rs index 22f03821bf4..f1cb042f63b 100644 --- a/packages/rs-drive/src/fees/op.rs +++ b/packages/rs-drive/src/fees/op.rs @@ -579,15 +579,15 @@ impl LowLevelDriveOperationTreeTypeConverter for TreeType { TreeType::ProvableCountSumTree => { Element::empty_provable_count_sum_tree_with_flags(element_flags) } - TreeType::CommitmentTree => { - Element::empty_commitment_tree_with_flags(11, element_flags) + TreeType::CommitmentTree(chunk_power) => { + Element::empty_commitment_tree_with_flags(*chunk_power, element_flags) } TreeType::MmrTree => Element::empty_mmr_tree_with_flags(element_flags), - TreeType::BulkAppendTree => { - Element::empty_bulk_append_tree_with_flags(4, element_flags) + TreeType::BulkAppendTree(chunk_power) => { + Element::empty_bulk_append_tree_with_flags(*chunk_power, element_flags) } - TreeType::DenseAppendOnlyFixedSizeTree => { - Element::empty_dense_tree_with_flags(8, element_flags) + TreeType::DenseAppendOnlyFixedSizeTree(chunk_power) => { + Element::empty_dense_tree_with_flags(*chunk_power, element_flags) } }; diff --git a/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs b/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs index db95af541c8..2494d17c56c 100644 --- a/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs +++ b/packages/rs-drive/src/util/grove_operations/grove_insert_empty_tree/v0/mod.rs @@ -28,10 +28,12 @@ impl Drive { TreeType::CountSumTree => Element::empty_count_sum_tree(), TreeType::ProvableCountTree => Element::empty_provable_count_tree(), TreeType::ProvableCountSumTree => Element::empty_provable_count_sum_tree(), - TreeType::CommitmentTree => Element::empty_commitment_tree(11), + TreeType::CommitmentTree(chunk_power) => Element::empty_commitment_tree(chunk_power), TreeType::MmrTree => Element::empty_mmr_tree(), - TreeType::BulkAppendTree => Element::empty_bulk_append_tree(4), - TreeType::DenseAppendOnlyFixedSizeTree => Element::empty_dense_tree(8), + TreeType::BulkAppendTree(chunk_power) => Element::empty_bulk_append_tree(chunk_power), + TreeType::DenseAppendOnlyFixedSizeTree(chunk_power) => { + Element::empty_dense_tree(chunk_power) + } }; let cost_context = self.grove.insert( path, diff --git a/packages/rs-platform-version/Cargo.toml b/packages/rs-platform-version/Cargo.toml index c8dac616980..64123f578f7 100644 --- a/packages/rs-platform-version/Cargo.toml +++ b/packages/rs-platform-version/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT" thiserror = { version = "2.0.12" } bincode = { version = "=2.0.1" } versioned-feature-core = { git = "https://github.com/dashpay/versioned-feature-core", version = "1.0.0" } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18" } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de" } [features] mock-versions = [] 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 78bab3abb0f..893aa6c69ae 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 @@ -16,6 +16,7 @@ pub struct DriveAbciValidationVersions { pub has_address_witness_validation: FeatureVersion, pub validate_address_witnesses: FeatureVersion, pub validate_shielded_proof: FeatureVersion, + pub validate_minimum_shielded_fee: FeatureVersion, pub process_state_transition: FeatureVersion, pub state_transition_to_execution_event_for_check_tx: FeatureVersion, pub penalties: PenaltyAmounts, @@ -30,6 +31,9 @@ pub struct DriveAbciValidationConstants { /// transitions (Unshield, ShieldedWithdrawal) are allowed. This ensures a /// sufficient anonymity set before funds can leave the pool. pub minimum_pool_notes_for_outgoing: u64, + /// Minimum fee (in credits) required for shielded transitions that pay fees + /// from the shielded pool (ShieldedTransfer, Unshield, ShieldedWithdrawal). + pub minimum_shielded_fee: u64, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs index 8d5058db63f..31b6daa8cb0 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs @@ -245,6 +245,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V1: DriveAbciValidationVersions = has_address_witness_validation: 0, validate_address_witnesses: 0, validate_shielded_proof: 0, + validate_minimum_shielded_fee: 0, process_state_transition: 0, state_transition_to_execution_event_for_check_tx: 0, penalties: PenaltyAmounts { @@ -259,5 +260,6 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V1: DriveAbciValidationVersions = maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, minimum_pool_notes_for_outgoing: 250, + minimum_shielded_fee: 1, }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs index 0b6a9bc1c2a..80266c555df 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs @@ -245,6 +245,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V2: DriveAbciValidationVersions = has_address_witness_validation: 0, validate_address_witnesses: 0, validate_shielded_proof: 0, + validate_minimum_shielded_fee: 0, process_state_transition: 0, state_transition_to_execution_event_for_check_tx: 0, penalties: PenaltyAmounts { @@ -259,5 +260,6 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V2: DriveAbciValidationVersions = maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, minimum_pool_notes_for_outgoing: 250, + minimum_shielded_fee: 1, }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs index 4c17a065eb9..daff58bb158 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs @@ -245,6 +245,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V3: DriveAbciValidationVersions = has_address_witness_validation: 0, validate_address_witnesses: 0, validate_shielded_proof: 0, + validate_minimum_shielded_fee: 0, process_state_transition: 0, state_transition_to_execution_event_for_check_tx: 0, penalties: PenaltyAmounts { @@ -259,5 +260,6 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V3: DriveAbciValidationVersions = maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, minimum_pool_notes_for_outgoing: 250, + minimum_shielded_fee: 1, }, }; 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 f1affbaf9cd..0e8d1a5a8a8 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 @@ -248,6 +248,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V4: DriveAbciValidationVersions = has_address_witness_validation: 0, validate_address_witnesses: 0, validate_shielded_proof: 0, + validate_minimum_shielded_fee: 0, process_state_transition: 0, state_transition_to_execution_event_for_check_tx: 0, penalties: PenaltyAmounts { @@ -262,5 +263,6 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V4: DriveAbciValidationVersions = maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, minimum_pool_notes_for_outgoing: 250, + minimum_shielded_fee: 1, }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs index 7afcbacfdc6..a6e12782842 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs @@ -249,6 +249,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V5: DriveAbciValidationVersions = has_address_witness_validation: 0, validate_address_witnesses: 0, validate_shielded_proof: 0, + validate_minimum_shielded_fee: 0, process_state_transition: 0, state_transition_to_execution_event_for_check_tx: 0, penalties: PenaltyAmounts { @@ -263,5 +264,6 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V5: DriveAbciValidationVersions = maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, minimum_pool_notes_for_outgoing: 250, + minimum_shielded_fee: 1, }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs index 474cf69b7ae..1cf61e5b2be 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs @@ -252,6 +252,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V6: DriveAbciValidationVersions = has_address_witness_validation: 0, validate_address_witnesses: 0, validate_shielded_proof: 0, + validate_minimum_shielded_fee: 0, process_state_transition: 0, state_transition_to_execution_event_for_check_tx: 0, penalties: PenaltyAmounts { @@ -266,5 +267,6 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V6: DriveAbciValidationVersions = maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, minimum_pool_notes_for_outgoing: 250, + minimum_shielded_fee: 1, }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs index 83a1ade1119..2d5bb45e4e6 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs @@ -246,6 +246,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V7: DriveAbciValidationVersions = has_address_witness_validation: 0, validate_address_witnesses: 0, validate_shielded_proof: 0, + validate_minimum_shielded_fee: 0, process_state_transition: 0, state_transition_to_execution_event_for_check_tx: 0, penalties: PenaltyAmounts { @@ -260,5 +261,6 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V7: DriveAbciValidationVersions = maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, minimum_pool_notes_for_outgoing: 250, + minimum_shielded_fee: 1, }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v8.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v8.rs index 74d32eb6ef9..6141bdf58c1 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v8.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v8.rs @@ -250,6 +250,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V8: DriveAbciValidationVersions = has_address_witness_validation: 0, validate_address_witnesses: 0, validate_shielded_proof: 0, + validate_minimum_shielded_fee: 0, process_state_transition: 0, state_transition_to_execution_event_for_check_tx: 0, penalties: PenaltyAmounts { @@ -264,5 +265,6 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V8: DriveAbciValidationVersions = maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, minimum_pool_notes_for_outgoing: 250, + minimum_shielded_fee: 1, }, }; diff --git a/packages/rs-sdk/Cargo.toml b/packages/rs-sdk/Cargo.toml index a51e7639bd5..00020ff4359 100644 --- a/packages/rs-sdk/Cargo.toml +++ b/packages/rs-sdk/Cargo.toml @@ -18,7 +18,7 @@ drive = { path = "../rs-drive", default-features = false, features = [ platform-wallet = { path = "../rs-platform-wallet", optional = true } drive-proof-verifier = { path = "../rs-drive-proof-verifier", default-features = false } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "56120fb5d0f8abfa9038e018115cdb11c51cde18", features = ["client", "sqlite"], optional = true } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de", features = ["client", "sqlite"], optional = true } dash-context-provider = { path = "../rs-context-provider", default-features = false } dash-platform-macros = { path = "../rs-dash-platform-macros" } http = { version = "1.1" } From 7313bc0a466343c9299b38de72c33d8a36a1039f Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 25 Feb 2026 08:36:47 +0700 Subject: [PATCH 32/40] more work --- .../engine/run_block_proposal/v0/mod.rs | 8 - .../execute_event/v0/mod.rs | 25 ++ .../state_transition_processing/mod.rs | 1 - .../process_raw_state_transitions/v0/mod.rs | 5 - .../mod.rs | 43 -- .../v0/mod.rs | 30 -- .../validate_fees_of_event/v0/mod.rs | 1 + .../execution/types/execution_event/mod.rs | 36 +- .../processor/traits/shielded_proof.rs | 54 ++- .../shielded_transfer/tests.rs | 371 +++++++++++++++++- .../mod.rs | 14 - .../shielded/mod.rs | 14 + .../shielded/shielded_transfer_transition.rs | 5 +- .../shielded_withdrawal_transition.rs | 5 +- .../shielded/unshield_transition.rs | 5 +- .../src/util/batch/drive_op_batch/shielded.rs | 29 +- .../drive_abci_validation_versions/mod.rs | 9 +- .../drive_abci_validation_versions/v1.rs | 3 +- .../drive_abci_validation_versions/v2.rs | 3 +- .../drive_abci_validation_versions/v3.rs | 3 +- .../drive_abci_validation_versions/v4.rs | 3 +- .../drive_abci_validation_versions/v5.rs | 3 +- .../drive_abci_validation_versions/v6.rs | 3 +- .../drive_abci_validation_versions/v7.rs | 3 +- .../drive_abci_validation_versions/v8.rs | 3 +- .../src/version/mocks/v2_test.rs | 7 + 26 files changed, 513 insertions(+), 173 deletions(-) delete mode 100644 packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/store_nullifiers_to_recent_block_storage/mod.rs delete mode 100644 packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/store_nullifiers_to_recent_block_storage/v0/mod.rs 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 eebc3691498..3f35d0cf881 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 @@ -344,14 +344,6 @@ where platform_version, )?; - // Store nullifiers inserted during this block to recent block storage - self.store_nullifiers_to_recent_block_storage( - &state_transitions_result.nullifiers_inserted, - &block_info, - transaction, - platform_version, - )?; - // Clean up expired compacted nullifier entries self.cleanup_recent_block_storage_nullifiers(&block_info, transaction, platform_version)?; diff --git a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs index 404ceee029c..02bb9150152 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/execute_event/v0/mod.rs @@ -344,6 +344,7 @@ where )?), ExecutionEvent::PaidFromAssetLockWithoutIdentity { .. } | ExecutionEvent::PaidFixedCost { .. } + | ExecutionEvent::PaidFromShieldedPool { .. } | ExecutionEvent::Free { .. } => None, }; @@ -488,6 +489,30 @@ where ExecutionEvent::PaidFixedCost { operations, fees_to_add_to_pool, + } => { + if consensus_errors.is_empty() { + self.drive + .apply_drive_operations( + operations, + true, + block_info, + Some(transaction), + platform_version, + Some(previous_fee_versions), + ) + .map_err(Error::Drive)?; + + Ok(SuccessfulPaidExecution( + None, + FeeResult::default_with_fees(0, fees_to_add_to_pool), + )) + } else { + Ok(UnpaidConsensusExecutionError(consensus_errors)) + } + } + ExecutionEvent::PaidFromShieldedPool { + operations, + fees_to_add_to_pool, .. } => { if consensus_errors.is_empty() { diff --git a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/mod.rs index 52c39e1102f..26ea2e160dc 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/mod.rs @@ -4,5 +4,4 @@ mod decode_raw_state_transitions; mod execute_event; mod process_raw_state_transitions; mod store_address_balances_to_recent_block_storage; -mod store_nullifiers_to_recent_block_storage; mod validate_fees_of_event; diff --git a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs index c8c28f74f14..fa1b3012917 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs @@ -368,9 +368,6 @@ where } })?; - // Extract nullifiers before the execution event is consumed - let nullifiers = execution_event.nullifiers().to_vec(); - let mut address_balances = BTreeMap::new(); let event_execution_result = self .execute_event( @@ -407,7 +404,6 @@ where estimated_fees, fee_result: actual_fees, address_balance_changes: address_balances, - nullifiers_inserted: nullifiers, } } EventExecutionResult::UnsuccessfulPaidExecution( @@ -454,7 +450,6 @@ where estimated_fees: None, fee_result: FeeResult::default(), address_balance_changes: BTreeMap::new(), - nullifiers_inserted: nullifiers, } } EventExecutionResult::UnpaidConsensusExecutionError(mut errors) => { diff --git a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/store_nullifiers_to_recent_block_storage/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/store_nullifiers_to_recent_block_storage/mod.rs deleted file mode 100644 index cb964419d5a..00000000000 --- a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/store_nullifiers_to_recent_block_storage/mod.rs +++ /dev/null @@ -1,43 +0,0 @@ -mod v0; - -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::version::PlatformVersion; -use drive::grovedb::Transaction; - -impl Platform -where - C: CoreRPCLike, -{ - /// Stores nullifiers inserted during this block to recent block storage for sync purposes. - pub(in crate::execution) fn store_nullifiers_to_recent_block_storage( - &self, - nullifiers: &[[u8; 32]], - block_info: &BlockInfo, - transaction: &Transaction, - platform_version: &PlatformVersion, - ) -> Result<(), Error> { - match platform_version - .drive_abci - .methods - .state_transition_processing - .store_nullifiers_to_recent_block_storage - { - None => Ok(()), - Some(0) => self.store_nullifiers_to_recent_block_storage_v0( - nullifiers, - block_info, - transaction, - platform_version, - ), - Some(version) => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { - method: "store_nullifiers_to_recent_block_storage".to_string(), - known_versions: vec![0], - received: version, - })), - } - } -} diff --git a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/store_nullifiers_to_recent_block_storage/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/store_nullifiers_to_recent_block_storage/v0/mod.rs deleted file mode 100644 index 779393ee242..00000000000 --- a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/store_nullifiers_to_recent_block_storage/v0/mod.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::error::Error; -use crate::platform_types::platform::Platform; -use crate::rpc::core::CoreRPCLike; -use dpp::block::block_info::BlockInfo; -use dpp::version::PlatformVersion; -use drive::grovedb::Transaction; - -impl Platform -where - C: CoreRPCLike, -{ - /// Version 0 implementation of storing nullifiers to recent block storage. - pub(super) fn store_nullifiers_to_recent_block_storage_v0( - &self, - nullifiers: &[[u8; 32]], - block_info: &BlockInfo, - transaction: &Transaction, - platform_version: &PlatformVersion, - ) -> Result<(), Error> { - self.drive.store_nullifiers_for_block( - nullifiers, - block_info.height, - block_info.time_ms, - Some(transaction), - platform_version, - )?; - - Ok(()) - } -} diff --git a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/validate_fees_of_event/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/validate_fees_of_event/v0/mod.rs index 5e1ac125c69..f1944dfd600 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/validate_fees_of_event/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/validate_fees_of_event/v0/mod.rs @@ -268,6 +268,7 @@ where } } ExecutionEvent::PaidFixedCost { .. } + | ExecutionEvent::PaidFromShieldedPool { .. } | ExecutionEvent::Free { .. } | ExecutionEvent::PaidFromAssetLockWithoutIdentity { .. } => Ok( ConsensusValidationResult::new_with_data(FeeResult::default()), diff --git a/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs b/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs index a923ed9dad5..b26e41185de 100644 --- a/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs +++ b/packages/rs-drive-abci/src/execution/types/execution_event/mod.rs @@ -67,8 +67,16 @@ pub(in crate::execution) enum ExecutionEvent<'a> { operations: Vec>, /// fees to add fees_to_add_to_pool: Credits, - /// Nullifiers inserted by this action (for shielded spends) - nullifiers: Vec<[u8; 32]>, + }, + /// A drive event paid from the shielded pool's value_balance. + /// The fee is embedded in the ZK-proven value_balance and validated + /// at the processor level (validate_minimum_shielded_fee). + /// Nullifiers are stored to recent block storage as part of the drive operations. + PaidFromShieldedPool { + /// the operations that should be performed + operations: Vec>, + /// fees derived from value_balance to add to the fee pool + fees_to_add_to_pool: Credits, }, /// A drive event that is paid from an asset lock PaidFromAssetLock { @@ -110,16 +118,6 @@ pub(in crate::execution) enum ExecutionEvent<'a> { } impl ExecutionEvent<'_> { - /// Extract nullifiers from this execution event, if any. - /// Shielded spend actions (ShieldedTransfer, Unshield, ShieldedWithdrawal) - /// carry nullifiers that were consumed. - pub(crate) fn nullifiers(&self) -> &[[u8; 32]] { - match self { - ExecutionEvent::PaidFixedCost { nullifiers, .. } => nullifiers.as_slice(), - _ => &[], - } - } - pub(crate) fn create_from_state_transition_action( action: StateTransitionAction, identity: Option, @@ -245,7 +243,6 @@ impl ExecutionEvent<'_> { .fee_version .vote_resolution_fund_fees .contested_document_single_vote_cost, - nullifiers: vec![], }) } StateTransitionAction::DataContractCreateAction(data_contract_create_action) => { @@ -486,24 +483,20 @@ impl ExecutionEvent<'_> { } StateTransitionAction::ShieldedTransferAction(ref shielded_transfer_action) => { let fee_amount = shielded_transfer_action.fee_amount(); - let nullifiers = shielded_transfer_action.nullifiers().to_vec(); let operations = action.into_high_level_drive_operations(epoch, platform_version)?; - Ok(ExecutionEvent::PaidFixedCost { + Ok(ExecutionEvent::PaidFromShieldedPool { operations, fees_to_add_to_pool: fee_amount, - nullifiers, }) } StateTransitionAction::UnshieldAction(ref unshield_action) => { let fee_amount = unshield_action.fee_amount(); - let nullifiers = unshield_action.nullifiers().to_vec(); let operations = action.into_high_level_drive_operations(epoch, platform_version)?; - Ok(ExecutionEvent::PaidFixedCost { + Ok(ExecutionEvent::PaidFromShieldedPool { operations, fees_to_add_to_pool: fee_amount, - nullifiers, }) } StateTransitionAction::ShieldFromAssetLockAction(ref shield_from_asset_lock_action) => { @@ -523,13 +516,11 @@ impl ExecutionEvent<'_> { } StateTransitionAction::ShieldedWithdrawalAction(ref shielded_withdrawal_action) => { let fee_amount = shielded_withdrawal_action.fee_amount(); - let nullifiers = shielded_withdrawal_action.nullifiers().to_vec(); let operations = action.into_high_level_drive_operations(epoch, platform_version)?; - Ok(ExecutionEvent::PaidFixedCost { + Ok(ExecutionEvent::PaidFromShieldedPool { operations, fees_to_add_to_pool: fee_amount, - nullifiers, }) } StateTransitionAction::PenalizeShieldedPoolAction(ref penalize_action) => { @@ -539,7 +530,6 @@ impl ExecutionEvent<'_> { Ok(ExecutionEvent::PaidFixedCost { operations, fees_to_add_to_pool: penalty_amount, - nullifiers: vec![], }) } _ => { diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/shielded_proof.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/shielded_proof.rs index 4076852ace2..6a302477a0b 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/shielded_proof.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/shielded_proof.rs @@ -7,6 +7,11 @@ use dpp::state_transition::StateTransition; use dpp::validation::SimpleConsensusValidationResult; use dpp::version::PlatformVersion; +/// Permanent storage bytes per shielded action: +/// 280 bytes in BulkAppendTree (32 cmx + 32 nullifier + 216 encrypted note) +/// + 32 bytes in nullifier tree = 312 bytes total. +const SHIELDED_STORAGE_BYTES_PER_ACTION: u64 = 312; + /// A trait for checking whether a state transition requires shielded ZK proof validation. pub(crate) trait StateTransitionHasShieldedProofValidationV0 { /// Returns true if this state transition has a ZK proof that must be verified @@ -40,6 +45,9 @@ impl StateTransitionHasShieldedProofValidationV0 for StateTransition { /// A trait for validating that a shielded state transition includes sufficient fees. /// +/// The minimum fee is computed dynamically based on the number of actions: +/// min_fee = proof_verification_fee + num_actions × (processing_fee + storage_fee) +/// /// The fee is derived from the public `value_balance` field (no ZK proof execution needed): /// - ShieldedTransfer: fee = value_balance /// - Unshield: fee = value_balance - amount @@ -63,7 +71,8 @@ impl StateTransitionShieldedMinimumFeeValidationV0 for StateTransition { .validate_minimum_shielded_fee { 0 => { - let fee: i64 = match self { + // Extract the fee and action count from the transition. + let (fee, num_actions): (i64, usize) = match self { // Shield: fee is paid from transparent address inputs, not from value_balance. StateTransition::Shield(_) => { return Ok(SimpleConsensusValidationResult::new()) @@ -71,7 +80,7 @@ impl StateTransitionShieldedMinimumFeeValidationV0 for StateTransition { // ShieldedTransfer: value_balance (u64) IS the fee. StateTransition::ShieldedTransfer(st) => match st { dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition::V0(v0) => { - v0.value_balance as i64 + (v0.value_balance as i64, v0.actions.len()) } }, // Unshield: fee = value_balance - amount. @@ -79,39 +88,58 @@ impl StateTransitionShieldedMinimumFeeValidationV0 for StateTransition { dpp::state_transition::unshield_transition::UnshieldTransition::V0( v0, ) => { - if v0.value_balance <= 0 || (v0.value_balance as u64) <= v0.amount { + let fee = if v0.value_balance <= 0 || (v0.value_balance as u64) <= v0.amount { 0 } else { (v0.value_balance as u64 - v0.amount) as i64 - } + }; + (fee, v0.actions.len()) } }, // ShieldedWithdrawal: fee = value_balance - amount. StateTransition::ShieldedWithdrawal(st) => match st { dpp::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition::V0(v0) => { - if v0.value_balance <= 0 || (v0.value_balance as u64) <= v0.amount { + let fee = if v0.value_balance <= 0 || (v0.value_balance as u64) <= v0.amount { 0 } else { (v0.value_balance as u64 - v0.amount) as i64 - } + }; + (fee, v0.actions.len()) } }, - // Other transitions don't go through shielded proof validation. + // Other transitions don't go through shielded fee validation. _ => return Ok(SimpleConsensusValidationResult::new()), }; - let minimum_shielded_fee = platform_version + let constants = &platform_version .drive_abci .validation_and_processing - .event_constants - .minimum_shielded_fee as i64; + .event_constants; + + // Storage fee per action: 312 bytes (280 BulkAppendTree + 32 nullifier) + // × (storage_disk_usage_credit_per_byte + storage_processing_credit_per_byte) + let storage_costs = &platform_version.fee_version.storage; + let storage_fee_per_action = SHIELDED_STORAGE_BYTES_PER_ACTION + * (storage_costs.storage_disk_usage_credit_per_byte + + storage_costs.storage_processing_credit_per_byte); + + // min_fee = proof_verification_fee + num_actions × (processing_fee + storage_fee) + let per_action_fee = + constants.shielded_per_action_processing_fee + storage_fee_per_action; + let minimum_shielded_fee = + constants.shielded_proof_verification_fee + num_actions as u64 * per_action_fee; - if fee < minimum_shielded_fee { + if (fee as u64) < minimum_shielded_fee { Ok(SimpleConsensusValidationResult::new_with_error( StateError::InsufficientShieldedFeeError( InsufficientShieldedFeeError::new(format!( - "shielded transition fee {} is below minimum required fee {}", - fee, minimum_shielded_fee + "shielded transition fee {} is below minimum required fee {} \ + ({} proof + {} actions × {} per-action)", + fee, + minimum_shielded_fee, + constants.shielded_proof_verification_fee, + num_actions, + per_action_fee, )), ) .into(), diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs index 017f706507b..340d2463226 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs @@ -44,11 +44,12 @@ mod tests { /// Shorthand for creating a structurally valid (but cryptographically invalid) shielded /// transfer transition. Has a non-zero anchor, valid field sizes, but random data. + /// Includes sufficient fee to pass the minimum shielded fee check (1 action = 111,548,800). fn create_default_shielded_transfer_transition() -> StateTransition { create_shielded_transfer_transition( vec![create_dummy_serialized_action()], 0x03, // spends_enabled | outputs_enabled - 0, // zero fee + 111_548_800, // minimum fee for 1 action [42u8; 32], // non-zero anchor vec![0u8; 100], // dummy proof bytes [0u8; 64], // dummy binding signature @@ -298,6 +299,9 @@ mod tests { ); } + /// Minimum fee for 2 actions (Orchard builder always produces ≥2). + const MINIMUM_FEE_2_ACTIONS: u64 = 123_097_600; + #[test] fn test_valid_shielded_transfer_proof_succeeds() { let platform_version = PlatformVersion::latest(); @@ -305,6 +309,9 @@ mod tests { let mut rng = OsRng; let pk = get_proving_key(); + let spend_amount = 200_000_000u64; + let output_amount = spend_amount - MINIMUM_FEE_2_ACTIONS; + // --- Create keys --- let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); let fvk = FullViewingKey::from(&sk); @@ -320,7 +327,7 @@ mod tests { let rho = Rho::from_bytes(&rho_bytes).unwrap(); let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); let note = - Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); + Note::from_parts(recipient, NoteValue::from_raw(spend_amount), rho, rseed).unwrap(); // --- Build commitment tree and get anchor + merkle path --- let cmx = ExtractedNoteCommitment::from(note.commitment()); @@ -330,11 +337,16 @@ mod tests { let anchor = tree.anchor().unwrap(); let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); - // --- Build bundle: spend 10_000 → output 10_000 (value_balance = 0) --- + // --- Build bundle: spend 200M → output (200M - fee), value_balance = fee --- let mut builder = Builder::::new(BundleType::DEFAULT, anchor); builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); builder - .add_output(None, recipient, NoteValue::from_raw(10_000), [0u8; 36]) + .add_output( + None, + recipient, + NoteValue::from_raw(output_amount), + [0u8; 36], + ) .unwrap(); let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); @@ -347,10 +359,10 @@ mod tests { let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = serialize_authorized_bundle(&bundle); - // value_balance should be 0 (equal spend and output) - assert_eq!(value_balance, 0); + assert_eq!(value_balance, MINIMUM_FEE_2_ACTIONS); - // --- Insert anchor into platform state --- + // --- Set pool balance and insert anchor --- + set_pool_total_balance(&platform, 500_000_000); insert_anchor_into_state(&platform, &anchor_bytes); // --- Create and process transition --- @@ -388,7 +400,7 @@ mod tests { let transition = create_shielded_transfer_transition( vec![bad_action], 0x03, - 0, + 111_548_800, // minimum fee for 1 action (fee check runs before proof reconstruction) anchor, vec![0u8; 100], [0u8; 64], @@ -405,6 +417,318 @@ mod tests { } } + // ========================================== + // FEE VALIDATION TESTS (InsufficientShieldedFeeError) + // ========================================== + // + // The minimum shielded fee is: + // min_fee = proof_verification_fee + num_actions × (processing_fee + storage_fee) + // + // With current constants: + // proof_verification_fee = 100_000_000 + // per_action_processing_fee = 3_000_000 + // per_action_storage_fee = 312 × (27_000 + 400) = 8_548_800 + // per_action_total = 11_548_800 + // + // Minimum fees by action count: + // 2 actions: 100_000_000 + 2 × 11_548_800 = 123_097_600 + // 3 actions: 100_000_000 + 3 × 11_548_800 = 134_646_400 + // 4 actions: 100_000_000 + 4 × 11_548_800 = 146_195_200 + + mod fee_validation { + use super::*; + use grovedb_commitment_tree::{ + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + ClientMemoryCommitmentTree, DashMemo, ExtractedNoteCommitment, FullViewingKey, + MerklePath, Note, NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, + SpendAuthorizingKey, SpendingKey, + }; + use rand::rngs::OsRng; + use std::sync::OnceLock; + + const MINIMUM_FEE_2_ACTIONS: u64 = 123_097_600; + const MINIMUM_FEE_3_ACTIONS: u64 = 134_646_400; + const MINIMUM_FEE_4_ACTIONS: u64 = 146_195_200; + + static TEST_PROVING_KEY: OnceLock = OnceLock::new(); + fn get_proving_key() -> &'static ProvingKey { + TEST_PROVING_KEY.get_or_init(ProvingKey::build) + } + + fn serialize_authorized_bundle( + bundle: &Bundle, + ) -> (Vec, u8, u64, [u8; 32], Vec, [u8; 64]) { + let actions: Vec = bundle + .actions() + .iter() + .map(|action| { + let enc = action.encrypted_note(); + let mut encrypted_note = Vec::with_capacity(216); + encrypted_note.extend_from_slice(&enc.epk_bytes); + encrypted_note.extend_from_slice(enc.enc_ciphertext.as_ref()); + encrypted_note.extend_from_slice(&enc.out_ciphertext); + SerializedAction { + nullifier: action.nullifier().to_bytes(), + rk: <[u8; 32]>::from(action.rk()), + cmx: action.cmx().to_bytes(), + encrypted_note, + cv_net: action.cv_net().to_bytes(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()), + } + }) + .collect(); + let flags = bundle.flags().to_byte(); + let value_balance = *bundle.value_balance() as u64; + let anchor = bundle.anchor().to_bytes(); + let proof = bundle.authorization().proof().as_ref().to_vec(); + let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); + (actions, flags, value_balance, anchor, proof, binding_sig) + } + + /// Helper to create a dummy action with a unique seed (avoids duplicate nullifiers). + fn create_dummy_action(seed: u8) -> SerializedAction { + SerializedAction { + nullifier: [seed; 32], + rk: [seed.wrapping_add(10); 32], + cmx: [seed.wrapping_add(20); 32], + encrypted_note: vec![seed.wrapping_add(30); 692], + cv_net: [seed.wrapping_add(40); 32], + spend_auth_sig: [seed.wrapping_add(50); 64], + } + } + + // --- Insufficient fee tests (dummy bundles — fee check runs before proof verification) --- + + #[test] + fn test_zero_fee_returns_insufficient_fee_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + // 2 actions with zero fee — well below minimum of 123,097,600 + let transition = create_shielded_transfer_transition( + vec![create_dummy_action(1), create_dummy_action(2)], + 0x03, + 0, // zero fee + [42u8; 32], + vec![0u8; 100], + [0u8; 64], + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InsufficientShieldedFeeError(_)) + )] + ); + } + + #[test] + fn test_fee_one_below_minimum_for_2_actions_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + // 2 actions with fee one credit below minimum + let transition = create_shielded_transfer_transition( + vec![create_dummy_action(1), create_dummy_action(2)], + 0x03, + MINIMUM_FEE_2_ACTIONS - 1, // 123,097,599 + [42u8; 32], + vec![0u8; 100], + [0u8; 64], + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InsufficientShieldedFeeError(_)) + )] + ); + } + + #[test] + fn test_fee_one_below_minimum_for_3_actions_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + // 3 actions with fee one credit below minimum + let transition = create_shielded_transfer_transition( + vec![ + create_dummy_action(1), + create_dummy_action(2), + create_dummy_action(3), + ], + 0x03, + MINIMUM_FEE_3_ACTIONS - 1, // 134,646,399 + [42u8; 32], + vec![0u8; 100], + [0u8; 64], + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InsufficientShieldedFeeError(_)) + )] + ); + } + + #[test] + fn test_fee_one_below_minimum_for_4_actions_returns_error() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + // 4 actions with fee one credit below minimum + let transition = create_shielded_transfer_transition( + vec![ + create_dummy_action(1), + create_dummy_action(2), + create_dummy_action(3), + create_dummy_action(4), + ], + 0x03, + MINIMUM_FEE_4_ACTIONS - 1, // 146,195,199 + [42u8; 32], + vec![0u8; 100], + [0u8; 64], + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::UnpaidConsensusError( + ConsensusError::StateError(StateError::InsufficientShieldedFeeError(_)) + )] + ); + } + + // --- Exact minimum fee tests (real bundles with valid ZK proofs) --- + + /// Build a valid 2-action Orchard bundle where value_balance equals the desired fee. + /// Spends `spend_amount` and outputs `spend_amount - fee`, so value_balance = fee. + fn build_bundle_with_fee( + fee: u64, + ) -> (Vec, u8, u64, [u8; 32], Vec, [u8; 64]) { + let mut rng = OsRng; + let pk = get_proving_key(); + + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + let ask = SpendAuthorizingKey::from(&sk); + + let spend_amount = 200_000_000u64; // 200M credits + let output_amount = spend_amount - fee; + + let rho_bytes: [u8; 32] = { + let mut b = [0u8; 32]; + b[0] = 1; + b + }; + let rho = Rho::from_bytes(&rho_bytes).unwrap(); + let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); + let note = + Note::from_parts(recipient, NoteValue::from_raw(spend_amount), rho, rseed).unwrap(); + + let cmx = ExtractedNoteCommitment::from(note.commitment()); + let mut tree = ClientMemoryCommitmentTree::new(100); + tree.append(cmx.to_bytes(), Retention::Marked).unwrap(); + tree.checkpoint(0u32).unwrap(); + let anchor = tree.anchor().unwrap(); + let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); + + let mut builder = Builder::::new(BundleType::DEFAULT, anchor); + builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); + builder + .add_output( + None, + recipient, + NoteValue::from_raw(output_amount), + [0u8; 36], + ) + .unwrap(); + + let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &[]); + let proven = unauthorized.create_proof(pk, &mut rng).unwrap(); + let bundle = proven.apply_signatures(rng, sighash, &[ask]).unwrap(); + + serialize_authorized_bundle(&bundle) + } + + #[test] + fn test_exact_minimum_fee_for_2_actions_succeeds() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + build_bundle_with_fee(MINIMUM_FEE_2_ACTIONS); + + // Verify the bundle has exactly 2 actions and the expected fee + assert_eq!(actions.len(), 2); + assert_eq!(value_balance, MINIMUM_FEE_2_ACTIONS); + + // Set pool balance large enough to cover the fee deduction + set_pool_total_balance(&platform, 500_000_000); + insert_anchor_into_state(&platform, &anchor_bytes); + + let transition = create_shielded_transfer_transition( + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution { .. }] + ); + } + + #[test] + fn test_fee_above_minimum_for_2_actions_succeeds() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + // Pay 1 credit more than the minimum + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + build_bundle_with_fee(MINIMUM_FEE_2_ACTIONS + 1); + + assert_eq!(actions.len(), 2); + assert_eq!(value_balance, MINIMUM_FEE_2_ACTIONS + 1); + + set_pool_total_balance(&platform, 500_000_000); + insert_anchor_into_state(&platform, &anchor_bytes); + + let transition = create_shielded_transfer_transition( + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + ); + + let processing_result = process_transition(&platform, transition, platform_version); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution { .. }] + ); + } + } + // ========================================== // SECURITY AUDIT TESTS // ========================================== @@ -425,6 +749,9 @@ mod tests { use rand::rngs::OsRng; use std::sync::OnceLock; + /// Minimum fee for 2 actions (Orchard builder always produces ≥2). + const MINIMUM_FEE_2_ACTIONS: u64 = 123_097_600; + static TEST_PROVING_KEY: OnceLock = OnceLock::new(); fn get_proving_key() -> &'static ProvingKey { TEST_PROVING_KEY.get_or_init(ProvingKey::build) @@ -461,12 +788,16 @@ mod tests { } /// Build a valid Orchard bundle for shielded transfer tests. + /// Includes sufficient fee (value_balance = MINIMUM_FEE_2_ACTIONS). /// Returns (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig). fn build_valid_shielded_transfer_bundle( ) -> (Vec, u8, u64, [u8; 32], Vec, [u8; 64]) { let mut rng = OsRng; let pk = get_proving_key(); + let spend_amount = 200_000_000u64; + let output_amount = spend_amount - MINIMUM_FEE_2_ACTIONS; + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); let fvk = FullViewingKey::from(&sk); let recipient = fvk.address_at(0u32, Scope::External); @@ -480,7 +811,7 @@ mod tests { let rho = Rho::from_bytes(&rho_bytes).unwrap(); let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); let note = - Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); + Note::from_parts(recipient, NoteValue::from_raw(spend_amount), rho, rseed).unwrap(); let cmx = ExtractedNoteCommitment::from(note.commitment()); let mut tree = ClientMemoryCommitmentTree::new(100); @@ -492,7 +823,12 @@ mod tests { let mut builder = Builder::::new(BundleType::DEFAULT, anchor); builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); builder - .add_output(None, recipient, NoteValue::from_raw(10_000), [0u8; 36]) + .add_output( + None, + recipient, + NoteValue::from_raw(output_amount), + [0u8; 36], + ) .unwrap(); let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); @@ -520,19 +856,17 @@ mod tests { let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = build_valid_shielded_transfer_bundle(); - assert_eq!(value_balance, 0); + assert_eq!(value_balance, MINIMUM_FEE_2_ACTIONS); - // ATTACK: Mutate value_balance from 0 to 5000 - let mutated_value_balance = 5000u64; + // ATTACK: Mutate value_balance (increase by 5000 so it still passes fee check) + let mutated_value_balance = value_balance + 5000; - // Set pool balance so fee deduction doesn't underflow - set_pool_total_balance(&platform, 10_000); insert_anchor_into_state(&platform, &anchor_bytes); let transition = create_shielded_transfer_transition( actions, flags, - mutated_value_balance, // MUTATED: was 0, now 5000 + mutated_value_balance, // MUTATED: different from signed value anchor_bytes, proof_bytes, binding_sig, @@ -540,7 +874,8 @@ mod tests { let processing_result = process_transition(&platform, transition, platform_version); - // FIXED: BatchValidator detects the binding signature mismatch. + // FIXED: BatchValidator detects the binding signature mismatch + // because mutating value_balance changes the bundle commitment (sighash). assert_matches!( processing_result.execution_results().as_slice(), [StateTransitionExecutionResult::UnpaidConsensusError( @@ -646,7 +981,7 @@ mod tests { let transition = create_shielded_transfer_transition( vec![action1, action2], // Both have nullifier [1u8; 32] 0x03, - 0, + MINIMUM_FEE_2_ACTIONS, // sufficient fee so we reach proof verification anchor, vec![0u8; 100], [0u8; 64], diff --git a/packages/rs-drive-abci/src/platform_types/state_transitions_processing_result/mod.rs b/packages/rs-drive-abci/src/platform_types/state_transitions_processing_result/mod.rs index 122947ad77b..c785fad0d93 100644 --- a/packages/rs-drive-abci/src/platform_types/state_transitions_processing_result/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/state_transitions_processing_result/mod.rs @@ -42,8 +42,6 @@ pub enum StateTransitionExecutionResult { fee_result: FeeResult, /// Address balance changes from this state transition address_balance_changes: BTreeMap, - /// Nullifiers inserted by shielded spend actions - nullifiers_inserted: Vec<[u8; 32]>, }, /// State Transition was not executed at all. /// The only current reason for this is that the proposer reached the maximum time limit @@ -57,7 +55,6 @@ pub enum StateTransitionExecutionResult { pub struct StateTransitionsProcessingResult { execution_results: Vec, pub(crate) address_balances_updated: BTreeMap, - pub(crate) nullifiers_inserted: Vec<[u8; 32]>, invalid_paid_count: usize, invalid_unpaid_count: usize, valid_count: usize, @@ -120,7 +117,6 @@ impl StateTransitionsProcessingResult { StateTransitionExecutionResult::SuccessfulExecution { fee_result: actual_fees, address_balance_changes, - nullifiers_inserted, .. } => { self.valid_count += 1; @@ -129,11 +125,6 @@ impl StateTransitionsProcessingResult { // Merge address balance changes self.add_address_balances_in_update(address_balance_changes.clone()); - - // Collect nullifiers from shielded spend actions - if !nullifiers_inserted.is_empty() { - self.nullifiers_inserted.extend(nullifiers_inserted); - } } StateTransitionExecutionResult::NotExecuted(_) => { self.failed_count += 1; @@ -179,9 +170,4 @@ impl StateTransitionsProcessingResult { pub fn execution_results(&self) -> &Vec { &self.execution_results } - - /// Add nullifiers that were inserted during state transition processing - pub fn add_nullifiers_inserted(&mut self, nullifiers: Vec<[u8; 32]>) { - self.nullifiers_inserted.extend(nullifiers); - } } diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs index 87e6cf66191..6e45d4472e3 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs @@ -49,3 +49,17 @@ pub(super) fn update_balance<'a>(ops: &mut Vec>, new_total_ba ShieldedPoolOperationType::UpdateTotalBalance { new_total_balance }, )); } + +/// Store nullifiers to recent block storage for catch-up sync RPCs. +pub(super) fn store_nullifiers_for_block<'a>( + ops: &mut Vec>, + nullifiers: &[[u8; 32]], +) { + if !nullifiers.is_empty() { + ops.push(DriveOperation::ShieldedPoolOperation( + ShieldedPoolOperationType::StoreNullifiersForBlock { + nullifiers: nullifiers.to_vec(), + }, + )); + } +} diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs index fe2a2a8bac2..5913f66dc43 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs @@ -1,4 +1,4 @@ -use super::{insert_notes, insert_nullifiers, update_balance}; +use super::{insert_notes, insert_nullifiers, store_nullifiers_for_block, update_balance}; use crate::error::drive::DriveError; use crate::error::Error; use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; @@ -47,6 +47,9 @@ impl DriveHighLevelOperationConverter for ShieldedTransferTransitionAction { })?; update_balance(&mut ops, new_total_balance); + // 4. Store nullifiers to recent block storage for catch-up sync + store_nullifiers_for_block(&mut ops, &v0.nullifiers); + Ok(ops) } }, diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs index e08057ee85b..0c4bd58338c 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs @@ -1,4 +1,4 @@ -use super::{insert_notes, insert_nullifiers, update_balance}; +use super::{insert_notes, insert_nullifiers, store_nullifiers_for_block, update_balance}; use crate::error::drive::DriveError; use crate::error::Error; use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; @@ -74,6 +74,9 @@ impl DriveHighLevelOperationConverter for ShieldedWithdrawalTransitionAction { SystemOperationType::RemoveFromSystemCredits { amount: v0.amount }, )); + // 6. Store nullifiers to recent block storage for catch-up sync + store_nullifiers_for_block(&mut ops, &v0.nullifiers); + Ok(ops) } }, diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs index d550f5d045d..ed4c00ba2bc 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs @@ -1,4 +1,4 @@ -use super::{insert_notes, insert_nullifiers, update_balance}; +use super::{insert_notes, insert_nullifiers, store_nullifiers_for_block, update_balance}; use crate::error::drive::DriveError; use crate::error::Error; use crate::state_transition_action::action_convert_to_operations::DriveHighLevelOperationConverter; @@ -63,6 +63,9 @@ impl DriveHighLevelOperationConverter for UnshieldTransitionAction { })?; update_balance(&mut ops, new_total_balance); + // 5. Store nullifiers to recent block storage for catch-up sync + store_nullifiers_for_block(&mut ops, &v0.nullifiers); + Ok(ops) } }, diff --git a/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs b/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs index 2ddd8e38555..6cfd34d387a 100644 --- a/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs +++ b/packages/rs-drive/src/util/batch/drive_op_batch/shielded.rs @@ -36,18 +36,24 @@ pub enum ShieldedPoolOperationType { /// The new total balance value new_total_balance: u64, }, + /// Store nullifiers to recent block storage for catch-up sync RPCs. + /// Block height and time are taken from BlockInfo during low-level conversion. + StoreNullifiersForBlock { + /// The nullifiers to store for this block + nullifiers: Vec<[u8; 32]>, + }, } impl DriveLowLevelOperationConverter for ShieldedPoolOperationType { fn into_low_level_drive_operations( self, - _drive: &Drive, + drive: &Drive, estimated_costs_only_with_layer_info: &mut Option< HashMap, >, - _block_info: &BlockInfo, - _transaction: TransactionArg, - _platform_version: &PlatformVersion, + block_info: &BlockInfo, + transaction: TransactionArg, + platform_version: &PlatformVersion, ) -> Result, Error> { if let Some(ref mut estimated_costs) = estimated_costs_only_with_layer_info { Drive::add_estimation_costs_for_shielded_pool_operations(estimated_costs); @@ -98,6 +104,21 @@ impl DriveLowLevelOperationConverter for ShieldedPoolOperationType { ), )]) } + ShieldedPoolOperationType::StoreNullifiersForBlock { nullifiers } => { + // Store nullifiers to recent block storage for catch-up sync RPCs. + // This is a side-effect operation — it doesn't produce low-level grove ops + // but instead calls store_nullifiers_for_block directly. + if !nullifiers.is_empty() { + drive.store_nullifiers_for_block( + &nullifiers, + block_info.height, + block_info.time_ms, + transaction, + platform_version, + )?; + } + Ok(vec![]) + } } } } 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 893aa6c69ae..24e6f1cf8cc 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 @@ -31,9 +31,12 @@ pub struct DriveAbciValidationConstants { /// transitions (Unshield, ShieldedWithdrawal) are allowed. This ensures a /// sufficient anonymity set before funds can leave the pool. pub minimum_pool_notes_for_outgoing: u64, - /// Minimum fee (in credits) required for shielded transitions that pay fees - /// from the shielded pool (ShieldedTransfer, Unshield, ShieldedWithdrawal). - pub minimum_shielded_fee: u64, + /// Per-bundle fee (in credits) for Halo 2 ZK proof verification. + /// Benchmarked at ~30x per-action signature verification cost. + pub shielded_proof_verification_fee: u64, + /// Per-action fee (in credits) for processing: RedPallas spend auth signature + /// verification, nullifier duplicate check, and tree insertion. + pub shielded_per_action_processing_fee: u64, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs index 31b6daa8cb0..45dce6261b5 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v1.rs @@ -260,6 +260,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V1: DriveAbciValidationVersions = maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, minimum_pool_notes_for_outgoing: 250, - minimum_shielded_fee: 1, + shielded_proof_verification_fee: 100_000_000, + shielded_per_action_processing_fee: 3_000_000, }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs index 80266c555df..4e6dbad38e7 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v2.rs @@ -260,6 +260,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V2: DriveAbciValidationVersions = maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, minimum_pool_notes_for_outgoing: 250, - minimum_shielded_fee: 1, + shielded_proof_verification_fee: 100_000_000, + shielded_per_action_processing_fee: 3_000_000, }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs index daff58bb158..2d72c6cc872 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v3.rs @@ -260,6 +260,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V3: DriveAbciValidationVersions = maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, minimum_pool_notes_for_outgoing: 250, - minimum_shielded_fee: 1, + shielded_proof_verification_fee: 100_000_000, + shielded_per_action_processing_fee: 3_000_000, }, }; 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 0e8d1a5a8a8..3af5abca025 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 @@ -263,6 +263,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V4: DriveAbciValidationVersions = maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, minimum_pool_notes_for_outgoing: 250, - minimum_shielded_fee: 1, + shielded_proof_verification_fee: 100_000_000, + shielded_per_action_processing_fee: 3_000_000, }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs index a6e12782842..8d207dd4a26 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v5.rs @@ -264,6 +264,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V5: DriveAbciValidationVersions = maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, minimum_pool_notes_for_outgoing: 250, - minimum_shielded_fee: 1, + shielded_proof_verification_fee: 100_000_000, + shielded_per_action_processing_fee: 3_000_000, }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs index 1cf61e5b2be..e6851d78904 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v6.rs @@ -267,6 +267,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V6: DriveAbciValidationVersions = maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, minimum_pool_notes_for_outgoing: 250, - minimum_shielded_fee: 1, + shielded_proof_verification_fee: 100_000_000, + shielded_per_action_processing_fee: 3_000_000, }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs index 2d5bb45e4e6..c8900b408b6 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v7.rs @@ -261,6 +261,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V7: DriveAbciValidationVersions = maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, minimum_pool_notes_for_outgoing: 250, - minimum_shielded_fee: 1, + shielded_proof_verification_fee: 100_000_000, + shielded_per_action_processing_fee: 3_000_000, }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v8.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v8.rs index 6141bdf58c1..a9936441ff8 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v8.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_validation_versions/v8.rs @@ -265,6 +265,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V8: DriveAbciValidationVersions = maximum_vote_polls_to_process: 2, maximum_contenders_to_consider: 100, minimum_pool_notes_for_outgoing: 250, - minimum_shielded_fee: 1, + shielded_proof_verification_fee: 100_000_000, + shielded_per_action_processing_fee: 3_000_000, }, }; 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 38d19591d29..caa84f9ebdd 100644 --- a/packages/rs-platform-version/src/version/mocks/v2_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v2_test.rs @@ -32,6 +32,7 @@ use crate::version::drive_versions::drive_contract_method_versions::v1::DRIVE_CO use crate::version::drive_versions::drive_credit_pool_method_versions::v1::CREDIT_POOL_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_document_method_versions::v1::DRIVE_DOCUMENT_METHOD_VERSIONS_V1; use crate::version::drive_versions::drive_group_method_versions::v1::DRIVE_GROUP_METHOD_VERSIONS_V1; +use crate::version::drive_versions::drive_group_method_versions::DriveShieldedMethodVersions; 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; @@ -141,6 +142,12 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { }, group: DRIVE_GROUP_METHOD_VERSIONS_V1, address_funds: DRIVE_ADDRESS_FUNDS_METHOD_VERSIONS_V1, + shielded: DriveShieldedMethodVersions { + prove_nullifiers_trunk_query: 0, + prove_nullifiers_branch_query: 0, + nullifiers_query_min_depth: 6, + nullifiers_query_max_depth: 10, + }, saved_block_transactions: DriveSavedBlockTransactionsMethodVersions { store_address_balances: 0, fetch_address_balances: 0, compact_address_balances: 0, cleanup_expired_address_balances: 0, max_blocks_before_compaction: 64, max_addresses_before_compaction: 2048, store_nullifiers: 0, fetch_nullifiers: 0, compact_nullifiers: 0, cleanup_expired_nullifiers: 0, max_blocks_before_nullifier_compaction: 64, max_nullifiers_before_compaction: 2048 }, }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, From ed89b5b75b79db5a45b6918e1af5094a052046bf Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 25 Feb 2026 09:37:13 +0700 Subject: [PATCH 33/40] more work --- Cargo.lock | 30 ++--- packages/rs-dpp/Cargo.toml | 2 +- packages/rs-dpp/src/shielded/builder.rs | 106 ++++++++++++++---- packages/rs-dpp/src/shielded/mod.rs | 33 ++++++ packages/rs-drive-abci/Cargo.toml | 4 +- .../processor/traits/shielded_proof.rs | 6 +- packages/rs-drive/Cargo.toml | 12 +- packages/rs-platform-version/Cargo.toml | 2 +- packages/rs-sdk/Cargo.toml | 2 +- 9 files changed, 147 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 47405d25fa5..e3adb90e9ec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2614,7 +2614,7 @@ dependencies = [ [[package]] name = "grovedb" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" +source = "git+https://github.com/dashpay/grovedb?rev=0df4c6ba82a452c8286174554074fd59704e3b06#0df4c6ba82a452c8286174554074fd59704e3b06" dependencies = [ "axum 0.8.8", "bincode", @@ -2652,7 +2652,7 @@ dependencies = [ [[package]] name = "grovedb-bulk-append-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" +source = "git+https://github.com/dashpay/grovedb?rev=0df4c6ba82a452c8286174554074fd59704e3b06#0df4c6ba82a452c8286174554074fd59704e3b06" dependencies = [ "bincode", "blake3", @@ -2668,7 +2668,7 @@ dependencies = [ [[package]] name = "grovedb-commitment-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" +source = "git+https://github.com/dashpay/grovedb?rev=0df4c6ba82a452c8286174554074fd59704e3b06#0df4c6ba82a452c8286174554074fd59704e3b06" dependencies = [ "incrementalmerkletree", "orchard", @@ -2680,7 +2680,7 @@ dependencies = [ [[package]] name = "grovedb-costs" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" +source = "git+https://github.com/dashpay/grovedb?rev=0df4c6ba82a452c8286174554074fd59704e3b06#0df4c6ba82a452c8286174554074fd59704e3b06" dependencies = [ "integer-encoding", "intmap", @@ -2690,7 +2690,7 @@ dependencies = [ [[package]] name = "grovedb-dense-fixed-sized-merkle-tree" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" +source = "git+https://github.com/dashpay/grovedb?rev=0df4c6ba82a452c8286174554074fd59704e3b06#0df4c6ba82a452c8286174554074fd59704e3b06" dependencies = [ "bincode", "blake3", @@ -2703,7 +2703,7 @@ dependencies = [ [[package]] name = "grovedb-element" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" +source = "git+https://github.com/dashpay/grovedb?rev=0df4c6ba82a452c8286174554074fd59704e3b06#0df4c6ba82a452c8286174554074fd59704e3b06" dependencies = [ "bincode", "bincode_derive", @@ -2718,7 +2718,7 @@ dependencies = [ [[package]] name = "grovedb-epoch-based-storage-flags" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" +source = "git+https://github.com/dashpay/grovedb?rev=0df4c6ba82a452c8286174554074fd59704e3b06#0df4c6ba82a452c8286174554074fd59704e3b06" dependencies = [ "grovedb-costs", "hex", @@ -2730,7 +2730,7 @@ dependencies = [ [[package]] name = "grovedb-merk" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" +source = "git+https://github.com/dashpay/grovedb?rev=0df4c6ba82a452c8286174554074fd59704e3b06#0df4c6ba82a452c8286174554074fd59704e3b06" dependencies = [ "bincode", "bincode_derive", @@ -2756,7 +2756,7 @@ dependencies = [ [[package]] name = "grovedb-merkle-mountain-range" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" +source = "git+https://github.com/dashpay/grovedb?rev=0df4c6ba82a452c8286174554074fd59704e3b06#0df4c6ba82a452c8286174554074fd59704e3b06" dependencies = [ "bincode", "blake3", @@ -2767,7 +2767,7 @@ dependencies = [ [[package]] name = "grovedb-path" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" +source = "git+https://github.com/dashpay/grovedb?rev=0df4c6ba82a452c8286174554074fd59704e3b06#0df4c6ba82a452c8286174554074fd59704e3b06" dependencies = [ "hex", ] @@ -2775,7 +2775,7 @@ dependencies = [ [[package]] name = "grovedb-query" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" +source = "git+https://github.com/dashpay/grovedb?rev=0df4c6ba82a452c8286174554074fd59704e3b06#0df4c6ba82a452c8286174554074fd59704e3b06" dependencies = [ "bincode", "byteorder", @@ -2791,7 +2791,7 @@ dependencies = [ [[package]] name = "grovedb-storage" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" +source = "git+https://github.com/dashpay/grovedb?rev=0df4c6ba82a452c8286174554074fd59704e3b06#0df4c6ba82a452c8286174554074fd59704e3b06" dependencies = [ "blake3", "grovedb-costs", @@ -2810,7 +2810,7 @@ dependencies = [ [[package]] name = "grovedb-version" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" +source = "git+https://github.com/dashpay/grovedb?rev=0df4c6ba82a452c8286174554074fd59704e3b06#0df4c6ba82a452c8286174554074fd59704e3b06" dependencies = [ "thiserror 2.0.18", "versioned-feature-core 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2819,7 +2819,7 @@ dependencies = [ [[package]] name = "grovedb-visualize" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" +source = "git+https://github.com/dashpay/grovedb?rev=0df4c6ba82a452c8286174554074fd59704e3b06#0df4c6ba82a452c8286174554074fd59704e3b06" dependencies = [ "hex", "itertools 0.14.0", @@ -2828,7 +2828,7 @@ dependencies = [ [[package]] name = "grovedbg-types" version = "4.0.0" -source = "git+https://github.com/dashpay/grovedb?rev=59c25a734f0b885e1749437600217761ccd3e7de#59c25a734f0b885e1749437600217761ccd3e7de" +source = "git+https://github.com/dashpay/grovedb?rev=0df4c6ba82a452c8286174554074fd59704e3b06#0df4c6ba82a452c8286174554074fd59704e3b06" dependencies = [ "serde", "serde_with 3.16.1", diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index 3827b7d7156..03bbb9d182b 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -71,7 +71,7 @@ strum = { version = "0.26", features = ["derive"] } json-schema-compatibility-validator = { path = '../rs-json-schema-compatibility-validator', optional = true } once_cell = "1.19.0" tracing = { version = "0.1.41" } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de", optional = true } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "0df4c6ba82a452c8286174554074fd59704e3b06", optional = true } [dev-dependencies] tokio = { version = "1.40", features = ["full"] } diff --git a/packages/rs-dpp/src/shielded/builder.rs b/packages/rs-dpp/src/shielded/builder.rs index c533b12f06a..878ee41c015 100644 --- a/packages/rs-dpp/src/shielded/builder.rs +++ b/packages/rs-dpp/src/shielded/builder.rs @@ -42,7 +42,7 @@ use crate::fee::Credits; use crate::identity::core_script::CoreScript; use crate::identity::signer::Signer; use crate::prelude::{AddressNonce, UserFeeIncrease}; -use crate::shielded::{compute_platform_sighash, SerializedAction}; +use crate::shielded::{compute_minimum_shielded_fee, compute_platform_sighash, SerializedAction}; use crate::state_transition::shield_from_asset_lock_transition::methods::ShieldFromAssetLockTransitionMethodsV0; use crate::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; use crate::state_transition::shield_transition::methods::ShieldTransitionMethodsV0; @@ -309,8 +309,9 @@ pub fn build_shield_from_asset_lock_transition( /// Builds a ShieldedTransfer state transition (shielded pool -> shielded pool). /// -/// Spends existing notes and creates a new note for the recipient. Any change -/// (total spent - transfer amount) is returned to the `change_address`. +/// Spends existing notes and creates a new note for the recipient. The shielded +/// fee is deducted from the spent notes. Any remaining change is returned to +/// the `change_address`. /// /// # Parameters /// - `spends` - Notes to spend with their Merkle paths @@ -322,6 +323,8 @@ pub fn build_shield_from_asset_lock_transition( /// - `anchor` - Merkle root of the commitment tree /// - `proving_key` - Halo 2 proving key /// - `memo` - 36-byte structured memo for the recipient (4-byte type tag + 32-byte payload) +/// - `fee` - Optional fee override; if `None`, the minimum fee is computed automatically. +/// If `Some`, must be >= the minimum fee. /// - `platform_version` - Protocol version pub fn build_shielded_transfer_transition( spends: Vec, @@ -333,17 +336,37 @@ pub fn build_shielded_transfer_transition( anchor: Anchor, proving_key: &ProvingKey, memo: [u8; 36], + fee: Option, platform_version: &PlatformVersion, ) -> Result { let total_spent: u64 = spends.iter().map(|s| s.note.value().inner()).sum(); - if transfer_amount > total_spent { + + // Conservative action count: at least (spends, 2) since we always have + // a recipient output and likely a change output. + let num_actions = spends.len().max(2); + let min_fee = compute_minimum_shielded_fee(num_actions, platform_version); + let effective_fee = match fee { + Some(f) if f < min_fee => { + return Err(ProtocolError::Generic(format!( + "fee {} is below minimum required fee {}", + f, min_fee + ))); + } + Some(f) => f, + None => min_fee, + }; + + let required = transfer_amount + .checked_add(effective_fee) + .ok_or_else(|| ProtocolError::Generic("fee + transfer_amount overflows u64".to_string()))?; + if required > total_spent { return Err(ProtocolError::Generic(format!( - "transfer amount {} exceeds total spendable value {}", - transfer_amount, total_spent + "transfer amount {} + fee {} = {} exceeds total spendable value {}", + transfer_amount, effective_fee, required, total_spent ))); } - let change_amount = total_spent - transfer_amount; + let change_amount = total_spent - required; let recipient_payment = orchard_address_to_payment_address(recipient)?; @@ -383,8 +406,7 @@ pub fn build_shielded_transfer_transition( let (actions, flags, value_balance, anchor_bytes, proof, binding_sig) = serialize_authorized_bundle(&bundle); - // value_balance for shielded transfer is u64; cast from i64 - // (should be 0 when transfer_amount == total_spent, positive if fees leave pool) + // value_balance = effective_fee (the amount leaving the shielded pool as fee) ShieldedTransferTransition::try_from_bundle( actions, flags, @@ -399,7 +421,8 @@ pub fn build_shielded_transfer_transition( /// Builds an Unshield state transition (shielded pool -> platform address). /// /// Spends existing notes and sends part of the value to a transparent platform -/// address. Any remaining value is returned to the shielded `change_address`. +/// address. The shielded fee is deducted from the spent notes. Any remaining +/// value is returned to the shielded `change_address`. /// /// # Parameters /// - `spends` - Notes to spend with their Merkle paths @@ -411,6 +434,8 @@ pub fn build_shielded_transfer_transition( /// - `anchor` - Merkle root of the commitment tree /// - `proving_key` - Halo 2 proving key /// - `memo` - 36-byte structured memo for the change output (4-byte type tag + 32-byte payload) +/// - `fee` - Optional fee override; if `None`, the minimum fee is computed automatically. +/// If `Some`, must be >= the minimum fee. /// - `platform_version` - Protocol version pub fn build_unshield_transition( spends: Vec, @@ -422,17 +447,36 @@ pub fn build_unshield_transition( anchor: Anchor, proving_key: &ProvingKey, memo: [u8; 36], + fee: Option, platform_version: &PlatformVersion, ) -> Result { let total_spent: u64 = spends.iter().map(|s| s.note.value().inner()).sum(); - if unshield_amount > total_spent { + + // Conservative action count: at least (spends, 1) since we have a change output. + let num_actions = spends.len().max(1); + let min_fee = compute_minimum_shielded_fee(num_actions, platform_version); + let effective_fee = match fee { + Some(f) if f < min_fee => { + return Err(ProtocolError::Generic(format!( + "fee {} is below minimum required fee {}", + f, min_fee + ))); + } + Some(f) => f, + None => min_fee, + }; + + let required = unshield_amount + .checked_add(effective_fee) + .ok_or_else(|| ProtocolError::Generic("fee + unshield_amount overflows u64".to_string()))?; + if required > total_spent { return Err(ProtocolError::Generic(format!( - "unshield amount {} exceeds total spendable value {}", - unshield_amount, total_spent + "unshield amount {} + fee {} = {} exceeds total spendable value {}", + unshield_amount, effective_fee, required, total_spent ))); } - let change_amount = total_spent - unshield_amount; + let change_amount = total_spent - required; // Unshield extra_data = output_address.to_bytes() || amount.to_le_bytes() let mut extra_sighash_data = output_address.to_bytes(); @@ -469,7 +513,8 @@ pub fn build_unshield_transition( /// Builds a ShieldedWithdrawal state transition (shielded pool -> core L1 address). /// /// Spends existing notes and withdraws value to a core chain script output. -/// Any remaining value is returned to the shielded `change_address`. +/// The shielded fee is deducted from the spent notes. Any remaining value is +/// returned to the shielded `change_address`. /// /// # Parameters /// - `spends` - Notes to spend with their Merkle paths @@ -483,6 +528,8 @@ pub fn build_unshield_transition( /// - `anchor` - Merkle root of the commitment tree /// - `proving_key` - Halo 2 proving key /// - `memo` - 36-byte structured memo for the change output (4-byte type tag + 32-byte payload) +/// - `fee` - Optional fee override; if `None`, the minimum fee is computed automatically. +/// If `Some`, must be >= the minimum fee. /// - `platform_version` - Protocol version pub fn build_shielded_withdrawal_transition( spends: Vec, @@ -496,17 +543,38 @@ pub fn build_shielded_withdrawal_transition( anchor: Anchor, proving_key: &ProvingKey, memo: [u8; 36], + fee: Option, platform_version: &PlatformVersion, ) -> Result { let total_spent: u64 = spends.iter().map(|s| s.note.value().inner()).sum(); - if withdrawal_amount > total_spent { + + // Conservative action count: at least (spends, 1) since we have a change output. + let num_actions = spends.len().max(1); + let min_fee = compute_minimum_shielded_fee(num_actions, platform_version); + let effective_fee = match fee { + Some(f) if f < min_fee => { + return Err(ProtocolError::Generic(format!( + "fee {} is below minimum required fee {}", + f, min_fee + ))); + } + Some(f) => f, + None => min_fee, + }; + + let required = withdrawal_amount + .checked_add(effective_fee) + .ok_or_else(|| { + ProtocolError::Generic("fee + withdrawal_amount overflows u64".to_string()) + })?; + if required > total_spent { return Err(ProtocolError::Generic(format!( - "withdrawal amount {} exceeds total spendable value {}", - withdrawal_amount, total_spent + "withdrawal amount {} + fee {} = {} exceeds total spendable value {}", + withdrawal_amount, effective_fee, required, total_spent ))); } - let change_amount = total_spent - withdrawal_amount; + let change_amount = total_spent - required; // ShieldedWithdrawal extra_data = output_script.as_bytes() || amount.to_le_bytes() let mut extra_sighash_data = output_script.as_bytes().to_vec(); diff --git a/packages/rs-dpp/src/shielded/mod.rs b/packages/rs-dpp/src/shielded/mod.rs index 0690ffcab8b..1c451e9f352 100644 --- a/packages/rs-dpp/src/shielded/mod.rs +++ b/packages/rs-dpp/src/shielded/mod.rs @@ -6,6 +6,14 @@ use bincode::{Decode, Encode}; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; +use crate::fee::Credits; +use platform_version::version::PlatformVersion; + +/// Permanent storage bytes per shielded action: +/// 280 bytes in BulkAppendTree (32 cmx + 32 nullifier + 216 encrypted note) +/// + 32 bytes in nullifier tree = 312 bytes total. +pub const SHIELDED_STORAGE_BYTES_PER_ACTION: u64 = 312; + /// Domain separator for Platform sighash computation. const SIGHASH_DOMAIN: &[u8] = b"DashPlatformSighash"; @@ -30,6 +38,31 @@ pub fn compute_platform_sighash(bundle_commitment: &[u8; 32], extra_data: &[u8]) hasher.finalize().into() } +/// Computes the minimum fee (in credits) for a shielded state transition. +/// +/// The fee formula mirrors the on-chain validation in `validate_minimum_shielded_fee`: +/// `min_fee = proof_verification_fee + num_actions × (processing_fee + storage_fee)` +/// +/// where `storage_fee = SHIELDED_STORAGE_BYTES_PER_ACTION × (disk + processing) credits/byte`. +/// +/// # Parameters +/// - `num_actions` — number of Orchard actions in the bundle +/// - `platform_version` — protocol version (determines fee constants) +pub fn compute_minimum_shielded_fee( + num_actions: usize, + platform_version: &PlatformVersion, +) -> Credits { + let constants = &platform_version + .drive_abci + .validation_and_processing + .event_constants; + let storage = &platform_version.fee_version.storage; + let storage_fee = SHIELDED_STORAGE_BYTES_PER_ACTION + * (storage.storage_disk_usage_credit_per_byte + storage.storage_processing_credit_per_byte); + let per_action = constants.shielded_per_action_processing_fee + storage_fee; + constants.shielded_proof_verification_fee + num_actions as u64 * per_action +} + /// Serde helper for `[u8; 64]` fields (serde only supports arrays up to 32). #[cfg(feature = "state-transition-serde-conversion")] pub(crate) mod serde_bytes_64 { diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index 2793bd06305..27f3a969c2a 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -82,7 +82,7 @@ derive_more = { version = "1.0", features = ["from", "deref", "deref_mut"] } async-trait = "0.1.77" console-subscriber = { version = "0.4", optional = true } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f", optional = true } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de" } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "0df4c6ba82a452c8286174554074fd59704e3b06" } sha2 = "0.10" nonempty = "0.11" @@ -105,7 +105,7 @@ dpp = { path = "../rs-dpp", default-features = false, features = [ drive = { path = "../rs-drive", features = ["fixtures-and-mocks"] } drive-proof-verifier = { path = "../rs-drive-proof-verifier" } strategy-tests = { path = "../strategy-tests" } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de", features = ["client"] } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "0df4c6ba82a452c8286174554074fd59704e3b06", features = ["client"] } assert_matches = "1.5.0" drive-abci = { path = ".", features = ["testing-config", "mocks"] } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", rev = "0842b17583888e8f46c252a4ee84cdfd58e0546f" } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/shielded_proof.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/shielded_proof.rs index 6a302477a0b..0905007c844 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/shielded_proof.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/processor/traits/shielded_proof.rs @@ -3,15 +3,11 @@ use crate::error::Error; use crate::execution::validation::state_transition::state_transitions::shielded_common::reconstruct_and_verify_bundle; use dpp::consensus::state::shielded::insufficient_shielded_fee_error::InsufficientShieldedFeeError; use dpp::consensus::state::state_error::StateError; +use dpp::shielded::SHIELDED_STORAGE_BYTES_PER_ACTION; use dpp::state_transition::StateTransition; use dpp::validation::SimpleConsensusValidationResult; use dpp::version::PlatformVersion; -/// Permanent storage bytes per shielded action: -/// 280 bytes in BulkAppendTree (32 cmx + 32 nullifier + 216 encrypted note) -/// + 32 bytes in nullifier tree = 312 bytes total. -const SHIELDED_STORAGE_BYTES_PER_ACTION: u64 = 312; - /// A trait for checking whether a state transition requires shielded ZK proof validation. pub(crate) trait StateTransitionHasShieldedProofValidationV0 { /// Returns true if this state transition has a ZK proof that must be verified diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index 776231f4e7c..f8351453775 100644 --- a/packages/rs-drive/Cargo.toml +++ b/packages/rs-drive/Cargo.toml @@ -52,12 +52,12 @@ enum-map = { version = "2.0.3", optional = true } intmap = { version = "3.0.1", features = ["serde"], optional = true } chrono = { version = "0.4.35", optional = true } itertools = { version = "0.13", optional = true } -grovedb = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de", optional = true, default-features = false } -grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de", optional = true } -grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de" } -grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de", optional = true } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de" } -grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de" } +grovedb = { git = "https://github.com/dashpay/grovedb", rev = "0df4c6ba82a452c8286174554074fd59704e3b06", optional = true, default-features = false } +grovedb-costs = { git = "https://github.com/dashpay/grovedb", rev = "0df4c6ba82a452c8286174554074fd59704e3b06", optional = true } +grovedb-path = { git = "https://github.com/dashpay/grovedb", rev = "0df4c6ba82a452c8286174554074fd59704e3b06" } +grovedb-storage = { git = "https://github.com/dashpay/grovedb", rev = "0df4c6ba82a452c8286174554074fd59704e3b06", optional = true } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "0df4c6ba82a452c8286174554074fd59704e3b06" } +grovedb-epoch-based-storage-flags = { git = "https://github.com/dashpay/grovedb", rev = "0df4c6ba82a452c8286174554074fd59704e3b06" } [dev-dependencies] criterion = "0.5" diff --git a/packages/rs-platform-version/Cargo.toml b/packages/rs-platform-version/Cargo.toml index 64123f578f7..2af25b36f63 100644 --- a/packages/rs-platform-version/Cargo.toml +++ b/packages/rs-platform-version/Cargo.toml @@ -11,7 +11,7 @@ license = "MIT" thiserror = { version = "2.0.12" } bincode = { version = "=2.0.1" } versioned-feature-core = { git = "https://github.com/dashpay/versioned-feature-core", version = "1.0.0" } -grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de" } +grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "0df4c6ba82a452c8286174554074fd59704e3b06" } [features] mock-versions = [] diff --git a/packages/rs-sdk/Cargo.toml b/packages/rs-sdk/Cargo.toml index 00020ff4359..cc527cb0682 100644 --- a/packages/rs-sdk/Cargo.toml +++ b/packages/rs-sdk/Cargo.toml @@ -18,7 +18,7 @@ drive = { path = "../rs-drive", default-features = false, features = [ platform-wallet = { path = "../rs-platform-wallet", optional = true } drive-proof-verifier = { path = "../rs-drive-proof-verifier", default-features = false } -grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "59c25a734f0b885e1749437600217761ccd3e7de", features = ["client", "sqlite"], optional = true } +grovedb-commitment-tree = { git = "https://github.com/dashpay/grovedb", rev = "0df4c6ba82a452c8286174554074fd59704e3b06", features = ["client", "sqlite"], optional = true } dash-context-provider = { path = "../rs-context-provider", default-features = false } dash-platform-macros = { path = "../rs-dash-platform-macros" } http = { version = "1.1" } From 24fea3cb30a9800f684e2a3c921d9ea9c1d066d0 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 25 Feb 2026 14:01:17 +0700 Subject: [PATCH 34/40] more work --- book/src/SUMMARY.md | 1 + book/src/state-transitions/return-proofs.md | 182 ++++++++++++ packages/rs-dpp/src/asset_lock/mod.rs | 1 + .../src/errors/consensus/basic/basic_error.rs | 11 +- .../consensus/basic/state_transition/mod.rs | 2 + .../shielded_too_many_actions_error.rs | 46 +++ packages/rs-dpp/src/errors/consensus/codes.rs | 3 +- .../src/state_transition/proof_result.rs | 13 +- .../shielded/common_validation.rs | 16 +- .../v0/state_transition_validation.rs | 13 +- .../v0/state_transition_validation.rs | 11 +- .../accessors/mod.rs | 14 + .../accessors/v0/mod.rs | 15 + .../shielded_transfer_transition/mod.rs | 1 + .../v0/state_transition_validation.rs | 13 +- .../accessors/mod.rs | 21 ++ .../accessors/v0/mod.rs | 19 ++ .../shielded_withdrawal_transition/mod.rs | 1 + .../v0/state_transition_validation.rs | 13 +- .../unshield_transition/accessors/mod.rs | 21 ++ .../unshield_transition/accessors/v0/mod.rs | 19 ++ .../shielded/unshield_transition/mod.rs | 1 + .../v0/state_transition_validation.rs | 13 +- .../state_transitions/shield/tests.rs | 234 +++++++++++++++ .../shield_from_asset_lock/tests.rs | 186 ++++++++++++ .../shielded_transfer/tests.rs | 215 ++++++++++++++ .../shielded_withdrawal/tests.rs | 277 ++++++++++++++++++ .../state_transitions/unshield/tests.rs | 237 +++++++++++++++ .../test_cases/address_tests.rs | 5 +- .../prove/prove_state_transition/v0/mod.rs | 111 ++++++- .../v0/mod.rs | 218 +++++++++++++- .../src/version/mocks/v2_test.rs | 1 + .../src/version/system_limits/mod.rs | 1 + .../src/version/system_limits/v1.rs | 1 + .../src/system/queries/path_elements.rs | 15 +- .../src/errors/consensus/consensus_error.rs | 10 +- .../src/state_transitions/proof_result.rs | 50 ++-- 37 files changed, 1929 insertions(+), 82 deletions(-) create mode 100644 book/src/state-transitions/return-proofs.md create mode 100644 packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_too_many_actions_error.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/accessors/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/accessors/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/accessors/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/accessors/v0/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/accessors/mod.rs create mode 100644 packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/accessors/v0/mod.rs diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 86685496ecd..01e819ee13c 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -21,6 +21,7 @@ - [Validation Pipeline](state-transitions/validation-pipeline.md) - [Transform Into Action](state-transitions/transform-into-action.md) - [Drive Operations](state-transitions/drive-operations.md) +- [Return Proofs](state-transitions/return-proofs.md) # Fees diff --git a/book/src/state-transitions/return-proofs.md b/book/src/state-transitions/return-proofs.md new file mode 100644 index 00000000000..f0f4e3a56a6 --- /dev/null +++ b/book/src/state-transitions/return-proofs.md @@ -0,0 +1,182 @@ +# Return Proofs + +After a state transition is confirmed in a block, clients can request a **return proof** — +a GroveDB Merkle proof demonstrating that the expected state changes were actually applied. +This lets light clients verify execution without trusting the node. + +## How It Works + +The flow is: + +1. Client broadcasts a state transition via DAPI. +2. Client calls `waitForStateTransitionResult` with `prove: true`. +3. The node waits for the transition to be included in a block. +4. Drive deserializes the transition and calls `prove_state_transition()`. +5. This builds a `PathQuery` describing which GroveDB paths/keys the transition affected. +6. GroveDB generates a Merkle proof covering exactly those paths. +7. The proof is returned to the client in the response. + +The client then calls `verify_state_transition_was_executed_with_proof()` to check the +proof against the known app hash (root hash). If verification succeeds, the client receives +a `StateTransitionProofResult` containing the verified data. + +## Key Design Decisions + +- **Minimal proofs.** Only the paths/keys affected by the transition are included, not the + entire state tree. This keeps proofs small. +- **Type-specific.** Each transition type proves different data — an identity create proves + the full identity, while a top-up only proves the new balance. +- **On-demand.** Proofs are generated after confirmation, not during validation. +- **Batch limitation.** Batch transitions (documents/tokens) currently support proofs only + for single-transition batches. +- **Limits removed.** All `PathQuery` limits are set to `None` before proof generation to + ensure the full result set is included. + +## What Each Transition Proves + +### Identity Transitions + +| Transition | What's Proved | Verified Result | +|---|---|---| +| **IdentityCreate** | Full identity: data, balance, nonce, all public keys | `VerifiedIdentity(Identity)` | +| **IdentityTopUp** | Balance and revision only | `VerifiedPartialIdentity { balance, revision }` | +| **IdentityCreditWithdrawal** | Balance only | `VerifiedPartialIdentity { balance }` | +| **IdentityUpdate** | All public keys | `VerifiedPartialIdentity { loaded_public_keys }` | +| **IdentityCreditTransfer** | Sender balance + recipient balance | `VerifiedBalanceTransfer(sender, recipient)` | + +The proof generation uses these Drive query helpers: + +- `Drive::full_identity_query()` — identity tree + balance + nonce + all key subtree +- `Drive::revision_and_balance_path_query()` — just balance and revision elements +- `Drive::identity_balance_query()` — just the balance element +- `Drive::identity_all_keys_query()` — identity key subtree + +For **IdentityCreditTransfer**, the sender and recipient balance queries are merged into +a single `PathQuery` via `PathQuery::merge()`. + +### Identity + Address Transitions + +| Transition | What's Proved | Verified Result | +|---|---|---| +| **IdentityCreditTransferToAddresses** | Identity balance/revision + recipient address balances | `VerifiedIdentityWithAddressInfos` | +| **IdentityCreateFromAddresses** | Full identity + all input/output address balances | `VerifiedIdentityFullWithAddressInfos` | +| **IdentityTopUpFromAddresses** | Identity balance/revision + input/output address balances | `VerifiedIdentityWithAddressInfos` | + +These combine `Drive::revision_and_balance_path_query()` (or `full_identity_query()` for +create) with `Drive::balances_for_clear_addresses_query()`, merged into a single proof. + +### Address Fund Transitions + +| Transition | What's Proved | Verified Result | +|---|---|---| +| **AddressFundsTransfer** | All input + output address balances | `VerifiedAddressInfos` | +| **AddressFundingFromAssetLock** | All input + output address balances | `VerifiedAddressInfos` | +| **AddressCreditWithdrawal** | Input addresses + output address balance | `VerifiedAddressInfos` | + +All use `Drive::balances_for_clear_addresses_query()`. Each address entry in the proof +contains its nonce and credit balance, allowing the client to verify post-transition +balances. + +### Data Contract Transitions + +| Transition | What's Proved | Verified Result | +|---|---|---| +| **DataContractCreate** | The contract itself | `VerifiedDataContract(DataContract)` | +| **DataContractUpdate** | The updated contract | `VerifiedDataContract(DataContract)` | + +The query depends on whether the contract keeps history: +- Historical: `Drive::fetch_historical_contracts_query()` +- Non-historical: `Drive::fetch_non_historical_contracts_query()` + +Verification reconstructs the contract from the proof and compares it field-by-field +against the state transition's contract data via `first_mismatch()`. + +### Document Transitions (via Batch) + +| Operation | What's Proved | Verified Result | +|---|---|---| +| **Create** | The created document | `VerifiedDocuments({ id: Some(doc) })` | +| **Replace** | The replaced document | `VerifiedDocuments({ id: Some(doc) })` | +| **Delete** | Absence of the document | `VerifiedDocuments({ id: None })` | +| **Transfer** | The document (with new owner) | `VerifiedDocuments({ id: Some(doc) })` | +| **UpdatePrice** | The document (with new price) | `VerifiedDocuments({ id: Some(doc) })` | +| **Purchase** | The document (with new owner) | `VerifiedDocuments({ id: Some(doc) })` | + +All document operations use `SingleDocumentDriveQuery` to construct the path query. +For creates with prefunded voting balances, the query uses `Contested` status to look +up the document in the contested index tree instead of the regular document tree. + +Verification checks: +- **Create/Replace:** Reconstructs the expected document from the transition and compares + fields (ignoring time-based fields and transient fields). +- **Delete:** Asserts the document is absent from the proof. +- **Transfer/Purchase:** Verifies the document's `owner_id` matches the expected recipient. +- **UpdatePrice:** Verifies the document's `price` field matches the transition's price. + +### Token Transitions (via Batch) + +Token proof behavior depends on whether the token keeps historical documents for that +operation type. When history is enabled, the proof contains a historical document in the +token history contract. When disabled, the proof contains the raw state (balance, info, etc.). + +| Operation | History Off | History On | +|---|---|---| +| **Mint** | Recipient token balance | Historical mint document | +| **Burn** | Owner token balance | Historical burn document | +| **Transfer** | Sender + recipient balances | Historical transfer document | +| **Freeze** | Frozen identity's token info | Historical freeze document | +| **Unfreeze** | Unfrozen identity's token info | Historical unfreeze document | +| **DirectPurchase** | Purchaser token balance | Historical purchase document | +| **SetPriceForDirectPurchase** | Token pricing schedule | Historical pricing document | +| **DestroyFrozenFunds** | Always historical document | — | +| **EmergencyAction** | Always historical document | — | +| **ConfigUpdate** | Always historical document | — | +| **Claim** | Always historical document | — | + +**Group actions** add an extra layer: when a token transition uses group consensus +(multi-sig), the proof also includes the group action's signer and total power, plus the +action status (active vs closed). The verified result becomes one of the +`VerifiedTokenGroupAction*` variants. + +### Masternode Vote + +| Transition | What's Proved | Verified Result | +|---|---|---| +| **MasternodeVote** | The vote poll state for the specific vote | `VerifiedMasternodeVote(Vote)` | + +Uses `IdentityBasedVoteDriveQuery` to construct the path query from the voter's ProTxHash +and the resource vote poll. Verification checks the vote exists and matches expectations. + +### Shielded Transitions + +| Transition | Proof Generation | Proof Verification | +|---|---|---| +| **Shield** | Not yet supported | Verifies input address balances (`VerifiedAddressInfos`) | +| **Unshield** | Not yet supported | Verifies output address balance (`VerifiedAddressInfos`) | +| **ShieldedTransfer** | Not yet supported | Verifies shielded pool total balance (`VerifiedShieldedPoolState`) | +| **ShieldFromAssetLock** | Not yet supported | Verifies shielded pool total balance (`VerifiedShieldedPoolState`) | +| **ShieldedWithdrawal** | Not yet supported | Verifies shielded pool total balance (`VerifiedShieldedPoolState`) | + +Proof generation currently returns an error for all shielded transitions. The verification +side has been implemented in anticipation: + +- **Shield** verifies the input platform address balances were debited. +- **Unshield** verifies the output platform address balance was credited. +- **ShieldedTransfer, ShieldFromAssetLock, ShieldedWithdrawal** verify the shielded credit + pool's `total_balance` SumItem, confirming the pool balance changed as expected. + +Note that shielded proofs intentionally do **not** reveal which notes were created or spent +(that would break privacy). Only aggregate pool state or transparent address balances are +provable. + +## Code Locations + +| Component | Path | +|---|---| +| Proof generation | `rs-drive/src/prove/prove_state_transition/v0/mod.rs` | +| Proof verification | `rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs` | +| Proof result enum | `rs-dpp/src/state_transition/proof_result.rs` | +| DAPI wait service | `rs-dapi/src/services/platform_service/wait_for_state_transition_result.rs` | +| ABCI query handler | `rs-drive-abci/src/query/proofs/v0/mod.rs` | +| Shielded pool verify | `rs-drive/src/verify/shielded/verify_shielded_pool_state/v0/mod.rs` | +| Address balance verify | `rs-drive/src/verify/address_funds/verify_addresses_infos/v0/mod.rs` | diff --git a/packages/rs-dpp/src/asset_lock/mod.rs b/packages/rs-dpp/src/asset_lock/mod.rs index 5133348df5b..3844bfc5933 100644 --- a/packages/rs-dpp/src/asset_lock/mod.rs +++ b/packages/rs-dpp/src/asset_lock/mod.rs @@ -6,6 +6,7 @@ pub type PastAssetLockStateTransitionHashes = Vec>; /// An enumeration of the possible states when querying platform to get the stored state of an outpoint /// representing if the asset lock was already used or not. +#[derive(Debug)] pub enum StoredAssetLockInfo { /// The asset lock was fully consumed in the past FullyConsumed, diff --git a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs index 856f93a9c95..be18afa8680 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/basic_error.rs @@ -78,10 +78,10 @@ use crate::consensus::basic::state_transition::{ InvalidRemainderOutputCountError, InvalidStateTransitionTypeError, MissingStateTransitionTypeError, OutputAddressAlsoInputError, OutputBelowMinimumError, OutputsNotGreaterThanInputsError, ShieldedEmptyProofError, ShieldedInvalidValueBalanceError, - ShieldedNoActionsError, ShieldedZeroAnchorError, StateTransitionMaxSizeExceededError, - StateTransitionNotActiveError, TransitionNoInputsError, TransitionNoOutputsError, - TransitionOverMaxInputsError, TransitionOverMaxOutputsError, UnshieldAmountZeroError, - UnshieldValueBalanceBelowAmountError, WithdrawalBalanceMismatchError, + ShieldedNoActionsError, ShieldedTooManyActionsError, ShieldedZeroAnchorError, + StateTransitionMaxSizeExceededError, StateTransitionNotActiveError, TransitionNoInputsError, + TransitionNoOutputsError, TransitionOverMaxInputsError, TransitionOverMaxOutputsError, + UnshieldAmountZeroError, UnshieldValueBalanceBelowAmountError, WithdrawalBalanceMismatchError, WithdrawalBelowMinAmountError, }; use crate::consensus::basic::{ @@ -663,6 +663,9 @@ pub enum BasicError { #[error(transparent)] ShieldedNoActionsError(ShieldedNoActionsError), + #[error(transparent)] + ShieldedTooManyActionsError(ShieldedTooManyActionsError), + #[error(transparent)] ShieldedEmptyProofError(ShieldedEmptyProofError), diff --git a/packages/rs-dpp/src/errors/consensus/basic/state_transition/mod.rs b/packages/rs-dpp/src/errors/consensus/basic/state_transition/mod.rs index 06d06f3a777..a5721bcdd4a 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/state_transition/mod.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/state_transition/mod.rs @@ -16,6 +16,7 @@ mod outputs_not_greater_than_inputs_error; mod shielded_empty_proof_error; mod shielded_invalid_value_balance_error; mod shielded_no_actions_error; +mod shielded_too_many_actions_error; mod shielded_zero_anchor_error; mod state_transition_max_size_exceeded_error; mod state_transition_not_active_error; @@ -46,6 +47,7 @@ pub use outputs_not_greater_than_inputs_error::*; pub use shielded_empty_proof_error::*; pub use shielded_invalid_value_balance_error::*; pub use shielded_no_actions_error::*; +pub use shielded_too_many_actions_error::*; pub use shielded_zero_anchor_error::*; pub use state_transition_max_size_exceeded_error::*; pub use state_transition_not_active_error::*; diff --git a/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_too_many_actions_error.rs b/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_too_many_actions_error.rs new file mode 100644 index 00000000000..7b7218a79fd --- /dev/null +++ b/packages/rs-dpp/src/errors/consensus/basic/state_transition/shielded_too_many_actions_error.rs @@ -0,0 +1,46 @@ +use crate::consensus::basic::BasicError; +use crate::consensus::ConsensusError; +use crate::errors::ProtocolError; +use bincode::{Decode, Encode}; +use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize}; +use thiserror::Error; + +#[derive( + Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize, +)] +#[error( + "Shielded transition has {actual_actions} actions, which exceeds the maximum allowed {max_actions}" +)] +#[platform_serialize(unversioned)] +pub struct ShieldedTooManyActionsError { + /* + + DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION + + */ + actual_actions: u16, + max_actions: u16, +} + +impl ShieldedTooManyActionsError { + pub fn new(actual_actions: u16, max_actions: u16) -> Self { + Self { + actual_actions, + max_actions, + } + } + + pub fn actual_actions(&self) -> u16 { + self.actual_actions + } + + pub fn max_actions(&self) -> u16 { + self.max_actions + } +} + +impl From for ConsensusError { + fn from(err: ShieldedTooManyActionsError) -> Self { + Self::BasicError(BasicError::ShieldedTooManyActionsError(err)) + } +} diff --git a/packages/rs-dpp/src/errors/consensus/codes.rs b/packages/rs-dpp/src/errors/consensus/codes.rs index ca5c8800b77..dff4f34aaa0 100644 --- a/packages/rs-dpp/src/errors/consensus/codes.rs +++ b/packages/rs-dpp/src/errors/consensus/codes.rs @@ -232,13 +232,14 @@ impl ErrorWithCode for BasicError { Self::OutputAddressAlsoInputError(_) => 10816, Self::InvalidRemainderOutputCountError(_) => 10817, Self::WithdrawalBelowMinAmountError(_) => 10818, - // Shielded transition errors (10819-10824) + // Shielded transition errors (10819-10825) Self::ShieldedNoActionsError(_) => 10819, Self::ShieldedEmptyProofError(_) => 10820, Self::ShieldedZeroAnchorError(_) => 10821, Self::ShieldedInvalidValueBalanceError(_) => 10822, Self::UnshieldAmountZeroError(_) => 10823, Self::UnshieldValueBalanceBelowAmountError(_) => 10824, + Self::ShieldedTooManyActionsError(_) => 10825, } } } diff --git a/packages/rs-dpp/src/state_transition/proof_result.rs b/packages/rs-dpp/src/state_transition/proof_result.rs index d84d7802493..d36e14e0380 100644 --- a/packages/rs-dpp/src/state_transition/proof_result.rs +++ b/packages/rs-dpp/src/state_transition/proof_result.rs @@ -1,4 +1,5 @@ use crate::address_funds::PlatformAddress; +use crate::asset_lock::StoredAssetLockInfo; use crate::balances::credits::TokenAmount; use crate::data_contract::group::GroupSumPower; use crate::data_contract::DataContract; @@ -55,5 +56,15 @@ pub enum StateTransitionProofResult { PartialIdentity, BTreeMap>, ), - VerifiedShieldedPoolState(Option), + #[cfg_attr(feature = "state-transition-serde-conversion", serde(skip))] + VerifiedAssetLockConsumed(StoredAssetLockInfo), + VerifiedShieldedNullifiers(Vec<(Vec, bool)>), + VerifiedShieldedNullifiersWithAddressInfos( + Vec<(Vec, bool)>, + BTreeMap>, + ), + VerifiedShieldedNullifiersWithWithdrawalDocument( + Vec<(Vec, bool)>, + BTreeMap>, + ), } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/common_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/common_validation.rs index b2ea5e97f24..c18f5084c89 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/common_validation.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/common_validation.rs @@ -1,18 +1,28 @@ use crate::consensus::basic::state_transition::{ - ShieldedEmptyProofError, ShieldedNoActionsError, ShieldedZeroAnchorError, + ShieldedEmptyProofError, ShieldedNoActionsError, ShieldedTooManyActionsError, + ShieldedZeroAnchorError, }; use crate::consensus::basic::BasicError; use crate::shielded::SerializedAction; use crate::validation::SimpleConsensusValidationResult; -/// Validate that the actions list is not empty. -pub fn validate_actions_not_empty( +/// Validate that the actions list is not empty and does not exceed the maximum. +pub fn validate_actions_count( actions: &[SerializedAction], + max_actions: u16, ) -> Option { if actions.is_empty() { Some(SimpleConsensusValidationResult::new_with_error( BasicError::ShieldedNoActionsError(ShieldedNoActionsError::new()).into(), )) + } else if actions.len() > max_actions as usize { + Some(SimpleConsensusValidationResult::new_with_error( + BasicError::ShieldedTooManyActionsError(ShieldedTooManyActionsError::new( + actions.len().min(u16::MAX as usize) as u16, + max_actions, + )) + .into(), + )) } else { None } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_validation.rs index 407918caac5..cd9c691f79b 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_validation.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_from_asset_lock_transition/v0/state_transition_validation.rs @@ -2,7 +2,7 @@ use crate::consensus::basic::state_transition::ShieldedInvalidValueBalanceError; use crate::consensus::basic::BasicError; use crate::state_transition::shield_from_asset_lock_transition::v0::ShieldFromAssetLockTransitionV0; use crate::state_transition::state_transitions::shielded::common_validation::{ - validate_actions_not_empty, validate_anchor_not_zero, validate_proof_not_empty, + validate_actions_count, validate_anchor_not_zero, validate_proof_not_empty, }; use crate::state_transition::StateTransitionStructureValidation; use crate::validation::SimpleConsensusValidationResult; @@ -11,10 +11,15 @@ use platform_version::version::PlatformVersion; impl StateTransitionStructureValidation for ShieldFromAssetLockTransitionV0 { fn validate_structure( &self, - _platform_version: &PlatformVersion, + platform_version: &PlatformVersion, ) -> SimpleConsensusValidationResult { - // Actions must not be empty - if let Some(err) = validate_actions_not_empty(&self.actions) { + // Actions count must be in [1, max] + if let Some(err) = validate_actions_count( + &self.actions, + platform_version + .system_limits + .max_shielded_transition_actions, + ) { return err; } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs index a423e874cf1..0aaf4f058b7 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shield_transition/v0/state_transition_validation.rs @@ -6,7 +6,7 @@ use crate::consensus::basic::state_transition::{ use crate::consensus::basic::BasicError; use crate::state_transition::shield_transition::v0::ShieldTransitionV0; use crate::state_transition::state_transitions::shielded::common_validation::{ - validate_actions_not_empty, validate_anchor_not_zero, validate_proof_not_empty, + validate_actions_count, validate_anchor_not_zero, validate_proof_not_empty, }; use crate::state_transition::StateTransitionStructureValidation; use crate::validation::SimpleConsensusValidationResult; @@ -18,8 +18,13 @@ impl StateTransitionStructureValidation for ShieldTransitionV0 { &self, platform_version: &PlatformVersion, ) -> SimpleConsensusValidationResult { - // Actions must not be empty - if let Some(err) = validate_actions_not_empty(&self.actions) { + // Actions count must be in [1, max] + if let Some(err) = validate_actions_count( + &self.actions, + platform_version + .system_limits + .max_shielded_transition_actions, + ) { return err; } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/accessors/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/accessors/mod.rs new file mode 100644 index 00000000000..e12d9f4e66f --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/accessors/mod.rs @@ -0,0 +1,14 @@ +mod v0; + +pub use v0::*; + +use crate::shielded::SerializedAction; +use crate::state_transition::shielded_transfer_transition::ShieldedTransferTransition; + +impl ShieldedTransferTransitionAccessorsV0 for ShieldedTransferTransition { + fn actions(&self) -> &[SerializedAction] { + match self { + ShieldedTransferTransition::V0(v0) => &v0.actions, + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/accessors/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/accessors/v0/mod.rs new file mode 100644 index 00000000000..869c6167d28 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/accessors/v0/mod.rs @@ -0,0 +1,15 @@ +use crate::shielded::SerializedAction; + +pub trait ShieldedTransferTransitionAccessorsV0 { + /// Get the serialized Orchard actions + fn actions(&self) -> &[SerializedAction]; + + /// Extract nullifier bytes from each action. + /// Generic over the element type: use `Vec` or `[u8; 32]` as needed. + fn nullifiers>(&self) -> Vec { + self.actions() + .iter() + .map(|a| T::from(a.nullifier)) + .collect() + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/mod.rs index 9d22a44bab8..e9a183f249a 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/mod.rs @@ -1,3 +1,4 @@ +pub mod accessors; pub mod methods; mod state_transition_estimated_fee_validation; mod state_transition_like; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs index 97f05189a73..39960ef3815 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_transfer_transition/v0/state_transition_validation.rs @@ -2,7 +2,7 @@ use crate::consensus::basic::state_transition::ShieldedInvalidValueBalanceError; use crate::consensus::basic::BasicError; use crate::state_transition::shielded_transfer_transition::v0::ShieldedTransferTransitionV0; use crate::state_transition::state_transitions::shielded::common_validation::{ - validate_actions_not_empty, validate_anchor_not_zero, validate_proof_not_empty, + validate_actions_count, validate_anchor_not_zero, validate_proof_not_empty, }; use crate::state_transition::StateTransitionStructureValidation; use crate::validation::SimpleConsensusValidationResult; @@ -11,10 +11,15 @@ use platform_version::version::PlatformVersion; impl StateTransitionStructureValidation for ShieldedTransferTransitionV0 { fn validate_structure( &self, - _platform_version: &PlatformVersion, + platform_version: &PlatformVersion, ) -> SimpleConsensusValidationResult { - // Actions must not be empty - if let Some(err) = validate_actions_not_empty(&self.actions) { + // Actions count must be in [1, max] + if let Some(err) = validate_actions_count( + &self.actions, + platform_version + .system_limits + .max_shielded_transition_actions, + ) { return err; } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/accessors/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/accessors/mod.rs new file mode 100644 index 00000000000..d2bdd82cf71 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/accessors/mod.rs @@ -0,0 +1,21 @@ +mod v0; + +pub use v0::*; + +use crate::identity::core_script::CoreScript; +use crate::shielded::SerializedAction; +use crate::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; + +impl ShieldedWithdrawalTransitionAccessorsV0 for ShieldedWithdrawalTransition { + fn actions(&self) -> &[SerializedAction] { + match self { + ShieldedWithdrawalTransition::V0(v0) => &v0.actions, + } + } + + fn output_script(&self) -> &CoreScript { + match self { + ShieldedWithdrawalTransition::V0(v0) => &v0.output_script, + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/accessors/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/accessors/v0/mod.rs new file mode 100644 index 00000000000..c6fd48b4a1f --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/accessors/v0/mod.rs @@ -0,0 +1,19 @@ +use crate::identity::core_script::CoreScript; +use crate::shielded::SerializedAction; + +pub trait ShieldedWithdrawalTransitionAccessorsV0 { + /// Get the serialized Orchard actions + fn actions(&self) -> &[SerializedAction]; + + /// Get the output script receiving withdrawn funds + fn output_script(&self) -> &CoreScript; + + /// Extract nullifier bytes from each action. + /// Generic over the element type: use `Vec` or `[u8; 32]` as needed. + fn nullifiers>(&self) -> Vec { + self.actions() + .iter() + .map(|a| T::from(a.nullifier)) + .collect() + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/mod.rs index f4f56847ee4..9c1209411d6 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/mod.rs @@ -1,3 +1,4 @@ +pub mod accessors; pub mod methods; mod state_transition_estimated_fee_validation; mod state_transition_like; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_validation.rs index db89ea551c4..1b2f68f7afc 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_validation.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/shielded_withdrawal_transition/v0/state_transition_validation.rs @@ -4,7 +4,7 @@ use crate::consensus::basic::state_transition::{ use crate::consensus::basic::BasicError; use crate::state_transition::shielded_withdrawal_transition::v0::ShieldedWithdrawalTransitionV0; use crate::state_transition::state_transitions::shielded::common_validation::{ - validate_actions_not_empty, validate_anchor_not_zero, validate_proof_not_empty, + validate_actions_count, validate_anchor_not_zero, validate_proof_not_empty, }; use crate::state_transition::StateTransitionStructureValidation; use crate::validation::SimpleConsensusValidationResult; @@ -13,10 +13,15 @@ use platform_version::version::PlatformVersion; impl StateTransitionStructureValidation for ShieldedWithdrawalTransitionV0 { fn validate_structure( &self, - _platform_version: &PlatformVersion, + platform_version: &PlatformVersion, ) -> SimpleConsensusValidationResult { - // Actions must not be empty - if let Some(err) = validate_actions_not_empty(&self.actions) { + // Actions count must be in [1, max] + if let Some(err) = validate_actions_count( + &self.actions, + platform_version + .system_limits + .max_shielded_transition_actions, + ) { return err; } diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/accessors/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/accessors/mod.rs new file mode 100644 index 00000000000..2c0619d2159 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/accessors/mod.rs @@ -0,0 +1,21 @@ +mod v0; + +pub use v0::*; + +use crate::address_funds::PlatformAddress; +use crate::shielded::SerializedAction; +use crate::state_transition::unshield_transition::UnshieldTransition; + +impl UnshieldTransitionAccessorsV0 for UnshieldTransition { + fn actions(&self) -> &[SerializedAction] { + match self { + UnshieldTransition::V0(v0) => &v0.actions, + } + } + + fn output_address(&self) -> &PlatformAddress { + match self { + UnshieldTransition::V0(v0) => &v0.output_address, + } + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/accessors/v0/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/accessors/v0/mod.rs new file mode 100644 index 00000000000..583448b4568 --- /dev/null +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/accessors/v0/mod.rs @@ -0,0 +1,19 @@ +use crate::address_funds::PlatformAddress; +use crate::shielded::SerializedAction; + +pub trait UnshieldTransitionAccessorsV0 { + /// Get the serialized Orchard actions + fn actions(&self) -> &[SerializedAction]; + + /// Get the output address receiving unshielded funds + fn output_address(&self) -> &PlatformAddress; + + /// Extract nullifier bytes from each action. + /// Generic over the element type: use `Vec` or `[u8; 32]` as needed. + fn nullifiers>(&self) -> Vec { + self.actions() + .iter() + .map(|a| T::from(a.nullifier)) + .collect() + } +} diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/mod.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/mod.rs index 8fe541491b3..410405bb159 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/mod.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/mod.rs @@ -1,3 +1,4 @@ +pub mod accessors; pub mod methods; mod state_transition_estimated_fee_validation; mod state_transition_like; diff --git a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs index 71e41aa71f5..f59ccccc948 100644 --- a/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs +++ b/packages/rs-dpp/src/state_transition/state_transitions/shielded/unshield_transition/v0/state_transition_validation.rs @@ -3,7 +3,7 @@ use crate::consensus::basic::state_transition::{ }; use crate::consensus::basic::BasicError; use crate::state_transition::state_transitions::shielded::common_validation::{ - validate_actions_not_empty, validate_anchor_not_zero, validate_proof_not_empty, + validate_actions_count, validate_anchor_not_zero, validate_proof_not_empty, }; use crate::state_transition::unshield_transition::v0::UnshieldTransitionV0; use crate::state_transition::StateTransitionStructureValidation; @@ -13,10 +13,15 @@ use platform_version::version::PlatformVersion; impl StateTransitionStructureValidation for UnshieldTransitionV0 { fn validate_structure( &self, - _platform_version: &PlatformVersion, + platform_version: &PlatformVersion, ) -> SimpleConsensusValidationResult { - // Actions must not be empty - if let Some(err) = validate_actions_not_empty(&self.actions) { + // Actions count must be in [1, max] + if let Some(err) = validate_actions_count( + &self.actions, + platform_version + .system_limits + .max_shielded_transition_actions, + ) { return err; } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs index fee944e2aa2..63e36a87b50 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/tests.rs @@ -1058,4 +1058,238 @@ mod tests { ); } } + + // ========================================== + // RETURN PROOF TESTS (prove + verify round-trip) + // ========================================== + + mod return_proof { + use super::*; + use dpp::block::block_info::BlockInfo; + use dpp::serialization::PlatformSerializable; + use dpp::state_transition::proof_result::StateTransitionProofResult; + use drive::drive::Drive; + use grovedb_commitment_tree::{ + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, DashMemo, + Flags as OrchardFlags, FullViewingKey, NoteValue, ProvingKey, Scope, SpendingKey, + }; + use rand::rngs::OsRng; + use std::sync::OnceLock; + + static TEST_PROVING_KEY: OnceLock = OnceLock::new(); + fn get_proving_key() -> &'static ProvingKey { + TEST_PROVING_KEY.get_or_init(ProvingKey::build) + } + + /// Extract serialized fields from an authorized Orchard bundle into the + /// platform-compatible format: (actions, flags, value_balance, anchor, proof, binding_sig). + /// Returns `i64` for value_balance (shield bundles have negative value_balance). + fn serialize_authorized_bundle( + bundle: &Bundle, + ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { + let actions: Vec = bundle + .actions() + .iter() + .map(|action| { + let enc = action.encrypted_note(); + let mut encrypted_note = Vec::with_capacity(216); + encrypted_note.extend_from_slice(&enc.epk_bytes); + encrypted_note.extend_from_slice(enc.enc_ciphertext.as_ref()); + encrypted_note.extend_from_slice(&enc.out_ciphertext); + + SerializedAction { + nullifier: action.nullifier().to_bytes(), + rk: <[u8; 32]>::from(action.rk()), + cmx: action.cmx().to_bytes(), + encrypted_note, + cv_net: action.cv_net().to_bytes(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()), + } + }) + .collect(); + + let flags = bundle.flags().to_byte(); + let value_balance = *bundle.value_balance(); + let anchor = bundle.anchor().to_bytes(); + let proof = bundle.authorization().proof().as_ref().to_vec(); + let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); + + (actions, flags, value_balance, anchor, proof, binding_sig) + } + + #[test] + fn test_shield_prove_and_verify_address_balances() { + let platform_version = PlatformVersion::latest(); + let mut platform = setup_platform(); + let mut rng = OsRng; + let pk = get_proving_key(); + + // --- Create keys --- + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + + // --- Build valid Orchard bundle (shield = outputs only, no spends) --- + let anchor = Anchor::empty_tree(); + let mut builder = Builder::::new( + BundleType::Transactional { + flags: OrchardFlags::SPENDS_DISABLED, + bundle_required: false, + }, + anchor, + ); + + let shield_value = 5_000u64; + builder + .add_output( + None, + recipient, + NoteValue::from_raw(shield_value), + [0u8; 36], + ) + .unwrap(); + + let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + // Shield sighash extra_data is empty (no transparent output fields) + let sighash = compute_platform_sighash(&bundle_commitment, &[]); + let proven = unauthorized.create_proof(pk, &mut rng).unwrap(); + let bundle = proven.apply_signatures(rng, sighash, &[]).unwrap(); + + // --- Extract serialized fields from the authorized bundle --- + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + + // value_balance should be negative for shield (money going into pool) + assert!(value_balance < 0); + let shield_amount = (-value_balance) as u64; + + // --- Set up input address with enough balance --- + let mut signer = TestAddressSigner::new(); + let input_address = signer.add_p2pkh([1u8; 32]); + let input_amount = shield_amount + dash_to_credits!(0.01); + setup_address_with_balance(&mut platform, input_address, 0, dash_to_credits!(1.0)); + + // --- Build and sign the shield transition --- + let mut inputs = BTreeMap::new(); + inputs.insert(input_address, (1 as AddressNonce, input_amount)); + + let mut st = StateTransition::Shield(ShieldTransition::V0(ShieldTransitionV0 { + inputs: inputs.clone(), + actions, + flags, + value_balance, + anchor: anchor_bytes, + proof: proof_bytes, + binding_signature: binding_sig, + fee_strategy: AddressFundsFeeStrategy::from(vec![ + AddressFundsFeeStrategyStep::DeductFromInput(0), + ]), + user_fee_increase: 0, + input_witnesses: vec![], + })); + + let signable_bytes = st.signable_bytes().expect("should compute signable bytes"); + let witnesses: Vec = inputs + .keys() + .map(|address| { + signer + .sign_create_witness(address, &signable_bytes) + .expect("should sign") + }) + .collect(); + + if let StateTransition::Shield(ShieldTransition::V0(ref mut v0)) = st { + v0.input_witnesses = witnesses; + } + + // --- Serialize and process with manual transaction so we can commit before proving --- + let transition_bytes = st + .serialize_to_bytes() + .expect("should serialize transition"); + + let platform_state = platform.state.load(); + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![transition_bytes], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution { .. }] + ); + + // Commit the transaction so prove_state_transition can read committed state + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + // --- Generate proof --- + let proof_result = platform + .drive + .prove_state_transition(&st, None, platform_version) + .expect("expected to generate proof for shield"); + + let proof_bytes = proof_result + .into_data() + .expect("expected proof data, not an error"); + + // --- Verify proof --- + let (root_hash, proof_result) = Drive::verify_state_transition_was_executed_with_proof( + &st, + &BlockInfo::default(), + &proof_bytes, + &|_| Ok(None), + platform_version, + ) + .expect("expected to verify shield proof"); + + assert_ne!(root_hash, [0u8; 32], "root hash should not be zeroed"); + + // --- Assert result is VerifiedAddressInfos containing the input address --- + let StateTransitionProofResult::VerifiedAddressInfos(address_infos) = proof_result + else { + panic!("expected VerifiedAddressInfos, got {:?}", proof_result); + }; + + assert!( + address_infos.contains_key(&input_address), + "proof result should contain the input address" + ); + + // The address should have a balance entry (Some) after the shield + let address_info = address_infos + .get(&input_address) + .expect("input address should be in result"); + + assert!( + address_info.is_some(), + "input address should have balance info after shield" + ); + + let (nonce_after, balance_after) = address_info.unwrap(); + + // Nonce should have been incremented + assert_eq!(nonce_after, 1, "nonce should be 1 after first shield"); + + // Balance should be less than original (shield_amount + fees were deducted) + assert!( + balance_after < dash_to_credits!(1.0), + "balance should be less than original after shield" + ); + } + } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs index 4b8d522fe00..f9070d21980 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/tests.rs @@ -733,4 +733,190 @@ mod tests { ); } } + + // ========================================== + // RETURN PROOF TESTS + // ========================================== + + mod return_proof { + use super::*; + use dpp::asset_lock::StoredAssetLockInfo; + use dpp::block::block_info::BlockInfo; + use dpp::serialization::PlatformSerializable; + use dpp::state_transition::proof_result::StateTransitionProofResult; + use drive::drive::Drive; + use grovedb_commitment_tree::{ + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, DashMemo, + Flags as OrchardFlags, FullViewingKey, NoteValue, ProvingKey, Scope, SpendingKey, + }; + use rand::rngs::OsRng; + use std::sync::OnceLock; + + static TEST_PROVING_KEY: OnceLock = OnceLock::new(); + fn get_proving_key() -> &'static ProvingKey { + TEST_PROVING_KEY.get_or_init(ProvingKey::build) + } + + fn serialize_authorized_bundle( + bundle: &Bundle, + ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { + let actions: Vec = bundle + .actions() + .iter() + .map(|action| { + let enc = action.encrypted_note(); + let mut encrypted_note = Vec::with_capacity(216); + encrypted_note.extend_from_slice(&enc.epk_bytes); + encrypted_note.extend_from_slice(enc.enc_ciphertext.as_ref()); + encrypted_note.extend_from_slice(&enc.out_ciphertext); + + SerializedAction { + nullifier: action.nullifier().to_bytes(), + rk: <[u8; 32]>::from(action.rk()), + cmx: action.cmx().to_bytes(), + encrypted_note, + cv_net: action.cv_net().to_bytes(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()), + } + }) + .collect(); + + let flags = bundle.flags().to_byte(); + let value_balance = *bundle.value_balance(); + let anchor = bundle.anchor().to_bytes(); + let proof = bundle.authorization().proof().as_ref().to_vec(); + let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); + + (actions, flags, value_balance, anchor, proof, binding_sig) + } + + #[test] + fn test_shield_from_asset_lock_prove_and_verify() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + + let mut rng = StdRng::seed_from_u64(567); + let (asset_lock_proof, asset_lock_pk) = create_asset_lock_proof_with_key(&mut rng); + + // --- Build a valid Orchard bundle (shield = outputs only) --- + let mut orchard_rng = OsRng; + let pk = get_proving_key(); + + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + + let anchor = Anchor::empty_tree(); + let mut builder = Builder::::new( + BundleType::Transactional { + flags: OrchardFlags::SPENDS_DISABLED, + bundle_required: false, + }, + anchor, + ); + + let shield_value = 5_000u64; + builder + .add_output( + None, + recipient, + NoteValue::from_raw(shield_value), + [0u8; 36], + ) + .unwrap(); + + let (unauthorized, _) = builder.build::(&mut orchard_rng).unwrap().unwrap(); + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &[]); + let proven = unauthorized.create_proof(pk, &mut orchard_rng).unwrap(); + let bundle = proven.apply_signatures(orchard_rng, sighash, &[]).unwrap(); + + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + + assert!(value_balance < 0); + + // --- Build and sign the transition --- + let transition = create_signed_shield_from_asset_lock_transition( + asset_lock_proof, + &asset_lock_pk, + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + 0, + ); + + // --- Serialize and process with manual transaction so we can commit before proving --- + let transition_bytes = transition + .serialize_to_bytes() + .expect("should serialize transition"); + + let platform_state = platform.state.load(); + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![transition_bytes], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution { .. }] + ); + + // Commit the transaction so prove_state_transition can read committed state + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + // --- Generate proof --- + let proof_result = platform + .drive + .prove_state_transition(&transition, None, platform_version) + .expect("expected to generate proof for shield_from_asset_lock"); + + let proof_bytes = proof_result + .into_data() + .expect("expected proof data, not an error"); + + // --- Verify proof --- + let (root_hash, proof_result) = Drive::verify_state_transition_was_executed_with_proof( + &transition, + &BlockInfo::default(), + &proof_bytes, + &|_| Ok(None), + platform_version, + ) + .expect("expected to verify shield_from_asset_lock proof"); + + assert_ne!(root_hash, [0u8; 32], "root hash should not be zeroed"); + + // --- Assert result is VerifiedAssetLockConsumed --- + let StateTransitionProofResult::VerifiedAssetLockConsumed(info) = proof_result else { + panic!("expected VerifiedAssetLockConsumed, got {:?}", proof_result); + }; + + // ShieldFromAssetLock always fully consumes the asset lock + // (remaining_credit_value is set to 0 in action-to-operations conversion). + assert!( + matches!(info, StoredAssetLockInfo::FullyConsumed), + "expected FullyConsumed, got {:?}", + info + ); + } + } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs index 340d2463226..130c5b51311 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/tests.rs @@ -999,4 +999,219 @@ mod tests { ); } } + + // ========================================== + // PROOF GENERATION & VERIFICATION TESTS + // ========================================== + + mod return_proof { + use super::*; + use dpp::block::block_info::BlockInfo; + use dpp::serialization::PlatformSerializable; + use dpp::state_transition::proof_result::StateTransitionProofResult; + use dpp::state_transition::shielded_transfer_transition::accessors::ShieldedTransferTransitionAccessorsV0; + use drive::drive::Drive; + use grovedb_commitment_tree::{ + Anchor, Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + ClientMemoryCommitmentTree, DashMemo, ExtractedNoteCommitment, FullViewingKey, Note, + NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, + SpendAuthorizingKey, SpendingKey, + }; + use rand::rngs::OsRng; + use std::sync::OnceLock; + + const MINIMUM_FEE_2_ACTIONS: u64 = 123_097_600; + + static TEST_PROVING_KEY: OnceLock = OnceLock::new(); + fn get_proving_key() -> &'static ProvingKey { + TEST_PROVING_KEY.get_or_init(ProvingKey::build) + } + + fn serialize_authorized_bundle( + bundle: &Bundle, + ) -> (Vec, u8, u64, [u8; 32], Vec, [u8; 64]) { + let actions: Vec = bundle + .actions() + .iter() + .map(|action| { + let enc = action.encrypted_note(); + let mut encrypted_note = Vec::with_capacity(216); + encrypted_note.extend_from_slice(&enc.epk_bytes); + encrypted_note.extend_from_slice(enc.enc_ciphertext.as_ref()); + encrypted_note.extend_from_slice(&enc.out_ciphertext); + SerializedAction { + nullifier: action.nullifier().to_bytes(), + rk: <[u8; 32]>::from(action.rk()), + cmx: action.cmx().to_bytes(), + encrypted_note, + cv_net: action.cv_net().to_bytes(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()), + } + }) + .collect(); + let flags = bundle.flags().to_byte(); + let value_balance = *bundle.value_balance() as u64; + let anchor = bundle.anchor().to_bytes(); + let proof = bundle.authorization().proof().as_ref().to_vec(); + let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); + (actions, flags, value_balance, anchor, proof, binding_sig) + } + + #[test] + fn test_shielded_transfer_prove_and_verify_nullifiers() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + let mut rng = OsRng; + let pk = get_proving_key(); + + let spend_amount = 200_000_000u64; + let output_amount = spend_amount - MINIMUM_FEE_2_ACTIONS; + + // --- Create keys --- + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + let ask = SpendAuthorizingKey::from(&sk); + + // --- Create a spendable note --- + let rho_bytes: [u8; 32] = { + let mut b = [0u8; 32]; + b[0] = 1; + b + }; + let rho = Rho::from_bytes(&rho_bytes).unwrap(); + let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); + let note = + Note::from_parts(recipient, NoteValue::from_raw(spend_amount), rho, rseed).unwrap(); + + // --- Build commitment tree and get anchor + merkle path --- + let cmx = ExtractedNoteCommitment::from(note.commitment()); + let mut tree = ClientMemoryCommitmentTree::new(100); + tree.append(cmx.to_bytes(), Retention::Marked).unwrap(); + tree.checkpoint(0u32).unwrap(); + let anchor = tree.anchor().unwrap(); + let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); + + // --- Build bundle --- + let mut builder = Builder::::new(BundleType::DEFAULT, anchor); + builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); + builder + .add_output( + None, + recipient, + NoteValue::from_raw(output_amount), + [0u8; 36], + ) + .unwrap(); + + let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &[]); + let proven = unauthorized.create_proof(pk, &mut rng).unwrap(); + let bundle = proven.apply_signatures(rng, sighash, &[ask]).unwrap(); + + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + + // --- Set up pool state --- + set_pool_total_balance(&platform, 500_000_000); + insert_anchor_into_state(&platform, &anchor_bytes); + + // --- Build and serialize the transition --- + let transition = create_shielded_transfer_transition( + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + ); + + let transition_bytes = transition + .serialize_to_bytes() + .expect("should serialize transition"); + + // --- Process with manual transaction so we can commit before proving --- + let platform_state = platform.state.load(); + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![transition_bytes], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution { .. }] + ); + + // Commit the transaction so prove_state_transition can read committed state + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + // --- Generate proof --- + let proof_result = platform + .drive + .prove_state_transition(&transition, None, platform_version) + .expect("expected to generate proof for shielded transfer"); + + let proof_bytes = proof_result + .into_data() + .expect("expected proof data, not an error"); + + // --- Verify proof --- + let (root_hash, proof_result) = Drive::verify_state_transition_was_executed_with_proof( + &transition, + &BlockInfo::default(), + &proof_bytes, + &|_| Ok(None), + platform_version, + ) + .expect("expected to verify shielded transfer proof"); + + assert_ne!(root_hash, [0u8; 32], "root hash should not be zeroed"); + + // --- Assert result is VerifiedShieldedNullifiers with all spent --- + let StateTransitionProofResult::VerifiedShieldedNullifiers(statuses) = proof_result + else { + panic!( + "expected VerifiedShieldedNullifiers, got {:?}", + proof_result + ); + }; + + // Extract expected nullifiers from the transition + let StateTransition::ShieldedTransfer(ref st) = transition else { + unreachable!(); + }; + let expected_nullifiers: Vec> = st.nullifiers(); + + assert_eq!( + statuses.len(), + expected_nullifiers.len(), + "should have one status per nullifier" + ); + + for (nf, is_spent) in &statuses { + assert!(is_spent, "nullifier {} should be spent", hex::encode(nf)); + assert!( + expected_nullifiers.contains(nf), + "proved nullifier {} should be one of the transition's nullifiers", + hex::encode(nf) + ); + } + } + } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs index 2a3591f7747..4fb7d0ecf55 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs @@ -973,4 +973,281 @@ mod tests { ); } } + + // ========================================== + // RETURN PROOF TESTS (prove + verify round-trip) + // ========================================== + + mod return_proof { + use super::*; + use dpp::block::block_info::BlockInfo; + use dpp::data_contracts::withdrawals_contract; + use dpp::data_contracts::withdrawals_contract::v1::document_types::withdrawal; + use dpp::document::Document; + use dpp::serialization::PlatformSerializable; + use dpp::state_transition::proof_result::StateTransitionProofResult; + use dpp::state_transition::shielded_withdrawal_transition::accessors::ShieldedWithdrawalTransitionAccessorsV0; + use dpp::system_data_contracts::{load_system_data_contract, SystemDataContract}; + use drive::drive::Drive; + use grovedb_commitment_tree::{ + Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + ClientMemoryCommitmentTree, DashMemo, ExtractedNoteCommitment, FullViewingKey, Note, + NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, + SpendAuthorizingKey, SpendingKey, + }; + use rand::rngs::OsRng; + use std::collections::BTreeMap; + use std::sync::{Arc, OnceLock}; + + static TEST_PROVING_KEY: OnceLock = OnceLock::new(); + fn get_proving_key() -> &'static ProvingKey { + TEST_PROVING_KEY.get_or_init(ProvingKey::build) + } + + fn serialize_authorized_bundle( + bundle: &Bundle, + ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { + let actions: Vec = bundle + .actions() + .iter() + .map(|action| { + let enc = action.encrypted_note(); + let mut encrypted_note = Vec::with_capacity(216); + encrypted_note.extend_from_slice(&enc.epk_bytes); + encrypted_note.extend_from_slice(enc.enc_ciphertext.as_ref()); + encrypted_note.extend_from_slice(&enc.out_ciphertext); + SerializedAction { + nullifier: action.nullifier().to_bytes(), + rk: <[u8; 32]>::from(action.rk()), + cmx: action.cmx().to_bytes(), + encrypted_note, + cv_net: action.cv_net().to_bytes(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()), + } + }) + .collect(); + let flags = bundle.flags().to_byte(); + let value_balance = *bundle.value_balance(); + let anchor = bundle.anchor().to_bytes(); + let proof = bundle.authorization().proof().as_ref().to_vec(); + let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); + (actions, flags, value_balance, anchor, proof, binding_sig) + } + + #[test] + fn test_shielded_withdrawal_prove_and_verify_nullifiers_and_document() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); + let mut rng = OsRng; + let pk = get_proving_key(); + + // --- Create keys --- + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + let ask = SpendAuthorizingKey::from(&sk); + + // --- Create a spendable note with value 10,000 --- + let rho_bytes: [u8; 32] = { + let mut b = [0u8; 32]; + b[0] = 1; + b + }; + let rho = Rho::from_bytes(&rho_bytes).unwrap(); + let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); + let note = + Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); + + // --- Build commitment tree and get anchor + merkle path --- + let cmx = ExtractedNoteCommitment::from(note.commitment()); + let mut tree = ClientMemoryCommitmentTree::new(100); + tree.append(cmx.to_bytes(), Retention::Marked).unwrap(); + tree.checkpoint(0u32).unwrap(); + let anchor = tree.anchor().unwrap(); + let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); + + // --- Build bundle: spend 10,000 -> output 5,000 (value_balance = 5,000) --- + let mut builder = Builder::::new(BundleType::DEFAULT, anchor); + builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); + builder + .add_output(None, recipient, NoteValue::from_raw(5_000), [0u8; 36]) + .unwrap(); + + let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); + + // Compute platform sighash binding transparent fields (output_script, amount) + let output_script = create_output_script(); + let amount = 5_000u64; // = value_balance (no fee difference) + let mut extra_sighash_data = output_script.as_bytes().to_vec(); + extra_sighash_data.extend_from_slice(&amount.to_le_bytes()); + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &extra_sighash_data); + + let proven = unauthorized.create_proof(pk, &mut rng).unwrap(); + let bundle = proven.apply_signatures(rng, sighash, &[ask]).unwrap(); + + // --- Extract serialized fields --- + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + + // value_balance should be 5000 (10,000 spent - 5,000 output) + assert_eq!(value_balance, 5_000); + + // --- Set up platform state --- + insert_anchor_into_state(&platform, &anchor_bytes); + set_pool_total_balance(&platform, 500_000); + + // --- Create and process transition --- + let transition = create_shielded_withdrawal_transition( + amount, + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + 1, // core_fee_per_byte + Pooling::Never, // pooling strategy + output_script.clone(), + ); + + let transition_bytes = transition + .serialize_to_bytes() + .expect("should serialize transition"); + + // --- Process with manual transaction so we can commit before proving --- + let platform_state = platform.state.load(); + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![transition_bytes], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution { .. }] + ); + + // Commit the transaction so prove_state_transition can read committed state + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + // --- Generate proof --- + let proof_result = platform + .drive + .prove_state_transition(&transition, None, platform_version) + .expect("expected to generate proof for shielded withdrawal"); + + let proof_bytes = proof_result + .into_data() + .expect("expected proof data, not an error"); + + // --- Verify proof --- + // ShieldedWithdrawal verification requires the withdrawals system data contract + // to look up the withdrawal document type. + let withdrawals_data_contract = + load_system_data_contract(SystemDataContract::Withdrawals, platform_version) + .expect("should load withdrawals contract"); + + let withdrawals_data_contract = Arc::new(withdrawals_data_contract); + + let (root_hash, proof_result) = Drive::verify_state_transition_was_executed_with_proof( + &transition, + &BlockInfo::default(), + &proof_bytes, + &|id| { + if *id == withdrawals_contract::ID { + Ok(Some(Arc::clone(&withdrawals_data_contract))) + } else { + Ok(None) + } + }, + platform_version, + ) + .expect("expected to verify shielded withdrawal proof"); + + assert_ne!(root_hash, [0u8; 32], "root hash should not be zeroed"); + + // --- Assert result is VerifiedShieldedNullifiersWithWithdrawalDocument --- + let StateTransitionProofResult::VerifiedShieldedNullifiersWithWithdrawalDocument( + statuses, + documents, + ) = proof_result + else { + panic!( + "expected VerifiedShieldedNullifiersWithWithdrawalDocument, got {:?}", + proof_result + ); + }; + + // Extract expected nullifiers from the transition + let StateTransition::ShieldedWithdrawal(ref st) = transition else { + unreachable!(); + }; + let expected_nullifiers: Vec> = st.nullifiers(); + + assert_eq!( + statuses.len(), + expected_nullifiers.len(), + "should have one status per nullifier" + ); + + // All nullifiers must be marked as spent + for (nf, is_spent) in &statuses { + assert!(is_spent, "nullifier {} should be spent", hex::encode(nf)); + assert!( + expected_nullifiers.contains(nf), + "proved nullifier {} should be one of the transition's nullifiers", + hex::encode(nf) + ); + } + + // Compute the expected withdrawal document ID (same logic as prove/verify sides) + let first_nullifier = expected_nullifiers + .first() + .expect("should have at least one nullifier"); + let mut entropy = Vec::new(); + entropy.extend_from_slice(first_nullifier); + entropy.extend_from_slice(output_script.as_bytes()); + let expected_document_id = Document::generate_document_id_v0( + &withdrawals_contract::ID, + &withdrawals_contract::OWNER_ID, + withdrawal::NAME, + &entropy, + ); + + // The documents map should contain exactly one entry with the expected document_id + assert_eq!( + documents.len(), + 1, + "should have exactly one withdrawal document entry" + ); + assert!( + documents.contains_key(&expected_document_id), + "documents map should contain the expected withdrawal document id {}", + expected_document_id + ); + + // The document should exist (Some) — it was created during processing + let maybe_doc = documents.get(&expected_document_id).unwrap(); + assert!( + maybe_doc.is_some(), + "withdrawal document should be present (not absent)" + ); + } + } } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs index a65d0ebbb49..30aba5d5d02 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs @@ -795,4 +795,241 @@ mod tests { ); } } + + // ========================================== + // PROOF GENERATION & VERIFICATION TESTS + // ========================================== + + mod return_proof { + use super::*; + use dpp::block::block_info::BlockInfo; + use dpp::serialization::PlatformSerializable; + use dpp::state_transition::proof_result::StateTransitionProofResult; + use dpp::state_transition::unshield_transition::accessors::UnshieldTransitionAccessorsV0; + use drive::drive::Drive; + use grovedb_commitment_tree::{ + Authorized as OrchardAuthorized, Builder, Bundle, BundleType, + ClientMemoryCommitmentTree, DashMemo, ExtractedNoteCommitment, FullViewingKey, Note, + NoteValue, Position, ProvingKey, RandomSeed, Retention, Rho, Scope, + SpendAuthorizingKey, SpendingKey, + }; + use rand::rngs::OsRng; + use std::sync::OnceLock; + + static TEST_PROVING_KEY: OnceLock = OnceLock::new(); + fn get_proving_key() -> &'static ProvingKey { + TEST_PROVING_KEY.get_or_init(ProvingKey::build) + } + + fn serialize_authorized_bundle( + bundle: &Bundle, + ) -> (Vec, u8, i64, [u8; 32], Vec, [u8; 64]) { + let actions: Vec = bundle + .actions() + .iter() + .map(|action| { + let enc = action.encrypted_note(); + let mut encrypted_note = Vec::with_capacity(216); + encrypted_note.extend_from_slice(&enc.epk_bytes); + encrypted_note.extend_from_slice(enc.enc_ciphertext.as_ref()); + encrypted_note.extend_from_slice(&enc.out_ciphertext); + SerializedAction { + nullifier: action.nullifier().to_bytes(), + rk: <[u8; 32]>::from(action.rk()), + cmx: action.cmx().to_bytes(), + encrypted_note, + cv_net: action.cv_net().to_bytes(), + spend_auth_sig: <[u8; 64]>::from(action.authorization()), + } + }) + .collect(); + let flags = bundle.flags().to_byte(); + let value_balance = *bundle.value_balance(); + let anchor = bundle.anchor().to_bytes(); + let proof = bundle.authorization().proof().as_ref().to_vec(); + let binding_sig = <[u8; 64]>::from(bundle.authorization().binding_signature()); + (actions, flags, value_balance, anchor, proof, binding_sig) + } + + #[test] + fn test_unshield_prove_and_verify_nullifiers_and_address() { + let platform_version = PlatformVersion::latest(); + let platform = setup_platform(); + insert_dummy_encrypted_notes(&platform, 250); + let mut rng = OsRng; + let pk = get_proving_key(); + + let spend_amount = 10_000u64; + let output_amount = 5_000u64; + + // --- Create keys --- + let sk = SpendingKey::from_bytes([0u8; 32]).unwrap(); + let fvk = FullViewingKey::from(&sk); + let recipient = fvk.address_at(0u32, Scope::External); + let ask = SpendAuthorizingKey::from(&sk); + + // --- Create a spendable note --- + let rho_bytes: [u8; 32] = { + let mut b = [0u8; 32]; + b[0] = 1; + b + }; + let rho = Rho::from_bytes(&rho_bytes).unwrap(); + let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); + let note = + Note::from_parts(recipient, NoteValue::from_raw(spend_amount), rho, rseed).unwrap(); + + // --- Build commitment tree and get anchor + merkle path --- + let cmx = ExtractedNoteCommitment::from(note.commitment()); + let mut tree = ClientMemoryCommitmentTree::new(100); + tree.append(cmx.to_bytes(), Retention::Marked).unwrap(); + tree.checkpoint(0u32).unwrap(); + let anchor = tree.anchor().unwrap(); + let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); + + // --- Build bundle: spend 10,000 -> output 5,000 (value_balance = 5,000) --- + let mut builder = Builder::::new(BundleType::DEFAULT, anchor); + builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); + builder + .add_output( + None, + recipient, + NoteValue::from_raw(output_amount), + [0u8; 36], + ) + .unwrap(); + + let (unauthorized, _) = builder.build::(&mut rng).unwrap().unwrap(); + + // Compute platform sighash binding transparent fields (output_address, amount) + let output_address = create_output_address(); + let amount = 5_000u64; // = value_balance (no fee difference) + let mut extra_sighash_data = output_address.to_bytes(); + extra_sighash_data.extend_from_slice(&amount.to_le_bytes()); + let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); + let sighash = compute_platform_sighash(&bundle_commitment, &extra_sighash_data); + + let proven = unauthorized.create_proof(pk, &mut rng).unwrap(); + let bundle = proven.apply_signatures(rng, sighash, &[ask]).unwrap(); + + // --- Extract serialized fields --- + let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = + serialize_authorized_bundle(&bundle); + + // value_balance should be 5000 (10,000 spent - 5,000 output) + assert_eq!(value_balance, 5_000); + + // --- Set up platform state --- + insert_anchor_into_state(&platform, &anchor_bytes); + set_pool_total_balance(&platform, 500_000); + + // --- Build and serialize the transition --- + let transition = create_unshield_transition( + output_address.clone(), + amount, + actions, + flags, + value_balance, + anchor_bytes, + proof_bytes, + binding_sig, + ); + + let transition_bytes = transition + .serialize_to_bytes() + .expect("should serialize transition"); + + // --- Process with manual transaction so we can commit before proving --- + let platform_state = platform.state.load(); + let transaction = platform.drive.grove.start_transaction(); + + let processing_result = platform + .platform + .process_raw_state_transitions( + &vec![transition_bytes], + &platform_state, + &BlockInfo::default(), + &transaction, + platform_version, + false, + None, + ) + .expect("expected to process state transition"); + + assert_matches!( + processing_result.execution_results().as_slice(), + [StateTransitionExecutionResult::SuccessfulExecution { .. }] + ); + + // Commit the transaction so prove_state_transition can read committed state + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .expect("expected to commit transaction"); + + // --- Generate proof --- + let proof_result = platform + .drive + .prove_state_transition(&transition, None, platform_version) + .expect("expected to generate proof for unshield"); + + let grovedb_proof_bytes = proof_result + .into_data() + .expect("expected proof data, not an error"); + + // --- Verify proof --- + let (root_hash, proof_result) = Drive::verify_state_transition_was_executed_with_proof( + &transition, + &BlockInfo::default(), + &grovedb_proof_bytes, + &|_| Ok(None), + platform_version, + ) + .expect("expected to verify unshield proof"); + + assert_ne!(root_hash, [0u8; 32], "root hash should not be zeroed"); + + // --- Assert result is VerifiedShieldedNullifiersWithAddressInfos --- + let StateTransitionProofResult::VerifiedShieldedNullifiersWithAddressInfos( + statuses, + balances, + ) = proof_result + else { + panic!( + "expected VerifiedShieldedNullifiersWithAddressInfos, got {:?}", + proof_result + ); + }; + + // Extract expected nullifiers from the transition + let StateTransition::Unshield(ref st) = transition else { + unreachable!(); + }; + let expected_nullifiers: Vec> = st.nullifiers(); + + assert_eq!( + statuses.len(), + expected_nullifiers.len(), + "should have one status per nullifier" + ); + + for (nf, is_spent) in &statuses { + assert!(is_spent, "nullifier {} should be spent", hex::encode(nf)); + assert!( + expected_nullifiers.contains(nf), + "proved nullifier {} should be one of the transition's nullifiers", + hex::encode(nf) + ); + } + + // Assert the output address appears in the address balances map + assert!( + balances.contains_key(&output_address), + "output address {:?} should be present in address balances", + output_address + ); + } + } } diff --git a/packages/rs-drive-abci/tests/strategy_tests/test_cases/address_tests.rs b/packages/rs-drive-abci/tests/strategy_tests/test_cases/address_tests.rs index d330c2f514d..c5425c21011 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/test_cases/address_tests.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/test_cases/address_tests.rs @@ -2205,7 +2205,10 @@ mod tests { // Now verify the proof using the FromProof trait with our test ContextProvider // This is the key test - it verifies the proof signature using the quorum public key - let verification_result = GroveTrunkQueryResult::maybe_from_proof_with_metadata::<_, _>( + let verification_result = GroveTrunkQueryResult::maybe_from_proof_with_metadata::< + GetAddressesTrunkStateRequest, + _, + >( request, response, Network::Testnet, diff --git a/packages/rs-drive/src/prove/prove_state_transition/v0/mod.rs b/packages/rs-drive/src/prove/prove_state_transition/v0/mod.rs index b51d8e7c6f1..d1a62293b78 100644 --- a/packages/rs-drive/src/prove/prove_state_transition/v0/mod.rs +++ b/packages/rs-drive/src/prove/prove_state_transition/v0/mod.rs @@ -301,14 +301,109 @@ impl Drive { .chain(st.output().into_iter().map(|(address, _)| address)); Drive::balances_for_clear_addresses_query(addresses_to_check) } - StateTransition::Shield(_) - | StateTransition::ShieldedTransfer(_) - | StateTransition::Unshield(_) - | StateTransition::ShieldFromAssetLock(_) - | StateTransition::ShieldedWithdrawal(_) => { - return Err(Error::Proof(ProofError::InvalidTransition( - "shielded state transitions do not support proof generation yet".to_string(), - ))); + StateTransition::ShieldedTransfer(st) => { + use crate::drive::shielded::paths::shielded_credit_pool_nullifiers_path_vec; + use dpp::state_transition::shielded_transfer_transition::accessors::ShieldedTransferTransitionAccessorsV0; + + let nullifier_keys: Vec> = st.nullifiers(); + let count = nullifier_keys.len() as u16; + + let mut query = grovedb::Query::new(); + query.insert_keys(nullifier_keys); + + PathQuery::new( + shielded_credit_pool_nullifiers_path_vec(), + grovedb::SizedQuery::new(query, Some(count), None), + ) + } + StateTransition::Shield(st) => { + Drive::balances_for_clear_addresses_query(st.inputs().keys()) + } + StateTransition::Unshield(st) => { + use crate::drive::shielded::paths::shielded_credit_pool_nullifiers_path_vec; + use dpp::state_transition::unshield_transition::accessors::UnshieldTransitionAccessorsV0; + + let nullifier_keys: Vec> = st.nullifiers(); + let mut nf_query = grovedb::Query::new(); + nf_query.insert_keys(nullifier_keys); + let nullifier_pq = PathQuery::new( + shielded_credit_pool_nullifiers_path_vec(), + grovedb::SizedQuery::new(nf_query, None, None), + ); + + let mut address_pq = + Drive::balances_for_clear_addresses_query(std::iter::once(st.output_address())); + address_pq.query.limit = None; + + PathQuery::merge( + vec![&nullifier_pq, &address_pq], + &platform_version.drive.grove_version, + )? + } + StateTransition::ShieldedWithdrawal(st) => { + use crate::drive::shielded::paths::shielded_credit_pool_nullifiers_path_vec; + use dpp::data_contracts::withdrawals_contract; + use dpp::data_contracts::withdrawals_contract::v1::document_types::withdrawal; + use dpp::document::Document; + use dpp::state_transition::shielded_withdrawal_transition::accessors::ShieldedWithdrawalTransitionAccessorsV0; + + let nullifier_keys: Vec> = st.nullifiers(); + let mut nf_query = grovedb::Query::new(); + nf_query.insert_keys(nullifier_keys.clone()); + let nullifier_pq = PathQuery::new( + shielded_credit_pool_nullifiers_path_vec(), + grovedb::SizedQuery::new(nf_query, None, None), + ); + + // Compute withdrawal document ID deterministically + let first_nullifier = nullifier_keys.first().ok_or_else(|| { + Error::Proof(ProofError::InvalidTransition( + "shielded withdrawal has no nullifiers".to_string(), + )) + })?; + let mut entropy = Vec::new(); + entropy.extend_from_slice(first_nullifier); + entropy.extend_from_slice(st.output_script().as_bytes()); + let document_id = Document::generate_document_id_v0( + &withdrawals_contract::ID, + &withdrawals_contract::OWNER_ID, + withdrawal::NAME, + &entropy, + ); + + let doc_query = SingleDocumentDriveQuery { + contract_id: withdrawals_contract::ID.to_buffer(), + document_type_name: withdrawal::NAME.to_string(), + document_type_keeps_history: false, + document_id: document_id.to_buffer(), + block_time_ms: None, + contested_status: SingleDocumentDriveQueryContestedStatus::NotContested, + }; + let mut doc_pq = doc_query.construct_path_query(platform_version)?; + doc_pq.query.limit = None; + + PathQuery::merge( + vec![&nullifier_pq, &doc_pq], + &platform_version.drive.grove_version, + )? + } + StateTransition::ShieldFromAssetLock(st) => { + use dpp::identity::state_transition::AssetLockProved; + + let outpoint = st.asset_lock_proof().out_point().ok_or_else(|| { + Error::Proof(ProofError::InvalidTransition( + "shield from asset lock has no outpoint".to_string(), + )) + })?; + let outpoint_bytes: [u8; 36] = outpoint.into(); + + let mut query = grovedb::Query::new(); + query.insert_key(outpoint_bytes.to_vec()); + + PathQuery::new( + vec![vec![72u8]], // RootTree::SpentAssetLockTransactions + grovedb::SizedQuery::new(query, Some(1), None), + ) } }; diff --git a/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs b/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs index 4cae37f729c..eb4250d7c2a 100644 --- a/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs +++ b/packages/rs-drive/src/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs @@ -46,7 +46,7 @@ use dpp::state_transition::batch_transition::token_transfer_transition::v0::v0_m use dpp::state_transition::batch_transition::token_unfreeze_transition::v0::v0_methods::TokenUnfreezeTransitionV0Methods; use dpp::state_transition::masternode_vote_transition::accessors::MasternodeVoteTransitionAccessorsV0; use dpp::state_transition::proof_result::StateTransitionProofResult; -use dpp::state_transition::proof_result::StateTransitionProofResult::{VerifiedAddressInfos, VerifiedBalanceTransfer, VerifiedDataContract, VerifiedDocuments, VerifiedIdentity, VerifiedIdentityFullWithAddressInfos, VerifiedIdentityWithAddressInfos, VerifiedMasternodeVote, VerifiedPartialIdentity, VerifiedShieldedPoolState, VerifiedTokenActionWithDocument, VerifiedTokenBalance, VerifiedTokenGroupActionWithDocument, VerifiedTokenGroupActionWithTokenBalance, VerifiedTokenGroupActionWithTokenIdentityInfo, VerifiedTokenGroupActionWithTokenPricingSchedule, VerifiedTokenIdentitiesBalances, VerifiedTokenIdentityInfo, VerifiedTokenPricingSchedule}; +use dpp::state_transition::proof_result::StateTransitionProofResult::{VerifiedAddressInfos, VerifiedBalanceTransfer, VerifiedDataContract, VerifiedDocuments, VerifiedIdentity, VerifiedIdentityFullWithAddressInfos, VerifiedIdentityWithAddressInfos, VerifiedMasternodeVote, VerifiedPartialIdentity, VerifiedTokenActionWithDocument, VerifiedTokenBalance, VerifiedTokenGroupActionWithDocument, VerifiedTokenGroupActionWithTokenBalance, VerifiedTokenGroupActionWithTokenIdentityInfo, VerifiedTokenGroupActionWithTokenPricingSchedule, VerifiedTokenIdentitiesBalances, VerifiedTokenIdentityInfo, VerifiedTokenPricingSchedule}; use dpp::system_data_contracts::{load_system_data_contract, SystemDataContract}; use dpp::tokens::info::v0::IdentityTokenInfoV0Accessors; use dpp::voting::vote_polls::VotePoll; @@ -1129,27 +1129,217 @@ impl Drive { Ok((root_hash, VerifiedAddressInfos(balances))) } StateTransition::Unshield(st) => { - use dpp::state_transition::unshield_transition::UnshieldTransition; - let output_address = match st { - UnshieldTransition::V0(v0) => &v0.output_address, - }; - let (root_hash, balances): ( + use dpp::state_transition::proof_result::StateTransitionProofResult::VerifiedShieldedNullifiersWithAddressInfos; + use dpp::state_transition::unshield_transition::accessors::UnshieldTransitionAccessorsV0; + + let nullifier_keys: Vec> = st.nullifiers(); + + let (root_hash_nf, statuses) = Drive::verify_shielded_nullifiers( + proof, + &nullifier_keys, + true, + platform_version, + )?; + + for (nf, is_spent) in &statuses { + if !is_spent { + return Err(Error::Proof(ProofError::IncorrectProof(format!( + "nullifier {} was not found as spent in the unshield proof", + hex::encode(nf) + )))); + } + } + + let (root_hash_addr, balances): ( RootHash, BTreeMap>, ) = Drive::verify_addresses_infos( proof, - std::iter::once(output_address), + std::iter::once(st.output_address()), + true, + platform_version, + )?; + + if root_hash_nf != root_hash_addr { + return Err(Error::Proof(ProofError::CorruptedProof( + "unshield proof root hashes do not match between nullifiers and address" + .to_string(), + ))); + } + + Ok(( + root_hash_nf, + VerifiedShieldedNullifiersWithAddressInfos(statuses, balances), + )) + } + StateTransition::ShieldedTransfer(st) => { + use dpp::state_transition::proof_result::StateTransitionProofResult::VerifiedShieldedNullifiers; + use dpp::state_transition::shielded_transfer_transition::accessors::ShieldedTransferTransitionAccessorsV0; + + let nullifier_keys: Vec> = st.nullifiers(); + + let (root_hash, statuses) = Drive::verify_shielded_nullifiers( + proof, + &nullifier_keys, false, platform_version, )?; - Ok((root_hash, VerifiedAddressInfos(balances))) + + // All nullifiers must be marked as spent + for (nf, is_spent) in &statuses { + if !is_spent { + return Err(Error::Proof(ProofError::IncorrectProof(format!( + "nullifier {} was not found as spent in the proof", + hex::encode(nf) + )))); + } + } + + Ok((root_hash, VerifiedShieldedNullifiers(statuses))) } - StateTransition::ShieldedTransfer(_) - | StateTransition::ShieldFromAssetLock(_) - | StateTransition::ShieldedWithdrawal(_) => { - let (root_hash, pool_balance) = - Drive::verify_shielded_pool_state(proof, false, platform_version)?; - Ok((root_hash, VerifiedShieldedPoolState(pool_balance))) + StateTransition::ShieldedWithdrawal(st) => { + use dpp::data_contracts::withdrawals_contract; + use dpp::data_contracts::withdrawals_contract::v1::document_types::withdrawal; + use dpp::document::Document; + use dpp::state_transition::proof_result::StateTransitionProofResult::VerifiedShieldedNullifiersWithWithdrawalDocument; + use dpp::state_transition::shielded_withdrawal_transition::accessors::ShieldedWithdrawalTransitionAccessorsV0; + + let nullifier_keys: Vec> = st.nullifiers(); + + let (root_hash_nf, statuses) = Drive::verify_shielded_nullifiers( + proof, + &nullifier_keys, + true, + platform_version, + )?; + + for (nf, is_spent) in &statuses { + if !is_spent { + return Err(Error::Proof(ProofError::IncorrectProof(format!( + "nullifier {} was not found as spent in the shielded withdrawal proof", + hex::encode(nf) + )))); + } + } + + // Compute withdrawal document ID deterministically (same as prove side) + let first_nullifier = nullifier_keys.first().ok_or_else(|| { + Error::Proof(ProofError::InvalidTransition( + "shielded withdrawal has no nullifiers".to_string(), + )) + })?; + let mut entropy = Vec::new(); + entropy.extend_from_slice(first_nullifier); + entropy.extend_from_slice(st.output_script().as_bytes()); + let document_id = Document::generate_document_id_v0( + &withdrawals_contract::ID, + &withdrawals_contract::OWNER_ID, + withdrawal::NAME, + &entropy, + ); + + let contract = + known_contracts_provider_fn(&withdrawals_contract::ID)?.ok_or_else(|| { + Error::Proof(ProofError::UnknownContract( + "withdrawals contract not available for shielded withdrawal verification" + .to_string(), + )) + })?; + let document_type = + contract + .document_type_for_name(withdrawal::NAME) + .map_err(|e| { + Error::Proof(ProofError::UnknownContract(format!( + "cannot fetch withdrawal document type: {}", + e + ))) + })?; + + let doc_query = SingleDocumentDriveQuery { + contract_id: withdrawals_contract::ID.to_buffer(), + document_type_name: withdrawal::NAME.to_string(), + document_type_keeps_history: false, + document_id: document_id.to_buffer(), + block_time_ms: None, + contested_status: SingleDocumentDriveQueryContestedStatus::NotContested, + }; + + let (root_hash_doc, maybe_doc) = + doc_query.verify_proof(true, proof, document_type, platform_version)?; + + if root_hash_nf != root_hash_doc { + return Err(Error::Proof(ProofError::CorruptedProof( + "shielded withdrawal proof root hashes do not match between nullifiers and document" + .to_string(), + ))); + } + + let documents = BTreeMap::from([(document_id, maybe_doc)]); + + Ok(( + root_hash_nf, + VerifiedShieldedNullifiersWithWithdrawalDocument(statuses, documents), + )) + } + StateTransition::ShieldFromAssetLock(st) => { + use dpp::asset_lock::reduced_asset_lock_value::AssetLockValue; + use dpp::asset_lock::StoredAssetLockInfo; + use dpp::identity::state_transition::AssetLockProved; + use dpp::serialization::PlatformDeserializable; + use dpp::state_transition::proof_result::StateTransitionProofResult::VerifiedAssetLockConsumed; + use grovedb::Element; + + let outpoint = st.asset_lock_proof().out_point().ok_or_else(|| { + Error::Proof(ProofError::InvalidTransition( + "shield from asset lock has no outpoint".to_string(), + )) + })?; + let outpoint_bytes: [u8; 36] = outpoint.into(); + + // Build the same PathQuery as the prove side + let mut query = grovedb::Query::new(); + query.insert_key(outpoint_bytes.to_vec()); + let path_query = grovedb::PathQuery::new( + vec![vec![72u8]], // RootTree::SpentAssetLockTransactions + grovedb::SizedQuery::new(query, Some(1), None), + ); + + let (root_hash, mut proved_key_values) = + grovedb::GroveDb::verify_query_with_absence_proof( + proof, + &path_query, + &platform_version.drive.grove_version, + )?; + + if proved_key_values.len() > 1 { + return Err(Error::Proof(ProofError::TooManyElements( + "expected at most 1 element for asset lock outpoint", + ))); + } + + let info = if let Some(proved) = proved_key_values.pop() { + match proved.2 { + Some(Element::Item(bytes, _)) => { + if bytes.is_empty() { + StoredAssetLockInfo::FullyConsumed + } else { + StoredAssetLockInfo::PartiallyConsumed( + AssetLockValue::deserialize_from_bytes(&bytes)?, + ) + } + } + Some(_) => { + return Err(Error::Proof(ProofError::CorruptedProof( + "expected an item element for asset lock outpoint".to_string(), + ))); + } + None => StoredAssetLockInfo::NotPresent, + } + } else { + StoredAssetLockInfo::NotPresent + }; + + Ok((root_hash, VerifiedAssetLockConsumed(info))) } } } 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 caa84f9ebdd..e622afc4e0c 100644 --- a/packages/rs-platform-version/src/version/mocks/v2_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v2_test.rs @@ -504,6 +504,7 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { max_withdrawal_amount: 50_000_000_000_000, max_contract_group_size: 256, max_token_redemption_cycles: 128, + max_shielded_transition_actions: 100, }, consensus: ConsensusVersions { tenderdash_consensus_version: 0, diff --git a/packages/rs-platform-version/src/version/system_limits/mod.rs b/packages/rs-platform-version/src/version/system_limits/mod.rs index 35929bac5de..f5531de6762 100644 --- a/packages/rs-platform-version/src/version/system_limits/mod.rs +++ b/packages/rs-platform-version/src/version/system_limits/mod.rs @@ -18,4 +18,5 @@ pub struct SystemLimits { // For other distributions we much calculate at each cycle the rewards, so we don't want to // do this that much pub max_token_redemption_cycles: u32, + pub max_shielded_transition_actions: u16, } diff --git a/packages/rs-platform-version/src/version/system_limits/v1.rs b/packages/rs-platform-version/src/version/system_limits/v1.rs index 2379b62d6c6..9b11657710c 100644 --- a/packages/rs-platform-version/src/version/system_limits/v1.rs +++ b/packages/rs-platform-version/src/version/system_limits/v1.rs @@ -10,4 +10,5 @@ pub const SYSTEM_LIMITS_V1: SystemLimits = SystemLimits { max_withdrawal_amount: 50_000_000_000_000, //500 Dash max_contract_group_size: 256, max_token_redemption_cycles: 128, + max_shielded_transition_actions: 100, }; diff --git a/packages/rs-sdk-ffi/src/system/queries/path_elements.rs b/packages/rs-sdk-ffi/src/system/queries/path_elements.rs index 3e0678f8168..c3e36047587 100644 --- a/packages/rs-sdk-ffi/src/system/queries/path_elements.rs +++ b/packages/rs-sdk-ffi/src/system/queries/path_elements.rs @@ -159,11 +159,9 @@ fn get_path_elements( Element::CommitmentTree(_, _, _, _) => { "commitment_tree".to_string() } - Element::MmrTree(_, _, _) => "mmr_tree".to_string(), - Element::BulkAppendTree(_, _, _, _) => { - "bulk_append_tree".to_string() - } - Element::DenseAppendOnlyFixedSizeTree(_, _, _, _) => { + Element::MmrTree(_, _) => "mmr_tree".to_string(), + Element::BulkAppendTree(_, _, _) => "bulk_append_tree".to_string(), + Element::DenseAppendOnlyFixedSizeTree(_, _, _) => { "dense_tree".to_string() } }; @@ -187,10 +185,9 @@ fn get_path_elements( "provable_count_sum_tree" } Element::CommitmentTree(_, _, _, _) => "commitment_tree", - Element::MmrTree(_, _, _) => "mmr_tree", - Element::BulkAppendTree(_, _, _, _) => "bulk_append_tree", - Element::DenseAppendOnlyFixedSizeTree(_, _, _, _) => - "dense_tree", + Element::MmrTree(_, _) => "mmr_tree", + Element::BulkAppendTree(_, _, _) => "bulk_append_tree", + Element::DenseAppendOnlyFixedSizeTree(_, _, _) => "dense_tree", } ) }) diff --git a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs index 7a8260989a2..8d0bcc63a37 100644 --- a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs +++ b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs @@ -88,8 +88,8 @@ use dpp::consensus::state::prefunded_specialized_balances::prefunded_specialized use dpp::consensus::state::prefunded_specialized_balances::prefunded_specialized_balance_not_found_error::PrefundedSpecializedBalanceNotFoundError; use dpp::consensus::state::token::{IdentityDoesNotHaveEnoughTokenBalanceError, IdentityTokenAccountNotFrozenError, IdentityTokenAccountFrozenError, TokenIsPausedError, IdentityTokenAccountAlreadyFrozenError, UnauthorizedTokenActionError, TokenSettingMaxSupplyToLessThanCurrentSupplyError, TokenMintPastMaxSupplyError, NewTokensDestinationIdentityDoesNotExistError, NewAuthorizedActionTakerIdentityDoesNotExistError, NewAuthorizedActionTakerGroupDoesNotExistError, NewAuthorizedActionTakerMainGroupNotSetError, InvalidGroupPositionError, TokenAlreadyPausedError, TokenNotPausedError, InvalidTokenClaimPropertyMismatch, InvalidTokenClaimNoCurrentRewards, InvalidTokenClaimWrongClaimant, TokenTransferRecipientIdentityNotExistError, PreProgrammedDistributionTimestampInPastError, IdentityHasNotAgreedToPayRequiredTokenAmountError, RequiredTokenPaymentInfoNotSetError, IdentityTryingToPayWithWrongTokenError, TokenDirectPurchaseUserPriceTooLow, TokenAmountUnderMinimumSaleAmount, TokenNotForDirectSale, InvalidTokenPositionStateError}; use dpp::consensus::state::address_funds::{AddressDoesNotExistError, AddressInvalidNonceError, AddressNotEnoughFundsError, AddressesNotEnoughFundsError}; -use dpp::consensus::state::shielded::{InsufficientPoolNotesError, InvalidAnchorError, InvalidShieldedProofError, NullifierAlreadySpentError}; -use dpp::consensus::basic::state_transition::{StateTransitionNotActiveError, TransitionOverMaxInputsError, TransitionOverMaxOutputsError, InputWitnessCountMismatchError, TransitionNoInputsError, TransitionNoOutputsError, FeeStrategyEmptyError, FeeStrategyDuplicateError, FeeStrategyIndexOutOfBoundsError, FeeStrategyTooManyStepsError, InputBelowMinimumError, OutputBelowMinimumError, InputOutputBalanceMismatchError, OutputsNotGreaterThanInputsError, WithdrawalBalanceMismatchError, InsufficientFundingAmountError, InputsNotLessThanOutputsError, OutputAddressAlsoInputError, InvalidRemainderOutputCountError, WithdrawalBelowMinAmountError, ShieldedNoActionsError, ShieldedEmptyProofError, ShieldedZeroAnchorError, ShieldedInvalidValueBalanceError, UnshieldAmountZeroError, UnshieldValueBalanceBelowAmountError}; +use dpp::consensus::state::shielded::{InsufficientPoolNotesError, InsufficientShieldedFeeError, InvalidAnchorError, InvalidShieldedProofError, NullifierAlreadySpentError}; +use dpp::consensus::basic::state_transition::{StateTransitionNotActiveError, TransitionOverMaxInputsError, TransitionOverMaxOutputsError, InputWitnessCountMismatchError, TransitionNoInputsError, TransitionNoOutputsError, FeeStrategyEmptyError, FeeStrategyDuplicateError, FeeStrategyIndexOutOfBoundsError, FeeStrategyTooManyStepsError, InputBelowMinimumError, OutputBelowMinimumError, InputOutputBalanceMismatchError, OutputsNotGreaterThanInputsError, WithdrawalBalanceMismatchError, InsufficientFundingAmountError, InputsNotLessThanOutputsError, OutputAddressAlsoInputError, InvalidRemainderOutputCountError, WithdrawalBelowMinAmountError, ShieldedNoActionsError, ShieldedTooManyActionsError, ShieldedEmptyProofError, ShieldedZeroAnchorError, ShieldedInvalidValueBalanceError, UnshieldAmountZeroError, UnshieldValueBalanceBelowAmountError}; use dpp::consensus::state::voting::masternode_incorrect_voter_identity_id_error::MasternodeIncorrectVoterIdentityIdError; use dpp::consensus::state::voting::masternode_incorrect_voting_address_error::MasternodeIncorrectVotingAddressError; use dpp::consensus::state::voting::masternode_not_found_error::MasternodeNotFoundError; @@ -454,6 +454,9 @@ pub fn from_state_error(state_error: &StateError) -> JsValue { StateError::InsufficientPoolNotesError(e) => { generic_consensus_error!(InsufficientPoolNotesError, e).into() } + StateError::InsufficientShieldedFeeError(e) => { + generic_consensus_error!(InsufficientShieldedFeeError, e).into() + } } } @@ -937,6 +940,9 @@ fn from_basic_error(basic_error: &BasicError) -> JsValue { BasicError::ShieldedNoActionsError(e) => { generic_consensus_error!(ShieldedNoActionsError, e).into() } + BasicError::ShieldedTooManyActionsError(e) => { + generic_consensus_error!(ShieldedTooManyActionsError, e).into() + } BasicError::ShieldedEmptyProofError(e) => { generic_consensus_error!(ShieldedEmptyProofError, e).into() } diff --git a/packages/wasm-dpp2/src/state_transitions/proof_result.rs b/packages/wasm-dpp2/src/state_transitions/proof_result.rs index 766f266b4df..538b6526f62 100644 --- a/packages/wasm-dpp2/src/state_transitions/proof_result.rs +++ b/packages/wasm-dpp2/src/state_transitions/proof_result.rs @@ -58,7 +58,7 @@ export type StateTransitionProofResultType = | VerifiedAddressInfos | VerifiedIdentityFullWithAddressInfos | VerifiedIdentityWithAddressInfos - | VerifiedShieldedPoolState; + | VerifiedAssetLockConsumed; "#; #[wasm_bindgen] @@ -735,25 +735,23 @@ fn action_status_to_string(status: dpp::group::group_action_status::GroupActionS } } -// --- VerifiedShieldedPoolState --- +// --- VerifiedAssetLockConsumed --- -#[wasm_bindgen(js_name = "VerifiedShieldedPoolState")] +#[wasm_bindgen(js_name = "VerifiedAssetLockConsumed")] #[derive(Clone, Serialize, Deserialize)] -pub struct VerifiedShieldedPoolStateWasm { - pool_balance: Option, +pub struct VerifiedAssetLockConsumedWasm { + /// "FullyConsumed", "PartiallyConsumed", or "NotPresent" + status: String, } -impl_wasm_type_info!(VerifiedShieldedPoolStateWasm, VerifiedShieldedPoolState); -impl_wasm_conversions!(VerifiedShieldedPoolStateWasm, VerifiedShieldedPoolState); +impl_wasm_type_info!(VerifiedAssetLockConsumedWasm, VerifiedAssetLockConsumed); +impl_wasm_conversions!(VerifiedAssetLockConsumedWasm, VerifiedAssetLockConsumed); -#[wasm_bindgen(js_class = VerifiedShieldedPoolState)] -impl VerifiedShieldedPoolStateWasm { - #[wasm_bindgen(getter, js_name = "poolBalance")] - pub fn pool_balance(&self) -> JsValue { - match self.pool_balance { - Some(b) => BigInt::from(b).into(), - None => JsValue::undefined(), - } +#[wasm_bindgen(js_class = VerifiedAssetLockConsumed)] +impl VerifiedAssetLockConsumedWasm { + #[wasm_bindgen(getter)] + pub fn status(&self) -> String { + self.status.clone() } } @@ -918,11 +916,23 @@ pub fn convert_proof_result( .into() } - StateTransitionProofResult::VerifiedShieldedPoolState(maybe_balance) => { - VerifiedShieldedPoolStateWasm { - pool_balance: maybe_balance, - } - .into() + StateTransitionProofResult::VerifiedShieldedNullifiers(..) + | StateTransitionProofResult::VerifiedShieldedNullifiersWithAddressInfos(..) + | StateTransitionProofResult::VerifiedShieldedNullifiersWithWithdrawalDocument(..) => { + return Err(WasmDppError::generic( + "Shielded nullifier proof results are not yet supported in WASM", + ) + .into()); + } + + StateTransitionProofResult::VerifiedAssetLockConsumed(info) => { + use dpp::asset_lock::StoredAssetLockInfo; + let status = match info { + StoredAssetLockInfo::FullyConsumed => "FullyConsumed".to_string(), + StoredAssetLockInfo::PartiallyConsumed(_) => "PartiallyConsumed".to_string(), + StoredAssetLockInfo::NotPresent => "NotPresent".to_string(), + }; + VerifiedAssetLockConsumedWasm { status }.into() } }; From 415ee8b2e5f3a2b79bb9c0d14947baa73e75812c Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 25 Feb 2026 14:10:21 +0700 Subject: [PATCH 35/40] more work --- .../tests/strategy_tests/test_cases/address_tests.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/rs-drive-abci/tests/strategy_tests/test_cases/address_tests.rs b/packages/rs-drive-abci/tests/strategy_tests/test_cases/address_tests.rs index c5425c21011..2d1611cbbc8 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/test_cases/address_tests.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/test_cases/address_tests.rs @@ -2205,10 +2205,9 @@ mod tests { // Now verify the proof using the FromProof trait with our test ContextProvider // This is the key test - it verifies the proof signature using the quorum public key - let verification_result = GroveTrunkQueryResult::maybe_from_proof_with_metadata::< + let verification_result = ( + >>::maybe_from_proof_with_metadata( request, response, Network::Testnet, From 1f94fe2afd5d1fb78b354d075fef687d57eb6334 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 25 Feb 2026 14:20:43 +0700 Subject: [PATCH 36/40] more work --- packages/rs-drive/src/query/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rs-drive/src/query/mod.rs b/packages/rs-drive/src/query/mod.rs index ef57daaa180..f3e29653687 100644 --- a/packages/rs-drive/src/query/mod.rs +++ b/packages/rs-drive/src/query/mod.rs @@ -2781,7 +2781,7 @@ mod tests { .construct_path_query(None, platform_version) .expect("expected to create path query"); - assert_eq!(path_query.to_string(), "PathQuery { path: [@, 0x1da29f488023e306ff9a680bc9837153fb0778c8ee9c934a87dc0de1d69abd3c, 0x01, domain, 0x7265636f7264732e6964656e74697479], query: SizedQuery { query: Query {\n items: [\n RangeTo(.. 8dc201fd7ad7905f8a84d66218e2b387daea7fe4739ae0e21e8c3ee755e6a2c0),\n ],\n default_subquery_branch: SubqueryBranch { subquery_path: [00], subquery: Query {\n items: [\n RangeFull,\n ],\n default_subquery_branch: SubqueryBranch { subquery_path: None subquery: None },\n left_to_right: false,\n} },\n conditional_subquery_branches: {\n Key(): SubqueryBranch { subquery_path: [00], subquery: Query {\n items: [\n RangeFull,\n ],\n default_subquery_branch: SubqueryBranch { subquery_path: None subquery: None },\n left_to_right: false,\n} },\n },\n left_to_right: false,\n}, limit: 6 } }"); + assert_eq!(path_query.to_string(), "PathQuery { path: [@, 0x1da29f488023e306ff9a680bc9837153fb0778c8ee9c934a87dc0de1d69abd3c, 0x01, domain, 0x7265636f7264732e6964656e74697479], query: SizedQuery { query: Query {\n items: [\n RangeTo(.. 0x8dc201fd7ad7905f8a84d66218e2b387daea7fe4739ae0e21e8c3ee755e6a2c0),\n ],\n default_subquery_branch: SubqueryBranch { subquery_path: [0x00], subquery: Query {\n items: [\n RangeFull,\n ],\n default_subquery_branch: SubqueryBranch { subquery_path: None subquery: None },\n left_to_right: false,\n add_parent_tree_on_subquery: false,\n} },\n conditional_subquery_branches: {\n Key(): SubqueryBranch { subquery_path: [0x00], subquery: Query {\n items: [\n RangeFull,\n ],\n default_subquery_branch: SubqueryBranch { subquery_path: None subquery: None },\n left_to_right: false,\n add_parent_tree_on_subquery: false,\n} },\n },\n left_to_right: false,\n add_parent_tree_on_subquery: false,\n}, limit: 6 } }"); // Serialize the PathQuery to a Vec let encoded = bincode::encode_to_vec(&path_query, bincode::config::standard()) From ca9dd7ecf533dceb510a1ae8bd90f5433e10ed90 Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 25 Feb 2026 16:00:33 +0700 Subject: [PATCH 37/40] more work --- .../state_transitions/shielded_common/mod.rs | 6 ++++++ packages/rs-drive-abci/src/main.rs | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs index 222649b1dc4..2dbe78b0e20 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_common/mod.rs @@ -35,6 +35,12 @@ fn get_verifying_key() -> &'static VerifyingKey { SHIELDED_VERIFYING_KEY.get_or_init(VerifyingKey::build) } +/// Pre-builds the shielded verifying key so that the first shielded +/// transaction does not pay the ~5-15 s construction cost at check_tx time. +pub fn warmup_shielded_verifying_key() { + get_verifying_key(); +} + const EPK_SIZE: usize = 32; const ENC_CIPHERTEXT_SIZE: usize = 104; const OUT_CIPHERTEXT_SIZE: usize = 80; diff --git a/packages/rs-drive-abci/src/main.rs b/packages/rs-drive-abci/src/main.rs index 5f8e332301a..a003e2e2f44 100644 --- a/packages/rs-drive-abci/src/main.rs +++ b/packages/rs-drive-abci/src/main.rs @@ -149,6 +149,15 @@ impl Cli { ) .expect("Failed to open platform"); + // Pre-build the shielded verifying key on a background thread so + // the first shielded transaction doesn't pay the ~5-15s build cost. + std::thread::spawn(|| { + use drive_abci::execution::validation::state_transition::shielded_common::warmup_shielded_verifying_key; + tracing::info!("pre-building shielded verifying key in background"); + warmup_shielded_verifying_key(); + tracing::info!("shielded verifying key is ready"); + }); + server::start(runtime, Arc::new(platform), config, cancel); tracing::info!("drive-abci server is stopped"); From 4aa8b9312185890be8eba4f935604e9b26ca652a Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Wed, 25 Feb 2026 16:30:25 +0700 Subject: [PATCH 38/40] fix --- Cargo.toml | 29 +++++++++++++++++++++++++++++ packages/rs-sdk/src/shielded.rs | 23 +++++++++++++++-------- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9ec94c2c918..5769f5da58f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,35 @@ key-wallet = { git = "https://github.com/dashpay/rust-dashcore", rev = "a05d256f key-wallet-manager = { git = "https://github.com/dashpay/rust-dashcore", rev = "a05d256f59743c69df912462dd77dd487e1ff5b2" } dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore", rev = "a05d256f59743c69df912462dd77dd487e1ff5b2" } +# Optimize heavy crypto crates even in dev/test builds so that +# Halo 2 proof generation and verification run at near-release speed. +# Without this, ZK operations are 10-100x slower (debug field arithmetic). +[profile.dev.package.halo2_proofs] +opt-level = 3 +[profile.dev.package.halo2_gadgets] +opt-level = 3 +[profile.dev.package.halo2_poseidon] +opt-level = 3 +[profile.dev.package.orchard] +opt-level = 3 +[profile.dev.package.pasta_curves] +opt-level = 3 +[profile.dev.package.grovedb-commitment-tree] +opt-level = 3 + +[profile.test.package.halo2_proofs] +opt-level = 3 +[profile.test.package.halo2_gadgets] +opt-level = 3 +[profile.test.package.halo2_poseidon] +opt-level = 3 +[profile.test.package.orchard] +opt-level = 3 +[profile.test.package.pasta_curves] +opt-level = 3 +[profile.test.package.grovedb-commitment-tree] +opt-level = 3 + [workspace.package] version = "3.1.0-dev.1" diff --git a/packages/rs-sdk/src/shielded.rs b/packages/rs-sdk/src/shielded.rs index d8161764cbc..4bfbd5f01cc 100644 --- a/packages/rs-sdk/src/shielded.rs +++ b/packages/rs-sdk/src/shielded.rs @@ -126,6 +126,8 @@ pub struct ShieldedSyncResult { pub next_start_index: u64, /// Total number of notes scanned in this sync. pub total_notes_scanned: u64, + /// Platform block height at the time of the most recent chunk response. + pub block_height: u64, } /// Fetch all shielded encrypted notes starting from `start_index`, query @@ -177,10 +179,10 @@ pub async fn sync_shielded_notes( let settings = config.request_settings; type ChunkFuture = - Pin), Error>> + Send>>; + Pin, u64), Error>> + Send>>; // Sliding-window parallel fetch using FuturesUnordered. - // Each future fetches one chunk and returns (chunk_start_index, notes). + // Each future fetches one chunk and returns (chunk_start_index, notes, block_height). let mut futures: FuturesUnordered = FuturesUnordered::new(); let mut next_chunk_index = start_index; let mut reached_end = false; @@ -197,11 +199,13 @@ pub async fn sync_shielded_notes( // Collect results keyed by chunk start_index for ordered reassembly let mut chunk_results: BTreeMap> = BTreeMap::new(); + let mut max_block_height: u64 = 0; while let Some(result) = futures.next().await { - let (chunk_idx, notes) = result?; + let (chunk_idx, notes, block_height) = result?; let is_partial = (notes.len() as u64) < chunk_size; chunk_results.insert(chunk_idx, notes); + max_block_height = max_block_height.max(block_height); if is_partial { reached_end = true; @@ -268,19 +272,20 @@ pub async fn sync_shielded_notes( all_notes, next_start_index, total_notes_scanned, + block_height: max_block_height, }) } /// Fetch a single chunk of encrypted notes from the network. /// -/// Returns `(chunk_start_index, notes)`. An empty vec means no notes exist -/// at this position (past end of tree). +/// Returns `(chunk_start_index, notes, block_height)`. An empty vec means no +/// notes exist at this position (past end of tree). async fn fetch_chunk( sdk: &Sdk, chunk_start: u64, chunk_size: u64, settings: RequestSettings, -) -> Result<(u64, Vec), Error> { +) -> Result<(u64, Vec, u64), Error> { let query = ShieldedEncryptedNotesQuery { start_index: chunk_start, count: chunk_size as u32, @@ -288,7 +293,8 @@ async fn fetch_chunk( debug!(chunk_start, chunk_size, "fetching shielded notes chunk"); - let result = ShieldedEncryptedNotes::fetch_with_settings(sdk, query, settings).await?; + let (result, metadata) = + ShieldedEncryptedNotes::fetch_with_metadata(sdk, query, Some(settings)).await?; let notes = match result { Some(ShieldedEncryptedNotes(notes)) => notes, @@ -298,8 +304,9 @@ async fn fetch_chunk( debug!( chunk_start, notes_returned = notes.len(), + block_height = metadata.height, "shielded notes chunk fetched" ); - Ok((chunk_start, notes)) + Ok((chunk_start, notes, metadata.height)) } From 48aa2d4ace2255df6777ead340395486682540fe Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Thu, 26 Feb 2026 07:40:27 +0700 Subject: [PATCH 39/40] more work --- .../shield/transform_into_action/v0/mod.rs | 21 ++++++------ .../transform_into_action/v0/mod.rs | 23 ++++++------- .../transform_into_action/v0/mod.rs | 22 ++++++------- .../transform_into_action/v0/mod.rs | 24 ++++++-------- .../unshield/transform_into_action/v0/mod.rs | 22 ++++++------- .../shielded/mod.rs | 32 +++++++++---------- .../shield_from_asset_lock_transition.rs | 7 +--- .../shielded/shield_transition.rs | 7 +--- .../shielded/shielded_transfer_transition.rs | 11 ++----- .../shielded_withdrawal_transition.rs | 11 ++----- .../shielded/unshield_transition.rs | 11 ++----- .../state_transition_action/shielded/mod.rs | 11 +++++++ .../shielded/shield/mod.rs | 13 +++----- .../shielded/shield/transformer.rs | 9 ++---- .../shielded/shield/v0/mod.rs | 9 ++---- .../shielded/shield/v0/transformer.rs | 9 ++---- .../shielded/shield_from_asset_lock/mod.rs | 13 +++----- .../shield_from_asset_lock/transformer.rs | 9 ++---- .../shielded/shield_from_asset_lock/v0/mod.rs | 9 ++---- .../shield_from_asset_lock/v0/transformer.rs | 9 ++---- .../shielded/shielded_transfer/mod.rs | 19 +++-------- .../shielded/shielded_transfer/transformer.rs | 9 ++---- .../shielded/shielded_transfer/v0/mod.rs | 9 ++---- .../shielded_transfer/v0/transformer.rs | 9 ++---- .../shielded/shielded_withdrawal/mod.rs | 19 +++-------- .../shielded_withdrawal/transformer.rs | 9 ++---- .../shielded/shielded_withdrawal/v0/mod.rs | 9 ++---- .../shielded_withdrawal/v0/transformer.rs | 13 +++----- .../shielded/unshield/mod.rs | 19 +++-------- .../shielded/unshield/transformer.rs | 9 ++---- .../shielded/unshield/v0/mod.rs | 9 ++---- .../shielded/unshield/v0/transformer.rs | 9 ++---- 32 files changed, 152 insertions(+), 272 deletions(-) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs index b5f3f178dbb..c9aff2b9f3a 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield/transform_into_action/v0/mod.rs @@ -15,6 +15,7 @@ use dpp::version::PlatformVersion; use drive::drive::Drive; use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::shield::ShieldTransitionAction; +use drive::state_transition_action::shielded::ShieldedActionNote; use drive::state_transition_action::StateTransitionAction; use std::collections::BTreeMap; @@ -41,18 +42,16 @@ impl ShieldStateTransitionTransformIntoActionValidationV0 for ShieldTransition { execution_context: &mut StateTransitionExecutionContext, platform_version: &PlatformVersion, ) -> Result, Error> { - // Extract nullifiers, note commitments, and encrypted notes from serialized actions - let nullifiers: Vec<[u8; 32]> = match self { - ShieldTransition::V0(v0) => v0.actions.iter().map(|a| a.nullifier).collect(), - }; - let note_commitments: Vec<[u8; 32]> = match self { - ShieldTransition::V0(v0) => v0.actions.iter().map(|a| a.cmx).collect(), - }; - let encrypted_notes: Vec> = match self { + // Extract notes from serialized actions + let notes: Vec = match self { ShieldTransition::V0(v0) => v0 .actions .iter() - .map(|a| a.encrypted_note.clone()) + .map(|a| ShieldedActionNote { + nullifier: a.nullifier, + cmx: a.cmx, + encrypted_note: a.encrypted_note.clone(), + }) .collect(), }; @@ -102,9 +101,7 @@ impl ShieldStateTransitionTransformIntoActionValidationV0 for ShieldTransition { self, inputs_with_remaining_balance, shield_amount, - nullifiers, - note_commitments, - encrypted_notes, + notes, current_total_balance, ); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs index 47b0f0fd94f..44b0227db1d 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shield_from_asset_lock/transform_into_action/v0/mod.rs @@ -34,6 +34,7 @@ use dpp::state_transition::{StateTransitionEstimatedFeeValidation, StateTransiti use drive::drive::Drive; use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::shield_from_asset_lock::ShieldFromAssetLockTransitionAction; +use drive::state_transition_action::shielded::ShieldedActionNote; use drive::state_transition_action::system::partially_use_asset_lock_action::PartiallyUseAssetLockActionV0; use drive::state_transition_action::system::partially_use_asset_lock_action::PartiallyUseAssetLockAction; use drive::state_transition_action::StateTransitionAction; @@ -65,20 +66,16 @@ impl ShieldFromAssetLockStateTransitionTransformIntoActionValidationV0 ) -> Result, Error> { let platform_version = platform.state.current_platform_version()?; - // Extract nullifiers, note commitments, and encrypted notes from serialized actions - let nullifiers: Vec<[u8; 32]> = match self { - ShieldFromAssetLockTransition::V0(v0) => { - v0.actions.iter().map(|a| a.nullifier).collect() - } - }; - let note_commitments: Vec<[u8; 32]> = match self { - ShieldFromAssetLockTransition::V0(v0) => v0.actions.iter().map(|a| a.cmx).collect(), - }; - let encrypted_notes: Vec> = match self { + // Extract notes from serialized actions + let notes: Vec = match self { ShieldFromAssetLockTransition::V0(v0) => v0 .actions .iter() - .map(|a| a.encrypted_note.clone()) + .map(|a| ShieldedActionNote { + nullifier: a.nullifier, + cmx: a.cmx, + encrypted_note: a.encrypted_note.clone(), + }) .collect(), }; @@ -354,9 +351,7 @@ impl ShieldFromAssetLockStateTransitionTransformIntoActionValidationV0 asset_lock_value_credits, signable_bytes_hash, shield_amount, - nullifiers, - note_commitments, - encrypted_notes, + notes, current_total_balance, ); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs index c739b8eff42..dc8d8622b66 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_transfer/transform_into_action/v0/mod.rs @@ -15,6 +15,7 @@ use dpp::version::PlatformVersion; use drive::drive::Drive; use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::shielded_transfer::ShieldedTransferTransitionAction; +use drive::state_transition_action::shielded::ShieldedActionNote; use drive::state_transition_action::StateTransitionAction; pub(in crate::execution::validation::state_transition::state_transitions::shielded_transfer) trait ShieldedTransferStateTransitionTransformIntoActionValidationV0 @@ -38,18 +39,16 @@ impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 for Shielded execution_context: &mut StateTransitionExecutionContext, platform_version: &PlatformVersion, ) -> Result, Error> { - // Extract nullifiers, note commitments, and encrypted notes from serialized actions - let nullifiers: Vec<[u8; 32]> = match self { - ShieldedTransferTransition::V0(v0) => v0.actions.iter().map(|a| a.nullifier).collect(), - }; - let note_commitments: Vec<[u8; 32]> = match self { - ShieldedTransferTransition::V0(v0) => v0.actions.iter().map(|a| a.cmx).collect(), - }; - let encrypted_notes: Vec> = match self { + // Extract notes from serialized actions + let notes: Vec = match self { ShieldedTransferTransition::V0(v0) => v0 .actions .iter() - .map(|a| a.encrypted_note.clone()) + .map(|a| ShieldedActionNote { + nullifier: a.nullifier, + cmx: a.cmx, + encrypted_note: a.encrypted_note.clone(), + }) .collect(), }; @@ -95,6 +94,7 @@ impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 for Shielded } // Validate nullifiers: intra-bundle duplicates + already-spent in state + let nullifiers: Vec<[u8; 32]> = notes.iter().map(|n| n.nullifier).collect(); if let Some(err) = validate_nullifiers( drive, &nullifiers, @@ -118,9 +118,7 @@ impl ShieldedTransferStateTransitionTransformIntoActionValidationV0 for Shielded let result = ShieldedTransferTransitionAction::try_from_transition( self, - nullifiers, - note_commitments, - encrypted_notes, + notes, anchor, fee_amount, current_total_balance, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs index 3a24403ce4e..d348e14d166 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/transform_into_action/v0/mod.rs @@ -15,6 +15,7 @@ use dpp::version::PlatformVersion; use drive::drive::Drive; use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::shielded_withdrawal::ShieldedWithdrawalTransitionAction; +use drive::state_transition_action::shielded::ShieldedActionNote; use drive::state_transition_action::StateTransitionAction; pub(in crate::execution::validation::state_transition::state_transitions::shielded_withdrawal) trait ShieldedWithdrawalStateTransitionTransformIntoActionValidationV0 @@ -40,20 +41,16 @@ impl ShieldedWithdrawalStateTransitionTransformIntoActionValidationV0 transaction: TransactionArg, platform_version: &PlatformVersion, ) -> Result, Error> { - // Extract nullifiers, note commitments, and encrypted notes from serialized actions - let nullifiers: Vec<[u8; 32]> = match self { - ShieldedWithdrawalTransition::V0(v0) => { - v0.actions.iter().map(|a| a.nullifier).collect() - } - }; - let note_commitments: Vec<[u8; 32]> = match self { - ShieldedWithdrawalTransition::V0(v0) => v0.actions.iter().map(|a| a.cmx).collect(), - }; - let encrypted_notes: Vec> = match self { + // Extract notes from serialized actions + let notes: Vec = match self { ShieldedWithdrawalTransition::V0(v0) => v0 .actions .iter() - .map(|a| a.encrypted_note.clone()) + .map(|a| ShieldedActionNote { + nullifier: a.nullifier, + cmx: a.cmx, + encrypted_note: a.encrypted_note.clone(), + }) .collect(), }; @@ -111,6 +108,7 @@ impl ShieldedWithdrawalStateTransitionTransformIntoActionValidationV0 } // Validate nullifiers: intra-bundle duplicates + already-spent in state + let nullifiers: Vec<[u8; 32]> = notes.iter().map(|n| n.nullifier).collect(); if let Some(err) = validate_nullifiers( drive, &nullifiers, @@ -137,9 +135,7 @@ impl ShieldedWithdrawalStateTransitionTransformIntoActionValidationV0 let result = ShieldedWithdrawalTransitionAction::try_from_transition( self, - nullifiers, - note_commitments, - encrypted_notes, + notes, anchor, current_total_balance, creation_time_ms, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs index aacf924805e..a84265d1cce 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/transform_into_action/v0/mod.rs @@ -14,6 +14,7 @@ use dpp::version::PlatformVersion; use drive::drive::Drive; use drive::grovedb::TransactionArg; use drive::state_transition_action::shielded::unshield::UnshieldTransitionAction; +use drive::state_transition_action::shielded::ShieldedActionNote; use drive::state_transition_action::StateTransitionAction; pub(in crate::execution::validation::state_transition::state_transitions::unshield) trait UnshieldStateTransitionTransformIntoActionValidationV0 @@ -37,18 +38,16 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti execution_context: &mut StateTransitionExecutionContext, platform_version: &PlatformVersion, ) -> Result, Error> { - // Extract nullifiers, note commitments, and encrypted notes from serialized actions - let nullifiers: Vec<[u8; 32]> = match self { - UnshieldTransition::V0(v0) => v0.actions.iter().map(|a| a.nullifier).collect(), - }; - let note_commitments: Vec<[u8; 32]> = match self { - UnshieldTransition::V0(v0) => v0.actions.iter().map(|a| a.cmx).collect(), - }; - let encrypted_notes: Vec> = match self { + // Extract notes from serialized actions + let notes: Vec = match self { UnshieldTransition::V0(v0) => v0 .actions .iter() - .map(|a| a.encrypted_note.clone()) + .map(|a| ShieldedActionNote { + nullifier: a.nullifier, + cmx: a.cmx, + encrypted_note: a.encrypted_note.clone(), + }) .collect(), }; @@ -84,6 +83,7 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti } // Validate nullifiers: intra-bundle duplicates + already-spent in state + let nullifiers: Vec<[u8; 32]> = notes.iter().map(|n| n.nullifier).collect(); if let Some(err) = validate_nullifiers( drive, &nullifiers, @@ -126,9 +126,7 @@ impl UnshieldStateTransitionTransformIntoActionValidationV0 for UnshieldTransiti let result = UnshieldTransitionAction::try_from_transition( self, - nullifiers, - note_commitments, - encrypted_notes, + notes, anchor, current_total_balance, ); diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs index 6e45d4472e3..a5d89eab701 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs @@ -4,15 +4,19 @@ mod shielded_transfer_transition; mod shielded_withdrawal_transition; mod unshield_transition; +use crate::state_transition_action::shielded::ShieldedActionNote; use crate::util::batch::drive_op_batch::ShieldedPoolOperationType; use crate::util::batch::DriveOperation; /// Insert each nullifier (InsertOnly to prevent double-spend). -pub(super) fn insert_nullifiers<'a>(ops: &mut Vec>, nullifiers: &[[u8; 32]]) { - for nullifier in nullifiers.iter() { +pub(super) fn insert_nullifiers<'a>( + ops: &mut Vec>, + notes: &[ShieldedActionNote], +) { + for note in notes { ops.push(DriveOperation::ShieldedPoolOperation( ShieldedPoolOperationType::InsertNullifier { - nullifier: *nullifier, + nullifier: note.nullifier, }, )); } @@ -24,20 +28,14 @@ pub(super) fn insert_nullifiers<'a>(ops: &mut Vec>, nullifier /// Rho for trial decryption. pub(super) fn insert_notes<'a>( ops: &mut Vec>, - nullifiers: &[[u8; 32]], - note_commitments: &[[u8; 32]], - encrypted_notes: &[Vec], + notes: &[ShieldedActionNote], ) { - for ((nullifier, cmx), encrypted_note) in nullifiers - .iter() - .zip(note_commitments.iter()) - .zip(encrypted_notes.iter()) - { + for note in notes { ops.push(DriveOperation::ShieldedPoolOperation( ShieldedPoolOperationType::InsertNote { - nullifier: *nullifier, - cmx: *cmx, - encrypted_note: encrypted_note.clone(), + nullifier: note.nullifier, + cmx: note.cmx, + encrypted_note: note.encrypted_note.clone(), }, )); } @@ -53,12 +51,12 @@ pub(super) fn update_balance<'a>(ops: &mut Vec>, new_total_ba /// Store nullifiers to recent block storage for catch-up sync RPCs. pub(super) fn store_nullifiers_for_block<'a>( ops: &mut Vec>, - nullifiers: &[[u8; 32]], + notes: &[ShieldedActionNote], ) { - if !nullifiers.is_empty() { + if !notes.is_empty() { ops.push(DriveOperation::ShieldedPoolOperation( ShieldedPoolOperationType::StoreNullifiersForBlock { - nullifiers: nullifiers.to_vec(), + nullifiers: notes.iter().map(|n| n.nullifier).collect(), }, )); } diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_from_asset_lock_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_from_asset_lock_transition.rs index eea69690e59..58d878e68ed 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_from_asset_lock_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_from_asset_lock_transition.rs @@ -50,12 +50,7 @@ impl DriveHighLevelOperationConverter for ShieldFromAssetLockTransitionAction { )); // 3. Insert notes into CommitmentTree - insert_notes( - &mut ops, - &v0.nullifiers, - &v0.note_commitments, - &v0.encrypted_notes, - ); + insert_notes(&mut ops, &v0.notes); // 4. Update total balance let new_total_balance = diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_transition.rs index 530b4e08a05..4572c2f9d51 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shield_transition.rs @@ -37,12 +37,7 @@ impl DriveHighLevelOperationConverter for ShieldTransitionAction { } // 2. Insert notes into CommitmentTree - insert_notes( - &mut ops, - &v0.nullifiers, - &v0.note_commitments, - &v0.encrypted_notes, - ); + insert_notes(&mut ops, &v0.notes); // 3. Update total balance let new_total_balance = v0 diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs index 5913f66dc43..2c7f8eb9783 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_transfer_transition.rs @@ -25,15 +25,10 @@ impl DriveHighLevelOperationConverter for ShieldedTransferTransitionAction { let mut ops: Vec> = Vec::new(); // 1. Insert each nullifier (InsertOnly to prevent double-spend) - insert_nullifiers(&mut ops, &v0.nullifiers); + insert_nullifiers(&mut ops, &v0.notes); // 2. Insert notes into CommitmentTree - insert_notes( - &mut ops, - &v0.nullifiers, - &v0.note_commitments, - &v0.encrypted_notes, - ); + insert_notes(&mut ops, &v0.notes); // 3. Update total balance (pool decreases by fee_amount) let new_total_balance = v0 @@ -48,7 +43,7 @@ impl DriveHighLevelOperationConverter for ShieldedTransferTransitionAction { update_balance(&mut ops, new_total_balance); // 4. Store nullifiers to recent block storage for catch-up sync - store_nullifiers_for_block(&mut ops, &v0.nullifiers); + store_nullifiers_for_block(&mut ops, &v0.notes); Ok(ops) } diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs index 0c4bd58338c..1c3860384a0 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/shielded_withdrawal_transition.rs @@ -27,15 +27,10 @@ impl DriveHighLevelOperationConverter for ShieldedWithdrawalTransitionAction { let mut ops: Vec> = Vec::new(); // 1. Insert nullifiers (prevent double-spend) - insert_nullifiers(&mut ops, &v0.nullifiers); + insert_nullifiers(&mut ops, &v0.notes); // 2. Insert change notes into CommitmentTree - insert_notes( - &mut ops, - &v0.nullifiers, - &v0.note_commitments, - &v0.encrypted_notes, - ); + insert_notes(&mut ops, &v0.notes); // 3. Update total balance: subtract withdrawal amount + fee (both leave the pool) let total_deduction = @@ -75,7 +70,7 @@ impl DriveHighLevelOperationConverter for ShieldedWithdrawalTransitionAction { )); // 6. Store nullifiers to recent block storage for catch-up sync - store_nullifiers_for_block(&mut ops, &v0.nullifiers); + store_nullifiers_for_block(&mut ops, &v0.notes); Ok(ops) } diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs index ed4c00ba2bc..a40a7cac0bf 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/unshield_transition.rs @@ -26,7 +26,7 @@ impl DriveHighLevelOperationConverter for UnshieldTransitionAction { let mut ops: Vec> = Vec::new(); // 1. Insert each nullifier (InsertOnly to prevent double-spend) - insert_nullifiers(&mut ops, &v0.nullifiers); + insert_nullifiers(&mut ops, &v0.notes); // 2. Credit the output address with the unshielded amount ops.push(DriveOperation::AddressFundsOperation( @@ -37,12 +37,7 @@ impl DriveHighLevelOperationConverter for UnshieldTransitionAction { )); // 3. Insert notes into CommitmentTree (change outputs) - insert_notes( - &mut ops, - &v0.nullifiers, - &v0.note_commitments, - &v0.encrypted_notes, - ); + insert_notes(&mut ops, &v0.notes); // 4. Update total balance // Pool decreases by amount (to output address) + fee_amount (to proposers) @@ -64,7 +59,7 @@ impl DriveHighLevelOperationConverter for UnshieldTransitionAction { update_balance(&mut ops, new_total_balance); // 5. Store nullifiers to recent block storage for catch-up sync - store_nullifiers_for_block(&mut ops, &v0.nullifiers); + store_nullifiers_for_block(&mut ops, &v0.notes); Ok(ops) } diff --git a/packages/rs-drive/src/state_transition_action/shielded/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/mod.rs index b28bf298a38..3c4be746467 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/mod.rs @@ -8,3 +8,14 @@ pub mod shielded_transfer; pub mod shielded_withdrawal; /// Unshield transition action pub mod unshield; + +/// One note from an Orchard action: the three per-action fields that travel together. +#[derive(Debug, Clone)] +pub struct ShieldedActionNote { + /// Nullifier (needed for Rho derivation in trial decryption) + pub nullifier: [u8; 32], + /// Note commitment (cmx value) + pub cmx: [u8; 32], + /// Encrypted note ciphertext + pub encrypted_note: Vec, +} diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/mod.rs index d7ab7f7b1dd..4e66570167d 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/mod.rs @@ -4,6 +4,7 @@ pub mod transformer; pub mod v0; use crate::state_transition_action::shielded::shield::v0::ShieldTransitionActionV0; +use crate::state_transition_action::shielded::ShieldedActionNote; use derive_more::From; use dpp::address_funds::{AddressFundsFeeStrategy, PlatformAddress}; use dpp::fee::Credits; @@ -32,16 +33,10 @@ impl ShieldTransitionAction { ShieldTransitionAction::V0(transition) => transition.shield_amount, } } - /// Get note commitments - pub fn note_commitments(&self) -> &[[u8; 32]] { + /// Get notes + pub fn notes(&self) -> &[ShieldedActionNote] { match self { - ShieldTransitionAction::V0(transition) => &transition.note_commitments, - } - } - /// Get encrypted notes - pub fn encrypted_notes(&self) -> &[Vec] { - match self { - ShieldTransitionAction::V0(transition) => &transition.encrypted_notes, + ShieldTransitionAction::V0(transition) => &transition.notes, } } /// fee multiplier diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs index 92ea7a81698..be833da00d7 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/transformer.rs @@ -1,5 +1,6 @@ use crate::state_transition_action::shielded::shield::v0::ShieldTransitionActionV0; use crate::state_transition_action::shielded::shield::ShieldTransitionAction; +use crate::state_transition_action::shielded::ShieldedActionNote; use dpp::address_funds::PlatformAddress; use dpp::fee::Credits; use dpp::prelude::{AddressNonce, ConsensusValidationResult}; @@ -12,9 +13,7 @@ impl ShieldTransitionAction { value: &ShieldTransition, inputs_with_remaining_balance: BTreeMap, shield_amount: Credits, - nullifiers: Vec<[u8; 32]>, - note_commitments: Vec<[u8; 32]>, - encrypted_notes: Vec>, + notes: Vec, current_total_balance: Credits, ) -> ConsensusValidationResult { match value { @@ -23,9 +22,7 @@ impl ShieldTransitionAction { v0, inputs_with_remaining_balance, shield_amount, - nullifiers, - note_commitments, - encrypted_notes, + notes, current_total_balance, ); result.map(|action| action.into()) diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs index 922bfa6f480..b4802fe6436 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/mod.rs @@ -1,5 +1,6 @@ mod transformer; +use crate::state_transition_action::shielded::ShieldedActionNote; use dpp::address_funds::{AddressFundsFeeStrategy, PlatformAddress}; use dpp::fee::Credits; use dpp::prelude::{AddressNonce, UserFeeIncrease}; @@ -12,12 +13,8 @@ pub struct ShieldTransitionActionV0 { pub inputs_with_remaining_balance: BTreeMap, /// The amount being shielded (sent into the shielded pool) pub shield_amount: Credits, - /// Nullifiers from the orchard bundle actions (needed for Rho derivation in trial decryption) - pub nullifiers: Vec<[u8; 32]>, - /// Note commitments from the orchard bundle (cmx values) - pub note_commitments: Vec<[u8; 32]>, - /// Encrypted notes from the orchard bundle - pub encrypted_notes: Vec>, + /// Notes from the orchard bundle actions + pub notes: Vec, /// fee strategy pub fee_strategy: AddressFundsFeeStrategy, /// fee multiplier diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs index 826a9eddd8c..2a9f5bbab2d 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield/v0/transformer.rs @@ -1,4 +1,5 @@ use crate::state_transition_action::shielded::shield::v0::ShieldTransitionActionV0; +use crate::state_transition_action::shielded::ShieldedActionNote; use dpp::address_funds::PlatformAddress; use dpp::fee::Credits; use dpp::prelude::{AddressNonce, ConsensusValidationResult}; @@ -11,17 +12,13 @@ impl ShieldTransitionActionV0 { value: &ShieldTransitionV0, inputs_with_remaining_balance: BTreeMap, shield_amount: Credits, - nullifiers: Vec<[u8; 32]>, - note_commitments: Vec<[u8; 32]>, - encrypted_notes: Vec>, + notes: Vec, current_total_balance: Credits, ) -> ConsensusValidationResult { ConsensusValidationResult::new_with_data(ShieldTransitionActionV0 { inputs_with_remaining_balance, shield_amount, - nullifiers, - note_commitments, - encrypted_notes, + notes, fee_strategy: value.fee_strategy.clone(), user_fee_increase: value.user_fee_increase, current_total_balance, diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/mod.rs index dfd3e7d93e6..66beba24008 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/mod.rs @@ -4,6 +4,7 @@ pub mod transformer; pub mod v0; use crate::state_transition_action::shielded::shield_from_asset_lock::v0::ShieldFromAssetLockTransitionActionV0; +use crate::state_transition_action::shielded::ShieldedActionNote; use derive_more::From; use dpp::fee::Credits; use dpp::prelude::UserFeeIncrease; @@ -44,16 +45,10 @@ impl ShieldFromAssetLockTransitionAction { ShieldFromAssetLockTransitionAction::V0(transition) => transition.shield_amount, } } - /// Get note commitments - pub fn note_commitments(&self) -> &[[u8; 32]] { + /// Get notes + pub fn notes(&self) -> &[ShieldedActionNote] { match self { - ShieldFromAssetLockTransitionAction::V0(transition) => &transition.note_commitments, - } - } - /// Get encrypted notes - pub fn encrypted_notes(&self) -> &[Vec] { - match self { - ShieldFromAssetLockTransitionAction::V0(transition) => &transition.encrypted_notes, + ShieldFromAssetLockTransitionAction::V0(transition) => &transition.notes, } } /// fee multiplier diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/transformer.rs index 749254c2218..0cec6e308c1 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/transformer.rs @@ -1,5 +1,6 @@ use crate::state_transition_action::shielded::shield_from_asset_lock::v0::ShieldFromAssetLockTransitionActionV0; use crate::state_transition_action::shielded::shield_from_asset_lock::ShieldFromAssetLockTransitionAction; +use crate::state_transition_action::shielded::ShieldedActionNote; use dpp::fee::Credits; use dpp::prelude::ConsensusValidationResult; use dpp::state_transition::shield_from_asset_lock_transition::ShieldFromAssetLockTransition; @@ -12,9 +13,7 @@ impl ShieldFromAssetLockTransitionAction { asset_lock_value_to_be_consumed: Credits, signable_bytes_hasher: [u8; 32], shield_amount: Credits, - nullifiers: Vec<[u8; 32]>, - note_commitments: Vec<[u8; 32]>, - encrypted_notes: Vec>, + notes: Vec, current_total_balance: Credits, ) -> ConsensusValidationResult { match value { @@ -25,9 +24,7 @@ impl ShieldFromAssetLockTransitionAction { asset_lock_value_to_be_consumed, signable_bytes_hasher, shield_amount, - nullifiers, - note_commitments, - encrypted_notes, + notes, current_total_balance, ); result.map(|action| action.into()) diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/mod.rs index cfcb230d0e6..62ed2ce39a2 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/mod.rs @@ -1,5 +1,6 @@ mod transformer; +use crate::state_transition_action::shielded::ShieldedActionNote; use dpp::fee::Credits; use dpp::prelude::UserFeeIncrease; @@ -14,12 +15,8 @@ pub struct ShieldFromAssetLockTransitionActionV0 { pub signable_bytes_hasher: [u8; 32], /// Amount going into shielded pool (|value_balance|) pub shield_amount: Credits, - /// Nullifiers from the orchard bundle actions (needed for Rho derivation in trial decryption) - pub nullifiers: Vec<[u8; 32]>, - /// Note commitments from the orchard bundle (cmx values) - pub note_commitments: Vec<[u8; 32]>, - /// Encrypted notes from the orchard bundle - pub encrypted_notes: Vec>, + /// Notes from the orchard bundle actions + pub notes: Vec, /// fee multiplier pub user_fee_increase: UserFeeIncrease, /// Current total balance of the shielded pool diff --git a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/transformer.rs index 4e28e84cb32..1f62c435184 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shield_from_asset_lock/v0/transformer.rs @@ -1,4 +1,5 @@ use crate::state_transition_action::shielded::shield_from_asset_lock::v0::ShieldFromAssetLockTransitionActionV0; +use crate::state_transition_action::shielded::ShieldedActionNote; use dpp::fee::Credits; use dpp::prelude::ConsensusValidationResult; use dpp::state_transition::state_transitions::shielded::shield_from_asset_lock_transition::v0::ShieldFromAssetLockTransitionV0; @@ -11,9 +12,7 @@ impl ShieldFromAssetLockTransitionActionV0 { asset_lock_value_to_be_consumed: Credits, signable_bytes_hasher: [u8; 32], shield_amount: Credits, - nullifiers: Vec<[u8; 32]>, - note_commitments: Vec<[u8; 32]>, - encrypted_notes: Vec>, + notes: Vec, current_total_balance: Credits, ) -> ConsensusValidationResult { ConsensusValidationResult::new_with_data(ShieldFromAssetLockTransitionActionV0 { @@ -21,9 +20,7 @@ impl ShieldFromAssetLockTransitionActionV0 { asset_lock_value_to_be_consumed, signable_bytes_hasher, shield_amount, - nullifiers, - note_commitments, - encrypted_notes, + notes, user_fee_increase: value.user_fee_increase, current_total_balance, }) diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/mod.rs index 8972d0e2366..c5430e83d29 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/mod.rs @@ -4,6 +4,7 @@ pub mod transformer; pub mod v0; use crate::state_transition_action::shielded::shielded_transfer::v0::ShieldedTransferTransitionActionV0; +use crate::state_transition_action::shielded::ShieldedActionNote; use derive_more::From; use dpp::fee::Credits; @@ -15,22 +16,10 @@ pub enum ShieldedTransferTransitionAction { } impl ShieldedTransferTransitionAction { - /// Get nullifiers - pub fn nullifiers(&self) -> &[[u8; 32]] { + /// Get notes + pub fn notes(&self) -> &[ShieldedActionNote] { match self { - ShieldedTransferTransitionAction::V0(transition) => &transition.nullifiers, - } - } - /// Get note commitments - pub fn note_commitments(&self) -> &[[u8; 32]] { - match self { - ShieldedTransferTransitionAction::V0(transition) => &transition.note_commitments, - } - } - /// Get encrypted notes - pub fn encrypted_notes(&self) -> &[Vec] { - match self { - ShieldedTransferTransitionAction::V0(transition) => &transition.encrypted_notes, + ShieldedTransferTransitionAction::V0(transition) => &transition.notes, } } /// Get anchor diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/transformer.rs index 9f893364aa1..b1e329e233c 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/transformer.rs @@ -1,5 +1,6 @@ use crate::state_transition_action::shielded::shielded_transfer::v0::ShieldedTransferTransitionActionV0; use crate::state_transition_action::shielded::shielded_transfer::ShieldedTransferTransitionAction; +use crate::state_transition_action::shielded::ShieldedActionNote; use dpp::fee::Credits; use dpp::prelude::ConsensusValidationResult; use dpp::state_transition::shielded_transfer_transition::ShieldedTransferTransition; @@ -8,9 +9,7 @@ impl ShieldedTransferTransitionAction { /// Transforms the state transition into an action pub fn try_from_transition( value: &ShieldedTransferTransition, - nullifiers: Vec<[u8; 32]>, - note_commitments: Vec<[u8; 32]>, - encrypted_notes: Vec>, + notes: Vec, anchor: [u8; 32], fee_amount: Credits, current_total_balance: Credits, @@ -19,9 +18,7 @@ impl ShieldedTransferTransitionAction { ShieldedTransferTransition::V0(v0) => { let result = ShieldedTransferTransitionActionV0::try_from_transition( v0, - nullifiers, - note_commitments, - encrypted_notes, + notes, anchor, fee_amount, current_total_balance, diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs index d3ef8cd05f9..1c26ed90f05 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/mod.rs @@ -1,16 +1,13 @@ mod transformer; +use crate::state_transition_action::shielded::ShieldedActionNote; use dpp::fee::Credits; /// Shielded transfer transition action v0 #[derive(Debug, Clone)] pub struct ShieldedTransferTransitionActionV0 { - /// Nullifiers from spent notes - pub nullifiers: Vec<[u8; 32]>, - /// Note commitments for new output notes - pub note_commitments: Vec<[u8; 32]>, - /// Encrypted notes for new output notes - pub encrypted_notes: Vec>, + /// Notes from the orchard bundle actions + pub notes: Vec, /// The anchor (root of the commitment tree) used for verification pub anchor: [u8; 32], /// Fee amount extracted from the value balance diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs index 482c9de6de2..b4c356d8bec 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_transfer/v0/transformer.rs @@ -1,4 +1,5 @@ use crate::state_transition_action::shielded::shielded_transfer::v0::ShieldedTransferTransitionActionV0; +use crate::state_transition_action::shielded::ShieldedActionNote; use dpp::fee::Credits; use dpp::prelude::ConsensusValidationResult; use dpp::state_transition::state_transitions::shielded::shielded_transfer_transition::v0::ShieldedTransferTransitionV0; @@ -7,17 +8,13 @@ impl ShieldedTransferTransitionActionV0 { /// Transforms the shielded transfer transition into an action pub fn try_from_transition( _value: &ShieldedTransferTransitionV0, - nullifiers: Vec<[u8; 32]>, - note_commitments: Vec<[u8; 32]>, - encrypted_notes: Vec>, + notes: Vec, anchor: [u8; 32], fee_amount: Credits, current_total_balance: Credits, ) -> ConsensusValidationResult { ConsensusValidationResult::new_with_data(ShieldedTransferTransitionActionV0 { - nullifiers, - note_commitments, - encrypted_notes, + notes, anchor, fee_amount, current_total_balance, diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/mod.rs index 61fdeaf61b0..fbe4a5782b4 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/mod.rs @@ -4,6 +4,7 @@ pub mod transformer; pub mod v0; use crate::state_transition_action::shielded::shielded_withdrawal::v0::ShieldedWithdrawalTransitionActionV0; +use crate::state_transition_action::shielded::ShieldedActionNote; use derive_more::From; use dpp::document::Document; use dpp::fee::Credits; @@ -24,22 +25,10 @@ impl ShieldedWithdrawalTransitionAction { ShieldedWithdrawalTransitionAction::V0(transition) => transition.amount, } } - /// Get nullifiers - pub fn nullifiers(&self) -> &[[u8; 32]] { + /// Get notes + pub fn notes(&self) -> &[ShieldedActionNote] { match self { - ShieldedWithdrawalTransitionAction::V0(transition) => &transition.nullifiers, - } - } - /// Get note commitments - pub fn note_commitments(&self) -> &[[u8; 32]] { - match self { - ShieldedWithdrawalTransitionAction::V0(transition) => &transition.note_commitments, - } - } - /// Get encrypted notes - pub fn encrypted_notes(&self) -> &[Vec] { - match self { - ShieldedWithdrawalTransitionAction::V0(transition) => &transition.encrypted_notes, + ShieldedWithdrawalTransitionAction::V0(transition) => &transition.notes, } } /// Get anchor diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/transformer.rs index e20d74f59cd..7048f97ebda 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/transformer.rs @@ -1,5 +1,6 @@ use crate::state_transition_action::shielded::shielded_withdrawal::v0::ShieldedWithdrawalTransitionActionV0; use crate::state_transition_action::shielded::shielded_withdrawal::ShieldedWithdrawalTransitionAction; +use crate::state_transition_action::shielded::ShieldedActionNote; use dpp::fee::Credits; use dpp::prelude::ConsensusValidationResult; use dpp::state_transition::shielded_withdrawal_transition::ShieldedWithdrawalTransition; @@ -8,9 +9,7 @@ impl ShieldedWithdrawalTransitionAction { /// Transforms the state transition into an action pub fn try_from_transition( value: &ShieldedWithdrawalTransition, - nullifiers: Vec<[u8; 32]>, - note_commitments: Vec<[u8; 32]>, - encrypted_notes: Vec>, + notes: Vec, anchor: [u8; 32], current_total_balance: Credits, creation_time_ms: u64, @@ -19,9 +18,7 @@ impl ShieldedWithdrawalTransitionAction { ShieldedWithdrawalTransition::V0(v0) => { let result = ShieldedWithdrawalTransitionActionV0::try_from_transition( v0, - nullifiers, - note_commitments, - encrypted_notes, + notes, anchor, current_total_balance, creation_time_ms, diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/mod.rs index f865b15d31c..9ff494ca7f1 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/mod.rs @@ -1,5 +1,6 @@ mod transformer; +use crate::state_transition_action::shielded::ShieldedActionNote; use dpp::document::Document; use dpp::fee::Credits; use dpp::identity::core_script::CoreScript; @@ -10,12 +11,8 @@ use dpp::withdrawal::Pooling; pub struct ShieldedWithdrawalTransitionActionV0 { /// Withdrawal amount in credits pub amount: Credits, - /// Nullifiers from spent notes - pub nullifiers: Vec<[u8; 32]>, - /// Note commitments for change outputs - pub note_commitments: Vec<[u8; 32]>, - /// Encrypted change notes - pub encrypted_notes: Vec>, + /// Notes from the orchard bundle actions + pub notes: Vec, /// Merkle root used for spends pub anchor: [u8; 32], /// Core transaction fee rate diff --git a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/transformer.rs index 15e0d18e1c2..c03ac69a797 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/shielded_withdrawal/v0/transformer.rs @@ -1,4 +1,5 @@ use crate::state_transition_action::shielded::shielded_withdrawal::v0::ShieldedWithdrawalTransitionActionV0; +use crate::state_transition_action::shielded::ShieldedActionNote; use dpp::data_contracts::withdrawals_contract; use dpp::data_contracts::withdrawals_contract::v1::document_types::withdrawal; use dpp::document::{Document, DocumentV0}; @@ -11,17 +12,15 @@ impl ShieldedWithdrawalTransitionActionV0 { /// Transforms the shielded withdrawal transition into an action pub fn try_from_transition( value: &ShieldedWithdrawalTransitionV0, - nullifiers: Vec<[u8; 32]>, - note_commitments: Vec<[u8; 32]>, - encrypted_notes: Vec>, + notes: Vec, anchor: [u8; 32], current_total_balance: Credits, creation_time_ms: u64, ) -> ConsensusValidationResult { // Generate entropy from first nullifier + output_script for document ID let mut entropy = Vec::new(); - if let Some(first_nullifier) = nullifiers.first() { - entropy.extend_from_slice(first_nullifier); + if let Some(first_note) = notes.first() { + entropy.extend_from_slice(&first_note.nullifier); } entropy.extend_from_slice(value.output_script.as_bytes()); @@ -68,9 +67,7 @@ impl ShieldedWithdrawalTransitionActionV0 { ConsensusValidationResult::new_with_data(ShieldedWithdrawalTransitionActionV0 { amount: value.amount, - nullifiers, - note_commitments, - encrypted_notes, + notes, anchor, core_fee_per_byte: value.core_fee_per_byte, pooling: value.pooling, diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/mod.rs index 84ad9d9d6d9..c84a9e065f8 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/unshield/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/mod.rs @@ -4,6 +4,7 @@ pub mod transformer; pub mod v0; use crate::state_transition_action::shielded::unshield::v0::UnshieldTransitionActionV0; +use crate::state_transition_action::shielded::ShieldedActionNote; use derive_more::From; use dpp::address_funds::PlatformAddress; use dpp::fee::Credits; @@ -28,22 +29,10 @@ impl UnshieldTransitionAction { UnshieldTransitionAction::V0(transition) => transition.amount, } } - /// Get nullifiers - pub fn nullifiers(&self) -> &[[u8; 32]] { + /// Get notes + pub fn notes(&self) -> &[ShieldedActionNote] { match self { - UnshieldTransitionAction::V0(transition) => &transition.nullifiers, - } - } - /// Get note commitments - pub fn note_commitments(&self) -> &[[u8; 32]] { - match self { - UnshieldTransitionAction::V0(transition) => &transition.note_commitments, - } - } - /// Get encrypted notes - pub fn encrypted_notes(&self) -> &[Vec] { - match self { - UnshieldTransitionAction::V0(transition) => &transition.encrypted_notes, + UnshieldTransitionAction::V0(transition) => &transition.notes, } } /// Get anchor diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/transformer.rs index 228658f03a3..5984e3216d1 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/unshield/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/transformer.rs @@ -1,5 +1,6 @@ use crate::state_transition_action::shielded::unshield::v0::UnshieldTransitionActionV0; use crate::state_transition_action::shielded::unshield::UnshieldTransitionAction; +use crate::state_transition_action::shielded::ShieldedActionNote; use dpp::fee::Credits; use dpp::prelude::ConsensusValidationResult; use dpp::state_transition::unshield_transition::UnshieldTransition; @@ -8,9 +9,7 @@ impl UnshieldTransitionAction { /// Transforms the state transition into an action pub fn try_from_transition( value: &UnshieldTransition, - nullifiers: Vec<[u8; 32]>, - note_commitments: Vec<[u8; 32]>, - encrypted_notes: Vec>, + notes: Vec, anchor: [u8; 32], current_total_balance: Credits, ) -> ConsensusValidationResult { @@ -18,9 +17,7 @@ impl UnshieldTransitionAction { UnshieldTransition::V0(v0) => { let result = UnshieldTransitionActionV0::try_from_transition( v0, - nullifiers, - note_commitments, - encrypted_notes, + notes, anchor, current_total_balance, ); diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs index c1d4b3f6a1a..bb9b113dd74 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/mod.rs @@ -1,5 +1,6 @@ mod transformer; +use crate::state_transition_action::shielded::ShieldedActionNote; use dpp::address_funds::PlatformAddress; use dpp::fee::Credits; @@ -10,12 +11,8 @@ pub struct UnshieldTransitionActionV0 { pub output_address: PlatformAddress, /// Amount being unshielded pub amount: Credits, - /// Nullifiers from spent notes - pub nullifiers: Vec<[u8; 32]>, - /// Note commitments for change outputs - pub note_commitments: Vec<[u8; 32]>, - /// Encrypted notes for change outputs - pub encrypted_notes: Vec>, + /// Notes from the orchard bundle actions + pub notes: Vec, /// The anchor used for verification pub anchor: [u8; 32], /// Fee amount (value_balance - amount), paid to proposers diff --git a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs index 2465ae299b3..b8c9eeca7ec 100644 --- a/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs +++ b/packages/rs-drive/src/state_transition_action/shielded/unshield/v0/transformer.rs @@ -1,4 +1,5 @@ use crate::state_transition_action::shielded::unshield::v0::UnshieldTransitionActionV0; +use crate::state_transition_action::shielded::ShieldedActionNote; use dpp::fee::Credits; use dpp::prelude::ConsensusValidationResult; use dpp::state_transition::state_transitions::shielded::unshield_transition::v0::UnshieldTransitionV0; @@ -7,9 +8,7 @@ impl UnshieldTransitionActionV0 { /// Transforms the unshield transition into an action pub fn try_from_transition( value: &UnshieldTransitionV0, - nullifiers: Vec<[u8; 32]>, - note_commitments: Vec<[u8; 32]>, - encrypted_notes: Vec>, + notes: Vec, anchor: [u8; 32], current_total_balance: Credits, ) -> ConsensusValidationResult { @@ -19,9 +18,7 @@ impl UnshieldTransitionActionV0 { ConsensusValidationResult::new_with_data(UnshieldTransitionActionV0 { output_address: value.output_address.clone(), amount: value.amount, - nullifiers, - note_commitments, - encrypted_notes, + notes, anchor, fee_amount, current_total_balance, From eacf972c0116ba9fdb984d44c2f3f225af7cb83c Mon Sep 17 00:00:00 2001 From: Quantum Explorer Date: Thu, 26 Feb 2026 08:03:54 +0700 Subject: [PATCH 40/40] more work --- .../shielded_withdrawal/tests.rs | 64 +++++++++---------- .../state_transitions/unshield/tests.rs | 53 ++++++++------- .../shielded/mod.rs | 5 +- 3 files changed, 59 insertions(+), 63 deletions(-) diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs index 4fb7d0ecf55..ec2eca733e8 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/shielded_withdrawal/tests.rs @@ -66,7 +66,7 @@ mod tests { 1000, // amount in credits vec![create_dummy_serialized_action()], 0x03, // spends_enabled | outputs_enabled - 1000, // value_balance = amount (no fee for simplicity) + 111_549_800, // amount (1000) + minimum fee for 1 action (111_548_800) [42u8; 32], // non-zero anchor vec![0u8; 100], // dummy proof bytes [0u8; 64], // dummy binding signature @@ -471,7 +471,7 @@ mod tests { let recipient = fvk.address_at(0u32, Scope::External); let ask = SpendAuthorizingKey::from(&sk); - // --- Create a spendable note with value 10,000 --- + // --- Create a spendable note with value 500M --- let rho_bytes: [u8; 32] = { let mut b = [0u8; 32]; b[0] = 1; @@ -480,7 +480,7 @@ mod tests { let rho = Rho::from_bytes(&rho_bytes).unwrap(); let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); let note = - Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); + Note::from_parts(recipient, NoteValue::from_raw(500_000_000), rho, rseed).unwrap(); // --- Build commitment tree and get anchor + merkle path --- let cmx = ExtractedNoteCommitment::from(note.commitment()); @@ -490,7 +490,7 @@ mod tests { let anchor = tree.anchor().unwrap(); let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); - // --- Build bundle: spend 10,000 -> output 5,000 (value_balance = 5,000) --- + // --- Build bundle: spend 500M -> output 5K (value_balance = 499,995,000) --- let mut builder = Builder::::new(BundleType::DEFAULT, anchor); builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); builder @@ -501,7 +501,7 @@ mod tests { // Compute platform sighash binding transparent fields (output_script, amount) let output_script = create_output_script(); - let amount = 5_000u64; // = value_balance (no fee difference) + let amount = 5_000u64; let mut extra_sighash_data = output_script.as_bytes().to_vec(); extra_sighash_data.extend_from_slice(&amount.to_le_bytes()); let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); @@ -514,15 +514,15 @@ mod tests { let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = serialize_authorized_bundle(&bundle); - // value_balance should be 5000 (10,000 spent - 5,000 output) - assert_eq!(value_balance, 5_000); + // value_balance should be 499,995,000 (500M spent - 5K output) + assert_eq!(value_balance, 499_995_000); // --- Set up platform state --- // Insert anchor so anchor validation passes insert_anchor_into_state(&platform, &anchor_bytes); // Set pool total balance so the withdrawal has sufficient funds - set_pool_total_balance(&platform, 10_000); + set_pool_total_balance(&platform, 500_000_000); // --- Create and process transition --- let transition = create_shielded_withdrawal_transition( @@ -568,7 +568,7 @@ mod tests { 1000, vec![bad_action], 0x03, - 1000, + 111_549_800, // amount (1000) + minimum fee for 1 action anchor, vec![0u8; 100], [0u8; 64], @@ -667,7 +667,7 @@ mod tests { let rho = Rho::from_bytes(&rho_bytes).unwrap(); let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); let note = - Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); + Note::from_parts(recipient, NoteValue::from_raw(500_000_000), rho, rseed).unwrap(); let cmx = ExtractedNoteCommitment::from(note.commitment()); let mut tree = ClientMemoryCommitmentTree::new(100); @@ -676,7 +676,7 @@ mod tests { let anchor = tree.anchor().unwrap(); let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); - // Spend 10,000 -> output 5,000 -> value_balance = 5,000 + // Spend 500M -> output 5K -> value_balance = 499,995,000 let mut builder = Builder::::new(BundleType::DEFAULT, anchor); builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); builder @@ -748,7 +748,7 @@ mod tests { let (actions, flags, value_balance, anchor_bytes, proof_bytes, _binding_sig) = build_valid_shielded_withdrawal_bundle(&output_script, amount); - set_pool_total_balance(&platform, 20_000); + set_pool_total_balance(&platform, 500_000_000); insert_anchor_into_state(&platform, &anchor_bytes); let transition = create_shielded_withdrawal_transition( @@ -795,20 +795,20 @@ mod tests { let signed_amount = 5_000u64; let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = build_valid_shielded_withdrawal_bundle(&output_script, signed_amount); - assert_eq!(value_balance, 5_000); + assert_eq!(value_balance, 499_995_000); - // ATTACK: Inflate value_balance from 5000 to 9000 - let mutated_value_balance = 9_000i64; + // ATTACK: Inflate value_balance from 499,995,000 to 999,000,000 + let mutated_value_balance = 999_000_000i64; // Set pool balance high enough for the inflated amount - set_pool_total_balance(&platform, 20_000); + set_pool_total_balance(&platform, 1_000_000_000); insert_anchor_into_state(&platform, &anchor_bytes); let transition = create_shielded_withdrawal_transition( - mutated_value_balance as u64, // amount = 9000 (inflated) + 500_000_000, // amount = 500M (inflated from original 5K) actions, flags, - mutated_value_balance, // MUTATED: was 5000, now 9000 + mutated_value_balance, // MUTATED: was 499,995,000, now 999,000,000 anchor_bytes, proof_bytes, binding_sig, @@ -847,9 +847,9 @@ mod tests { let amount = 5_000u64; let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = build_valid_shielded_withdrawal_bundle(&original_script, amount); - assert_eq!(value_balance, 5_000); + assert_eq!(value_balance, 499_995_000); - set_pool_total_balance(&platform, 20_000); + set_pool_total_balance(&platform, 500_000_000); insert_anchor_into_state(&platform, &anchor_bytes); // ATTACK: Use a completely different output script (attacker's address) @@ -897,13 +897,13 @@ mod tests { let signed_amount = 5_000u64; let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = build_valid_shielded_withdrawal_bundle(&output_script, signed_amount); - assert_eq!(value_balance, 5_000); + assert_eq!(value_balance, 499_995_000); - set_pool_total_balance(&platform, 20_000); + set_pool_total_balance(&platform, 500_000_000); insert_anchor_into_state(&platform, &anchor_bytes); - // ATTACK: Use a smaller amount (4000) but same value_balance (5000) - // to pocket the difference as "fee" that goes nowhere + // ATTACK: Use a smaller amount (4000) but same value_balance + // to pocket the difference as extra fee let manipulated_amount = 4_000u64; let transition = create_shielded_withdrawal_transition( @@ -952,7 +952,7 @@ mod tests { 1000, vec![action1, action2], // Both have nullifier [1u8; 32] 0x03, - 1000, + 123_098_600, // amount (1000) + minimum fee for 2 actions (123_097_600) anchor, vec![0u8; 100], [0u8; 64], @@ -1048,7 +1048,7 @@ mod tests { let recipient = fvk.address_at(0u32, Scope::External); let ask = SpendAuthorizingKey::from(&sk); - // --- Create a spendable note with value 10,000 --- + // --- Create a spendable note with value 500M --- let rho_bytes: [u8; 32] = { let mut b = [0u8; 32]; b[0] = 1; @@ -1057,7 +1057,7 @@ mod tests { let rho = Rho::from_bytes(&rho_bytes).unwrap(); let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); let note = - Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); + Note::from_parts(recipient, NoteValue::from_raw(500_000_000), rho, rseed).unwrap(); // --- Build commitment tree and get anchor + merkle path --- let cmx = ExtractedNoteCommitment::from(note.commitment()); @@ -1067,7 +1067,7 @@ mod tests { let anchor = tree.anchor().unwrap(); let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); - // --- Build bundle: spend 10,000 -> output 5,000 (value_balance = 5,000) --- + // --- Build bundle: spend 500M -> output 5K (value_balance = 499,995,000) --- let mut builder = Builder::::new(BundleType::DEFAULT, anchor); builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); builder @@ -1078,7 +1078,7 @@ mod tests { // Compute platform sighash binding transparent fields (output_script, amount) let output_script = create_output_script(); - let amount = 5_000u64; // = value_balance (no fee difference) + let amount = 5_000u64; let mut extra_sighash_data = output_script.as_bytes().to_vec(); extra_sighash_data.extend_from_slice(&amount.to_le_bytes()); let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); @@ -1091,12 +1091,12 @@ mod tests { let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = serialize_authorized_bundle(&bundle); - // value_balance should be 5000 (10,000 spent - 5,000 output) - assert_eq!(value_balance, 5_000); + // value_balance should be 499,995,000 (500M spent - 5K output) + assert_eq!(value_balance, 499_995_000); // --- Set up platform state --- insert_anchor_into_state(&platform, &anchor_bytes); - set_pool_total_balance(&platform, 500_000); + set_pool_total_balance(&platform, 500_000_000); // --- Create and process transition --- let transition = create_shielded_withdrawal_transition( diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs index 30aba5d5d02..def9d41a928 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/unshield/tests.rs @@ -61,7 +61,7 @@ mod tests { 1000, // amount being unshielded vec![create_dummy_serialized_action()], 0x03, // spends_enabled | outputs_enabled - 1000, // value_balance = amount (no fee for simplicity) + 111_549_800, // amount (1000) + minimum fee for 1 action (111_548_800) [42u8; 32], // non-zero anchor vec![0u8; 100], // dummy proof bytes [0u8; 64], // dummy binding signature @@ -437,7 +437,7 @@ mod tests { let recipient = fvk.address_at(0u32, Scope::External); let ask = SpendAuthorizingKey::from(&sk); - // --- Create a spendable note with value 10,000 --- + // --- Create a spendable note with value 500M --- let rho_bytes: [u8; 32] = { let mut b = [0u8; 32]; b[0] = 1; @@ -446,7 +446,7 @@ mod tests { let rho = Rho::from_bytes(&rho_bytes).unwrap(); let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); let note = - Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); + Note::from_parts(recipient, NoteValue::from_raw(500_000_000), rho, rseed).unwrap(); // --- Build commitment tree and get anchor + merkle path --- let cmx = ExtractedNoteCommitment::from(note.commitment()); @@ -456,7 +456,7 @@ mod tests { let anchor = tree.anchor().unwrap(); let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); - // --- Build bundle: spend 10,000 → output 5,000 (value_balance = 5,000) --- + // --- Build bundle: spend 500M → output 5K (value_balance = 499,995,000) --- let mut builder = Builder::::new(BundleType::DEFAULT, anchor); builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); builder @@ -467,7 +467,7 @@ mod tests { // Compute platform sighash binding transparent fields (output_address, amount) let output_address = create_output_address(); - let amount = 5_000u64; // = value_balance (no fee difference) + let amount = 5_000u64; let mut extra_sighash_data = output_address.to_bytes(); extra_sighash_data.extend_from_slice(&amount.to_le_bytes()); let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); @@ -480,18 +480,17 @@ mod tests { let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = serialize_authorized_bundle(&bundle); - // value_balance should be 5000 (10,000 spent - 5,000 output) - assert_eq!(value_balance, 5_000); + // value_balance should be 499,995,000 (500M spent - 5K output) + assert_eq!(value_balance, 499_995_000); // --- Set up platform state --- // Insert anchor so anchor validation passes insert_anchor_into_state(&platform, &anchor_bytes); // Set pool total balance so the unshield has sufficient funds - set_pool_total_balance(&platform, 10_000); + set_pool_total_balance(&platform, 500_000_000); // --- Create and process transition --- - // amount = value_balance (no fee difference) let transition = create_unshield_transition( output_address, amount, // amount = 5000 @@ -531,7 +530,7 @@ mod tests { 1000, vec![bad_action], 0x03, - 1000, + 111_549_800, // amount (1000) + minimum fee for 1 action anchor, vec![0u8; 100], [0u8; 64], @@ -622,7 +621,7 @@ mod tests { let rho = Rho::from_bytes(&rho_bytes).unwrap(); let rseed = RandomSeed::from_bytes([42u8; 32], &rho).unwrap(); let note = - Note::from_parts(recipient, NoteValue::from_raw(10_000), rho, rseed).unwrap(); + Note::from_parts(recipient, NoteValue::from_raw(500_000_000), rho, rseed).unwrap(); let cmx = ExtractedNoteCommitment::from(note.commitment()); let mut tree = ClientMemoryCommitmentTree::new(100); @@ -631,7 +630,7 @@ mod tests { let anchor = tree.anchor().unwrap(); let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); - // Spend 10,000 → output 5,000 → value_balance = 5,000 + // Spend 500M → output 5K → value_balance = 499,995,000 let mut builder = Builder::::new(BundleType::DEFAULT, anchor); builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); builder @@ -672,21 +671,21 @@ mod tests { let signed_amount = 5_000u64; let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = build_valid_unshield_bundle(&output_address, signed_amount); - assert_eq!(value_balance, 5_000); + assert_eq!(value_balance, 499_995_000); - // ATTACK: Inflate value_balance from 5000 to 9000 - let mutated_value_balance = 9_000i64; + // ATTACK: Inflate value_balance from 499,995,000 to 999,000,000 + let mutated_value_balance = 999_000_000i64; // Set pool balance high enough for the inflated amount - set_pool_total_balance(&platform, 20_000); + set_pool_total_balance(&platform, 1_000_000_000); insert_anchor_into_state(&platform, &anchor_bytes); let transition = create_unshield_transition( output_address, - mutated_value_balance as u64, // amount = 9000 (inflated) + 500_000_000, // amount = 500M (inflated from original 5K) actions, flags, - mutated_value_balance, // MUTATED: was 5000, now 9000 + mutated_value_balance, // MUTATED: was 499,995,000, now 999,000,000 anchor_bytes, proof_bytes, binding_sig, @@ -723,9 +722,9 @@ mod tests { let amount = 5_000u64; let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = build_valid_unshield_bundle(&original_address, amount); - assert_eq!(value_balance, 5_000); + assert_eq!(value_balance, 499_995_000); - set_pool_total_balance(&platform, 20_000); + set_pool_total_balance(&platform, 500_000_000); insert_anchor_into_state(&platform, &anchor_bytes); // ATTACK: Use a completely different output address @@ -777,7 +776,7 @@ mod tests { 1000, vec![action1, action2], // Both have nullifier [1u8; 32] 0x03, - 1000, + 123_098_600, // amount (1000) + minimum fee for 2 actions (123_097_600) anchor, vec![0u8; 100], [0u8; 64], @@ -859,7 +858,7 @@ mod tests { let mut rng = OsRng; let pk = get_proving_key(); - let spend_amount = 10_000u64; + let spend_amount = 500_000_000u64; let output_amount = 5_000u64; // --- Create keys --- @@ -887,7 +886,7 @@ mod tests { let anchor = tree.anchor().unwrap(); let merkle_path = tree.witness(Position::from(0u64), 0).unwrap().unwrap(); - // --- Build bundle: spend 10,000 -> output 5,000 (value_balance = 5,000) --- + // --- Build bundle: spend 500M -> output 5K (value_balance = 499,995,000) --- let mut builder = Builder::::new(BundleType::DEFAULT, anchor); builder.add_spend(fvk.clone(), note, merkle_path).unwrap(); builder @@ -903,7 +902,7 @@ mod tests { // Compute platform sighash binding transparent fields (output_address, amount) let output_address = create_output_address(); - let amount = 5_000u64; // = value_balance (no fee difference) + let amount = 5_000u64; let mut extra_sighash_data = output_address.to_bytes(); extra_sighash_data.extend_from_slice(&amount.to_le_bytes()); let bundle_commitment: [u8; 32] = unauthorized.commitment().into(); @@ -916,12 +915,12 @@ mod tests { let (actions, flags, value_balance, anchor_bytes, proof_bytes, binding_sig) = serialize_authorized_bundle(&bundle); - // value_balance should be 5000 (10,000 spent - 5,000 output) - assert_eq!(value_balance, 5_000); + // value_balance should be 499,995,000 (500M spent - 5K output) + assert_eq!(value_balance, 499_995_000); // --- Set up platform state --- insert_anchor_into_state(&platform, &anchor_bytes); - set_pool_total_balance(&platform, 500_000); + set_pool_total_balance(&platform, 500_000_000); // --- Build and serialize the transition --- let transition = create_unshield_transition( diff --git a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs index a5d89eab701..24dba2378bc 100644 --- a/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs +++ b/packages/rs-drive/src/state_transition_action/action_convert_to_operations/shielded/mod.rs @@ -26,10 +26,7 @@ pub(super) fn insert_nullifiers<'a>( /// /// Each action's nullifier is stored alongside the note so light clients can derive /// Rho for trial decryption. -pub(super) fn insert_notes<'a>( - ops: &mut Vec>, - notes: &[ShieldedActionNote], -) { +pub(super) fn insert_notes<'a>(ops: &mut Vec>, notes: &[ShieldedActionNote]) { for note in notes { ops.push(DriveOperation::ShieldedPoolOperation( ShieldedPoolOperationType::InsertNote {

5&p(I1>@G$Bsb6rN71k7f)>svA>VbgV5RRhwFz z^palns$y90gyY6PAH9US{V#scYrj6p%~c`7Ywuz40chL&?>re`(i94 zPbdbKm|3}-fS6I9HN2sU0j$l)tSJR4q$n1Mj*4#;gecOre1xDz^-x?Ii&#?;k|j_0 zOe$$kYl^5e!;D*Dqt@atDQY~w@=0{OSY}w>c`n3{90a`x6=s8vA#9c4!jJWnOs8+4 zaC|{NLuf!h(}a~*FLXBjR(5~1n66`n_+#$~g`?Gfe`m^^p5xdj5cu2Khl9)H3>&(* zrh!E}iO>Y28M)0lH9J!qLJ_jBuw?)@&p>|o=T!!hcXfV#*^f1o7UV!5Y`kYocBmN- zcTgN0P_>A3j{oRLIS9e~=WFNz;+=%(jc7x#wmrqzlHfy=k|6?2IR!9z5CMFq>k7zqQ53sEK*aSiT*QAvSIz-Um( z2uVhE6u2HkNt{Zg6ixrgiicR*Z}5`T^b|z_k=y``86f-W(=&GD57dt$iS%N56Iea% znMiSDnonwnOrm3N%4sCK2$jL`PNu8`G$0ud+K(p8k8J9eHawtSm@vm#UAo2kUvt*Vi;GLKINVW;U2|48{m86=Sj4epab)^#BI~BAN_uu4O z^s$UQD7vl{FiWv>K1*I5p;ENHbd`Z{W`!h?H8!{fJYu7)Pct}$nH1V4nY__e<` z%z&6Uch<)13HHr))v*)S6+1dal;UwVOXfAA^t(rhINZD30dji01IAjI3y^2l7T8g#IKUzzT`I&u!0CWH?Zv)p{$2!uI2IXcMOSnb;y5M0%nJ}Yu)u~a z>~~z`IV0{5($&bf87=@k`t+hMCcQhXpfJzR9jz4F8NS?G3%S92U_CAY+O3Md8OGOdR@% zclH9`E>>SWIrExYfX+0IByef3?uUwoz^%1kyQWSvNVFd}gX5&U2L*8xoCHkNf~K!( z7V(XR(RI=;V-j*&H6``{zFuqIU6UCuT7X{DNRVZAf_2@&haSE8a2l+%NIc)@l*0I? z%YYl#g8g>amnRpAr`zfoT8WYXfXly&=t2%_w{VkieHQBn&g`YdIyM~9wuZmg1BSj{ z+?c|NwkJq1f^BOr7gz|*=t-wZ3hTBw?8hrki`~2xRBJDnfq_ciZc z{+;z$CkX*rMqxm_6)xzwLrPtk@r=RZB%hq2mW^wz0XZEU6q??^+ySK)|36Wr9d)?myqdTzX0)#5+{#tCTFNn&z7AWN2G*b5k#p! zP(&n#yKK==O~YF{E{B%a7gWZ(y7&^9=eT(F_2sFN-dkYOGTU#kMj3+(wkUns^odEu zlmb3CwyA2whO6I$$^)=UO=zpEPgmn2H6anC@CA8H9Ue z0^#Ub0z6Az&*EU~90w7*_l1G~Y144)T@;y}YcT6_#RNSa^ASOh`X`v z=_xmkx>M?$w`D%3G%;``DY8^Fu)c+;#;>CbFaFK|>d*Y*%9v>(jZ`2Ij2n>RC)o@$ z7u+RT1HbXWi?e$9r*+=SYsjjB(vttmWAe{37vi{T%t__wCs%GbEAc4-1EsT!3Ysgm z@+z!nD~e+6>CgzI_TAkVX;$mq@ZLMc7gx!TpPw&Nd!tc4D=>Q)8iJ*^%Zr@a9|&Y9 zGub0_0@Bj_;Y=>TNg9D?dn^9G9lcrerg2#B?*mikjybJUJS6zA2QCm9VDu-XKdOf; z<)8~qx1(W&YCN2m3XyRCs>6cF-~Aaor!M}G!umvWzDc_BS~RE4@sR2<00$=tWJRiO z8YeGOb=&o6fa|evIIS)ApLZkRuQL{+*hVMJ8VmhZQDp^1Ywh1zGzbkcWDISof2*gt zT%nNfff7X74iuxmuUlS;x&T|A>w~yfhmfuqydfc@%mtyLE5#4JueC$mT1sRjDSa!; zX2tG-pIIH8p90>(PX-RoR`kBqEv-f*J`qD$PZo(%hqU#jqt^ z&zwGI1fCE>XKgYw0aJOaG8M_V$e#+%kCK|``NJ2SWnI~rGcp6!Q88yqCj@Kl6s|MM z&>gtS{Df0&3DF>8tm1XjuIM~yCQDBzGI4gEYzY%3vpo*jSBNmUDW41W#Q=Zd7-%=> zo?|NbL<$iwt#zm42#&35$bqp}+25fXCe-+EgRxn$0Ewk$(HE@Gjhxc_w0>V+oA}lJ zCaObVn#|WLU3`~11DAd_bl4$nIM9;`?<<24@|xm z05U6kKDIm7uJVPIy*|WaZZv#ncfB%^jNz^CJ8Q+Fy8|ICz4;GW>KvEpii1~lzC0$a zF>GgOvOfCR@TO&t3``Ev+?7iYVtP8l13bKw_BsBTLvuZL=e(S=dr1_%2y2<@W^?H| z)bf$vr+zGvT_|+d4$vWzjWpb2!B8~=8wF2`I<(EoUp+aBCb2u;&$s)>Q-rp*;CbA; zHjukhx!@Dd_BM*L$k*0-4lo?X`87@>YU|#CTfB83)UUoCq0#mem}OqG4pqg^-gkmW*R^iI92$);6{>~$;ANHM9wv`@Kp(E+v|c0q*?M-_a%snGW5w!(7O47h^{picO_}M*U|^P^znMhIBg zh20@nz-05fgZIZT7`1|}7<7(^D74E?8ga`eb9lGVKu~3%&abXnbcChV;&mgOIa=>@ z;Rm9YlW5E1oeKGbflZmi1=??_rgq*l)ry)i#b?C8CR1h$m@e%y(*5t zUYox5l+=@h%R9tU3tBjHalJeV)b7+{-zlHW}B{2Ah@I>962u5ufCGV@f!_Nxfer>tfds1>H~CU zh|yTJknnLw+EwPkJaMEuTRLgpMpZOEB{rvTYoeW31-wg)cpzz~8cpZ$YcEVt&+S|N9!-Dj&t6L}ZO*=6$*PYtbQVAHR5>acGb1@phM*g8 z&9(-_U~GjySq9JP{Mt2*_ft81gfjxtszQ?nj1^CgzSDxG@~CO5J0kwzwx~72A_m(J z%0(cf*j{QD^g|!VxwncJ>=oy!c8(}CIdFjx20qspNtk|yqGdnY|iYs`sna;%Z z&WZ!p7+3UA81IJy^}dE&K&J)Ra}f$HW00@_@wc~) z@IhcVtw+k%;J^cr?D@W)2B_hWC;j__{+;i4!!MxQ_ks8-1>SBpSg2q5<(>W&$0o90 zg)Ab=Kh@@D(~#a)`e+sO2D)up+KBGAFPK+~OaT+Ap&Mbx`4`4`wl!KnU2odhtx zPLOs>PYjQ{wz7Acg^)V+ySB;a?bIC#tLoh#DbdOS{{a2Yn(-a#@busIVd6>vOZVeP zrisf2YRbzz*V?sP73k7SqnHa%pJ6nL-kHFjkJQ-6(pj4!yo60e43NTQEyN&GD?Ts6 z`VsguEf_IbzP2)E=LWtIi^a-q=ZEsTw;eTVi)i#l-oEz4`gI2A{im7pCk}l7VK%brww;Ho^N3?na<27_{ zty-DHavSfzYxwR=KGRhDD~%Jil2Chr9^69s0~Oiap~_E>UT}?3yBsX{qVkJ5N6ldi>h&$*-#YoHNZBKeh)M0|}OVKgXQZpwD+Sfs?;5NSzzE1ECl+hxj zbJWg^<~%dqjOrv&RJ&;#YtHKShjbh^8nj?|avhJ%kY)Y1ieSfzQ+jE__cB|hgy!w0 z+C-;4wEn-Q>r=s-O89US_HLB523|Cgy>*T3hoZVGuWBd9XpS>o=8oMoMw)#}=3IHa z-z&}o3|ZQAT(`shvkma3a(|&Nb)3sxCC6>Py{%gxl&GiO>8;3RW=nj3#!+7*nXCc2Nn443UPsKG%bCvZ`rfz?kQrc+Hs8 z8CxUuYOG8okMPJ9@bCro7DZ?GIv>Kdha9VOPtItXJ+JzFR85)f_2h-n=V+e~!fL4u zcn~swgXeJX=sf_#Ywhg!U>%Uh9ay5J&h|En&UW5CJ6mQz43lt|{e81$)fqfVO0Ss+ zMuBnK^0Yhf=i~gg-{vx|n{5C|&_71Fn_zpQ>kI*h2ic=?iM)sjV77J?Q?dgN25_Sl z+d?PP;~jGY0T)lEGagDr4?H{!?e>EPO?WT~6%Bahz!5k2YZZmDDak~0WjB!*Q)=Y$ zyecq)*wO)qz0&cd|57scBPeFwC+*DXJ-5dWo{rwc?+rKKw>34pQvh8%p%(G+K;dD3Cn6;U=kNoL=%6{^F(yivTewDg{6!8a zb1z$J{3eLT0dMn@j7U6CYHkfi^^pyHO7Pp33EEt1tovl_sVFrQ_61Mj6mq!u1W)Tm<(9PBF0MnqOKH{j zQfDcZq2Ay6LHFH}HGP)jP7i@oiO4@bAP9r=#v#84Wes9H#HV^;Y4N;7HQ$|;c!M{j z6=Fdi)XEPiOI~HL;qxz(No_{{@Y3a*rbk=rE;Ua3h+ou&^q*6B+72@h>KO(fB;6au zaQz!dx(8s^)Sb4f@-?XHjwA3PtC?-5Y%M{9iv^`>l9A>3m4xDkT20Z)aV>tDw)U(> zx=XZ-qPTs{FiMM>4}3l|kn@ZH?pr)1_CgvxnSn~9YlA(ef`$#583EuwzdZ<>J`~jn zf4~X)^BcBOFs-ZQ?%Nu+fUO)^ghFLELP+n zt{e-u$@Xf z&e&~j8=Q%{K`^Qo%u1(RcMYte5jS!{#TqFt#H=~*-}|{rzdj}UW?G`Js7&9 zZlIH+ggq@KPfX;MIOrw?^5L4a9l^J+*P?g_5)tI)0TeVIf<80j)!t$gOPo7?~xw2r=y_s}OCM6*>@%EH&?@N`blc(_1uHk6hj-?(Y z#CbrV-iNi9P>e6ROjQS?afFKLNOgzCAirC7OgARUXmZyftb`!Q>cJY`{2K8Y4m#hp zxXO~Zt%FQ4PoN3Ybu)iwvTeG>S`YcyB6@%$<~X!8@*?laq3Jr!3KZSNYFKMeR9PSN zETqVmq=1!mxn(RqqmShcvCFW>DgXa z+e7^Mgr8wn6~b{KVBKBa{dxU;3%I@IV4rE_9iM+nbKeEbNL>689*S_xoIQcr0ytpC zWHl=}JeYIS6T5VA^ew?h!87-ay2#=LI~Vp5C1s#J#i;2rxv4 zYLxLT@a_1&VCs7rsP}Y^t5k$?EO%`Czgtt3PlWi$6&Cx|^#8lOeeq~kSAY%kX zYoj$+o%v;+Y>#%kx|EWsHq9&1HQOZ6odA9T`4cJQyKHyj&H`t<%dZxxy^xhMDQKVJ zk>O-8GW=^RvfFNFT(P5Bc-+B&Ll0Wu2V3*9;!G@4>TnF6z1yz4^0$i3%m5xOvq?rN z?TmmQW-DD51BW02hv0$fD|?_vX3wqnAGnL=7xxc@jj%Hm(6lO-J3npHF-*w+XTamtf4;Dy>$m$?w@ZAAv#(b)mo1UmX=F4?&(8zE-a`K#4c@PTV|0ltD`l) zKp2Ey{=2<3cm7hF>Ki?Gtwx#biRcks3H~4FR+WzMWtR_3!8TKc+TAZ!4;ki z1Fr3WlR={dc!HX7qj+&RK{>NBiKH%e8@1$E1`WSm?2<-#m`6Tb)J^8rILn9Nb>^yG zL#Cj~aQO$8_7LZ38+o2qnl$-5&Ct3B2j6#HucnTNBj*-tauFxOeBmq)JA21`uNTg8 zs`q26TrG0(+6{$dv}}eZFYlTw!;iGt1*iP&D|eY$9RgfFaDm->8-A#Fnkk{=8AR55 z%~{+PxTd`wTV^d=-_CzdL$^pd|4zEPQ2%7E4bDIeJO_%)*!Xol@j>mDpJ7|jh1C%h zv=(h=MUP+p!o7Z^nbZuqU24Fh`M3D}Ytt*~H;xkX^3#DaK(_-o!VbG}Q%WS$3kVVA zO>N>w544@RNey-U)5>l+C*TIDdVS zwNJz&;5!Ix2Q)n1Y%h-0^?vT()4YAypIUw{|Lk9Wr!nmG9Hz;1`?SG9yOw5i`M%cr zF|55|UYW~UOI$T#+aZwRf^}tC_&6>@lKS}0pqD=3$=P{6!GXtF_3W=ZQ8o-fIQeqr z!pqAuUtfa?VY6y#tT$k#DjzV&9xj1I8^jCG`KpsQ`Uun?wqB8x&4FO7eidl6`eBYz zRJ(9?fq&(mte=JI(Zm^A`hV^M%5)zFB5=nt-v`OL(igK934ayd72a8S#v!uYJ0C}k zxp%kL{*BUQRI_E|*cn=e9H0CJus)jHk6!D1{-mpT$~kO<2MlKk*xp53} z1~HtlP$UE;{TrEs!q^~;13kx*aC!=UfT*`&|C5cW;N**e*Dew zfa-bOA#<8I#VBL!`^zUPPcQ$?Aq9zd|MJ9V@OWJxvqlCN8lcj+9x@sMfpEVfGRH-I za8ZTm+)Pw8)KX`3iC{Ctw%riN-yUJIyXbAOx81ebIi!(;kNSD~?ZXYd`hN2`<|84q z(r3oPIzEw=Hj!ychS5kT?o|E0+R})|d|mmKlFF1yXXLx`5SE<&Sqj07eU=E(iR-3@ zrLM)K*{ki?)OtW2q~>;WT(;{baWt(_7pJc0ujxG2qQ zZVS??<%~GtmcEzZ$7+4g*DVcuOb94-0uB# zF7Kqa-UZl>ymsa`^smkBw?jEuHk4A=vTb*IujCr&lY3z5aGy8vxoil)7(VB$Y zwr$(C-P6;yZQHhO+qP}nwymAF8@+798{DvhQ-9T0oFkG>F1|Cjt{fOU<}C8x1Hi#( z6io#4ROEiY=2Lpkbs7z0)ijQ&Y7?{EyP%tUrJLnOw3)G;#zS zmvi6SzKQW$y$=l6Sknm~;U@CsQn9h&?TMGU@UbwH z9*^zjFlRUi8B4j3Q9`$1D`D;!v0z<>rB!r)@!(nZu`Kh*ZfGie(Cjkee-%e7aA#hzB>p zmuE*h?>pbWT@PX1x10WA^SJ$sFpa-;q*@0PYN0IXP&)EHiJ*_sX0u9d7ZJy#Sv(Lj z4i^(2RhVe4$` zE$z=*EVRXY9Ag(7Bv&%zft0}M0r~Z6TB=m{=_*IJB`;B+n42kwifgPcC0I&&)%bMt zGP|u^zx-D0TL0n@UAT7D1*Ojizr8`S0|vr+Gp12>h-tzXMAhbjw&l!FfVp&#{c^VM zBoX_}e4=Au!#+D)(w<(dMmMRfEz2j$0|e!y_b;dCUbrRgrxk^*lC{#ETpXa4gmj(^ zw7Ar53Cx{Yr?1*##e!o50Oje^1CNWsg=*a;=leTr8zOqUq)(%pu!Lvu#_us@t;zBs zpHbQB_14GG6uybs$sa{}rMVZpnDT!b$cgb45qHKh+04=rJ{nlql7(Rb?#1m;8xx76 z0`*38DnQn=e=T80u4A2$Wh(TIcQEsahpiISRhr)=gtY%Slr|ro`?e}Z)z_fI#5G*J zp^5v2wiR|9@D3)wAUW~Ci*@oW$|02nq5^WgrfuE))lVfit8r@x%y@O7@D7|6E_vo{ z^|jMwYG%E>vb*K=Tpe}11Qtizo))@EC0_Kz@JKc3RYnl0xq5X;tx9?m=)T?Hutj^x zGICn>oX5p&rh6uGR#w+wtrU{v)hpLXy|X4IP!^T!bG0be`-nIg{r9cc5sq|pXH5>! zOm<+(ze!U^g^E+>w~mEkEOzeJoN=CZ(3y5n23^33W^t7kROHi&A)E3L58ZZNBm-;- zIze+xj6Nru9+K!Vp%zS~fabE8X!wUyw9G!40BrloY>lckO`&4rE-+#K&*F!oMjk|rKk`gshbO)?_CEsMld z^@{_y$CAl~i*N@i?@HQ*3UFsJNO}4)ZuG4Sis)k{H`eh5ifN#Hi4YEE#*mC974rPZ zgq@Y_-=;z)9>v(OmcJo}REYC<|AxU~g`9OXh!lOtJZJ|SoIMJo@GM+Wkree;ySi?FerqiA*3-h?%%xBVq** zk~P?@C}BIIw>5c|{@^7XVDm*;pxB#fhZCh%6iEuPmCax}k#?x@CtN`D{aCQr%jkp? zv7t-a=fY28iQ?3#7IJ*H6O4&jXYX8{E{lX)*T#{+o^=o)wjn93gpkhjVqLNpOaZ9L zp*Z!mY|u$-7URdW_b-5*iKA6pn`=HM?!i_zslUg&V^diRl8&uuNnuG#*1J!tEzo_v zEkUHP_&aa+T6QIr;k3^2&W7l8E?ugUa;=EgicMcfC>J_v-)JOJDMuGkvami(C52&y zZ+JHTxv^N1u>IIz4kln2B)(lfH~7>8q*h*YaZqf6i?$+OcW6ebi8fkEDps&YX^fCb zKJS~WoKcC08AwyMpytIMudq-oM~r~eDVfTWu%)78BEL`|MLiMmRuJ^&M0`!Hq+{0s z?LMY6B27LPF}9B(=bfJJ=uytlY>W6!1N&{13;azp@EKN|n$1)z7kSB7 z!ASKklNL9{KWJdwh-|egdO>q|ce@tW=CZI1tBl?zEn615LjqbJxkmz07JEc`f->~L zbP0~{uDVMec|`*9q@I?n=$+KY@uGkDKr-Dut|8yJq_KIQcj5L;hrKMGjYlsYNveXmm0AEs*{#j5D z=9~D>EvYr|b-nsIUlHpcAW?nCDj;{x=gGX`GyTs9@ z?A1~mWRq<43Ef46zgj1-lAnXtK~Lbs3bUUK{l1#mwkAsiKD7W*ksV_iSzdkBnHEwM zxKeRO?)HhPjTa$6QWkr+*QDNM@88nXQSA1BM%F2*cabgXkxsg|;%H#T-F5n)Wh0`( z4VZhk0HZdX2G=-c%9<>amsR66lF}I@)DhY$*{DrY4@{XY@8}J(HjgP&Fd2fiuFW*1 zGWYK6c9cbmdA(C5x!~igIzUWTsj}%wM`WDV6_;5FEY=X!5%flJSKS62;R!mDHk*xJ zADpt$6C~rc2~Xj?U;Y&`IQ@Pgb*zqbiU>^N-RQrMu)e9Lb)^zVw2ZSkK`1R%#TUDTXgo;|QsG~3 z)%52T9Y4}KD50FgXe1}$pwI3zl_fyTx)(ioy@~|7&1)q-DZ11@$e{OekrsU5_jnpq zKRX~Fj$EN7mYD~Ae(&GDkHJZ_-nqi`QnHR#fy5raz*RadvndDAdGtFOEPEqKj{9p8 z?;Co#Q90Yo9&BW44{;499e&q_P?`Qh+w6Kjb%O89YJ$(gWQQ;-s`_itDlgA5>yPlt z%XlXnaOncEM)NJKS1PR&243`lf=US?3OAhe4cu35oPbe$x@e@|bljtJv5 z(>Ufd>JElorR^|Df3RBzbU}&$m7S7I4S>A6=~D7=VXaU-0^niPqV#;hWHjxdafm?S z*WxQ-enO+`SXIvRL7z#%EH8oc*Am%DHy}x)Uv;8w4f?hBf4ZA$koF2w+&^*KWIP%% zsl!5HbY`tMt%FNxA?0Yx$b`tp?y8aAxsSKNh>y4Gz~%=3DldE@_P+hT-Fnx8d;Ddk z#kD|(^DKZO-kmhW_J*3aB`s+Lr|GZlLPFpe6Ns&BXj7DsluP6c>%6+3&wGR&@TOiP z9u<7(+$EK_LT8$Xd70xpHuS^)6SUG6bptw!RweH|Y&kzZqG-l>ORNcMnMrysy^{qW zKxCCeFm9}jNN?&loy;DMmlv`+Y@Ed!e{YI8eyU3!xsEEMK zh?i-{QDGA1i%Yxp?$En+E^DR}5fT~w$THq%gA<<(1g=Uk!RGhyc9Z|x`_s4OR8z8- zAA>XMCc8l?MZdcUTKecPVP#I2HRaw4g1Ac#T(jZcfAD*UvhWDSmygTW$lx1B!D=Uu zv{{i6qXqgeSgboWEJGotyThDG8gZL}V<;4ppZ1=m?X(K8N$=v@XCkVV{o)Ik#$woO zUr9Edz-8u0PVIC?B%8}_^I&yUa2Yd$2zOct8Ku}|MZ#Hypb>r&*EHPV;b3*q%*~%( zJf^RH^+BZMUOoErSMiW}^v~ofUjr*|U}}T@4&q^q`j>!765v(RUv$UhBOPz5>P2&9 z6zMQ8bPd|dg z-ha!yhgVIwLQ1UbdZ`s~9 zBIlZA=vRH;%C?3JJ_*>s~|{9|H+a>$B0tJ<*%jDCfXu5n*B! zWF#|P-#YRWP0UIbZc-G-YC$kCwB3XGbs^d`1YO3We^+{0!QRb6+WpJ*nbDGWqk~mn zuPsi0e1;|Z`&N9|&`+E;Fe44DDDK|c2QjWt!0(fcZntG3rb7(N$pZSjz~ZtgpF45S zEBh0r52X1*^}W@ z&1L@W^72K`@7V!ec=_e7e{8IRFGSzPBlkvPaZv4v!)m6IEeX36(}-IYqtx4L(ia#_;aJuVwUfRKkOLnG;JrU1Qe_x6=pa=H&QYnYk+sq^+)%W<|( z>mB^bQ4b&3eV*^~Z@oIpHZssmt}!$sSZyILrqUwlSBTDqs{wJ9aZY zvOjL4r7Pw15ER&Thi2+biFpaxZ>W$vus#O~h z4BUBI05}W5q2tWzyIR2iiYS?7ht*sC>VtkSN};y?FdcSI&+5}$k(|o-d~{j zeKY(rk(u)L7gkpq*Z2B?cHtSV6;6?@+|mtEw1STTy5W zF|X09pWBY6{Jj5>cnH;b0=taWiB8*G^K-PxZtLeK-Mq0klHraL4}ny2vgt5Vg~WyhY{I{fh% zRn-J49K?!`BWsb9YJF?BBRmM~wG||Kgm~VhM{Wj+#TsY7Bk%3X2G}vDp8XhAWMJm7 z8L#5|Ia9UxA0n6FTdRT|)OcM7I8$WSWCU!l@vJuuT}>yR4yRoKHTVi+#)n`jjDCkl zIQb-pbEurMgA;9y_1;6i9pGQsKs8gI9CgS=m6s_HwcIDZgz|o%Vj{z#vMGz*kT{>E zUp}g0COPN{tLRWwjp@F+MBVVsZRqK4HH13tG_XxI&sn82%M>2x0MOrQ`*QVbgda}t zut9BM-@5rkd{K`yfp9Iw>&riC{B{`>Qio5wm|jh&pXk-7@V~%(>{~2v4jeLv*aVRG zdx&ni&NiJOC3oo^DvugXpTJ~W6mUj3s}QBMV-r&J~yEBts4*=O*R5-h9pYp2LkEx#1cp&7J9sA_Tgd0D8kgyVvu&W*RN=D3VL&!aT_)R)*evM${ugxd~6*46>4 zpEe!P%XGZwVu|029s!$|Fx3KBFJq_TJ9Glyhrk16B4}}l*p5h084i`NS6QD1025`FD1RT<5hY*$6%o+p4Nh1I{ zDF-d_$b<~vtCJP#FobO`{t(rOQ!P;pPOR5$yCC5?#^v1o9A#YX%e1(%vw~tGb4g^Y zn5gtT?+#yW!Q*f>OGUyVTN)ldmEv%E3`=$oDPt}ub4jJ-jNp{4qO%&NvkalN zsAex}*m#LKUx|651V;9d?|8qP6nJhPs)R})!o;_({5Zdbh1s8}i5CaJX%qg)25pIPM%EH&Mc(J+ zn%4Fdt%uj<==Ws_0{2JEk>uz{kY0|9`E^p_3IAcJr%Ww-_to9Q^z2UApMg7B1YuXu z-c}n6=|B(zA~P=}1P9+<962%h>Z9@ZI>rmFr^*VpSp>Yv>ntubRClz} zB{93dtWn`TJ@Ofw7GwC*ZTUhh+G`-haJx-9%Zgi$bOEu_!`f8PiD2iv0kdqh$djS> z{EscD8F=MKpo!coh_sF>iWNk@ke5;+2}+s9e3to5ox0)nM)>clWE0g22)BOS42Hee zb2U)Y9u?!Y5fo0v9nj*{wOjMY5d{0E3pUfxHL^>Mf%&B{7g2C6q1grZshTa`h|(q& z8bFPKr4@fXDu#w6_4K%wX(inK(~w;zZeN zXDuP0xWUc0R%7Zg{^Ho}Ap_wA*d3vz2~#`4*93QlypZqebhcopC;U#qkLVtu%tau~ z#4wl-<55{kH1x?sOaZ3un*T6)vd)tOO0`1+I{8nBOV8XpX;f4tJ%U24wwy0HlF$kR z8xphbl4RodYP=$4d;{Y1M1q{VZV}kf=&X+%?(}=(_fcCyPHnzid{?8AL@e7Pj|}sj zbOrQJx_}w@WWJG!VYYW|ET)Hr?Dj-|jaYj%_7}R{dwsdw7w3nW;Q!#p9)iGnJ=Z|a zdA)JCKN8BJ0X%VH9c#hIG34Sva)#uFOkH3G-&j9FQFRb@IE~ zJ32G_O`A^j6kO7XqJpM#iMk8KIak%MqjCxf4EAf~bzMirYDv-&9K)k&+53?6n_cf- z?^g*Ejh>HIs;)!`M8!GD7~~ny-x&vVmbTNgK-=@XgM*9iF9^RkQ(@4TB2Tjeg<;S~ z)#hbvXHj6Ars6A`2!LL^0Dup2wG)sg;b164`QKj#XduZJBtYN7D&SN|w?GiR`V2tT zlH61OP$nY<7b78&7vmo3jev4uJppj~agQw{hb?J+02JNM z?-BO&w!E|pV#@tqv3c*Le#ES|r8%NT2p`4|cys#-OvZ}! zZCDsJgcr1s_-Mv@mFV~Sitvuw*7F(wK$o33zee#N%cCOY$+NcVxR1p-U==LfXJnJMS7+Ai!f_Y7zEpTZzJc^Uzc}^^ zG-vg2yN7L7m}82u($>BaKana8{6I@IyUFl*%Kd|IIwAdrcNG<;1+RrUYsb=khYlB| zB{SG-O+Z-45iC<=26Y;^j~6^cZiaPO;uSVAAp}A7>Ej(Hbp!>%mtv5{v_bbroiU{H z@B~N`fa`;%75^=7 z#4?#ruJ?|_H{SCP{(t*$!k-?Zp8vQ@fcO9a|F|yzHnv8_y4JQv&Q`{b^p5V1PR7>e zHYTB=EvMx{9U(IdU1tq zaQ53dJ6*=Giwuw=GP?|0y#<3)wHHgAY)ebSM+(7;%F50=CjO|6nUy8kZg7u4X^@E~ zm8{>=*${7Tqi!-tG=t)=b?2*>blV4+LFTcs7g;OTf|-*{pdqfw{;8Te1jqOB^ox_s zK78?HA(%U}Ln2H-$!m^1mi!bY-qq8a41{ClYY=vVk$>Hc8;-br2~$`k3@-rhA1n^b z`ML1AdfdzNKSzKN)r5-vZnP*@UGsWY05hfP1fm%)!8|s9TXj)Q$%jFFiy0b&st8Jn z%mq2t7&HQ(&M~tZqpYlwue(WRPY*zHA;=|i9vymbt!AH477+LC)%70Z-p{&nHIy@) zERqWee14V;g-;t)s>WbjmM^b|E9WPAwpV`!YoqQ?wp0$66JrLN8dBQ38+E1MtH#pl zu7x}hwgO>Rur$s2_VFT6^1YY&HU0L!9{7y1Y5JyD#~?31$kL~#V<<}ZtX>)R{=qH# zCLu<>X}&T8Y3o}_)2YBCqS9}r6!+-2x3ejb(FoHnDD;!JdKeufiRIwb1?;VK2DMQr zGIXKTo4>5p>0QqQv#6Xli5UT&Ttco;5r|&N_=E~MtMgqaZSgLjw$-QEp?8XWbP`L* zrimpBSxl0WIBkKFw@jj?ytbv*hKH3iDuu-qPw!TR?^35KPF8?ic;j?mnWh>ey-28z zjWkQO02nW-wgjsz%|93%z7e}C?kg!&vI~>f6^r!=m+>T9M(3~TOl|(&q#KeQ(?we^Cr=U^a zfhptc*UeWXh9ID_*QE&o)9UCfd~=| zK-Szkr_t1R(5tJLuJ=gg8Tea(9pFNro884hOwZN%xw509qoQLYd$l5Jv#TF|nuckER89 za{Gg+1id3G&iLO~b%b}+*7+fn)(wOALA4p&k+i{vFU?+h)0bL(BDxZVwO2zwOFbXy zfa@JusC`5+I!C17LxPvi9dP^zgGDUG1QeKChWdm^*`{X$t_LI%nZ5x%EFMXK=z#Gn zGy;;dYT8lK@tVi;#2i2p^x*!!W7-}Jw|Sm4BgQ!=KyZGreV!R0p^;Z?ARCPLA7h@e zfqED~Ou6rH!~|oAvG80BK=Tg2NYli*IiZBB2uAD?^!ue(#Qo7=j4*Zj~z3o^Jm+NnNieH$Pl^U zKjH}Z3~o?r#qV-Z@UldhvSI^w{cu#=fd)J+4(r|~wRz&ha zOHKBwK0;8qL*1R_x|kzfI#%nA`deYh^il`xf)3jDnKm0V;48vRkz_HRUUSaog=kIv zMkJ+bP#3~5iwbdZ1GJC;VxVgV0Z!3*w&T9o#JT7zjdy@~#!y&e5W7D2q|lCT)B zL$OrJ0AM{AR^LZ^;=mHiz1J|*RRtA~iz$sG8GhM|_75HL8Y|iSUxbS1o6WA2e_cO8 zI;QPRLV}DY3Ysv{zy-a+sGHey@P-y(=4xWy&=Am#tBkO=DPWNGELlghWdR_+ zqkj1w4=g{nW4jo?p~wW0U>E3fc<%T~4k^Fo_)X#_m@p^GcTE`t2;NpRUGOYgmcjT zjBX(+lg~#jPmOx_pJYb!2T#cXkP@VU@Yf8D6J-6vf8NUq zXZo=nT>2wO3fD2BdqUbFX~n_ zwc8`rnLu(EWupDS6dDpa#k9e#*%9jt^2LgW_mtVKWywaLrdGp@$^091sG^xpC|)DP z7nf`nh1zPK@jB`XG0H!FGW_5^pQOR?O>R1!)(YvKluCGF>JZ}<3{}%xsnV>T zazqi*X*@Qp4a}}d6_8if|LXH~(#h@9`2ATtNae)#JRPd6IK6^A2qxtkv1TiuFtM;~ zt>;{IkkJVDb;$j8I|9F6vA4zS_D6ZQRM{Fu>Dc=&Al{YJLv7VZ;_|bn&9bW`P~nU; zdE#S3!w`0lx@cAQY`oFQzaQV5O^*Jj(6NT zE&r;_*Jcs=lPwi$F#6$7e!VT1^zk_$Kjo()2PeTzEO`3 zZj1+m(*-+u4NsD!Q)zs}UrK&?6)m3VxWF5VFyz(>*;EqQGtLCH0#kc^&c@U6Pww;< zQ>Sn9O_a@yCGQh*!q~L((RdG0v)jhkk)?F2Oy;+0qJX#5hQ=h_`EUG|2G^`*wW98^ zSFmS0rVc|-XK!9#40JmjnU7Ts;xRx6q>x3a{)pt&XsIgo1f!$NUAg-tmp0FOZ@0GQ zO^3J~adz@<%}{(cjTsmg8Jv-3S?;DS^8*dre<_BIw{pnRC^83c4wX1L0w>dqKlewv zAwmv~?>}o3ddGi@quVm>hcej|Cn~V8UKkFtSJxoZCUe;&l8`XWTCgK$1@7NJg~yBg zD0jbUqOO0LM*<6#{Qavq@%39fx6@%m`6z}J{un=0G?sCq@<$Amo!kkxtyn*^*l;vY zR_ieZdQdEp@>W4hc{@cVx?nSSRNRVwyH}x zPgM~Rue38L9_~q1vBSgn#=|zb@%?R z%U{@z0P^;7+0NzJGeXq@oe@mz&ybV9h^IAgj~+@{uM(3DWz5;E!0Bb4%Lx)I2}k!n zeig3lq{e)Xr|W*k-!2IvWqc?&oHFppZU1tc#p#@R53$kbJ?x)#Z#h}~6$%mXh^#_Q zxo+k!XF#gvjOt(>$`${xO8bVlJDFK@W1A&Ey>~rLGzpx=zgRSJkXjgsbt=rFbbBmKe8anQ;E!k=G+cqYPZKp~TZLg_tk^V!04sjV zJsOqSh9omoVt`1QBpYS<(l||K|KI6x6Sz5;>a&Ii8ME0UC_Ph~1Sr(*bWGy)N9Yjo z#qqS+m0^RXoZlzUwk}kRpwTX{wMyM86cy_QxqV+jLebfVzKk%z6b$nF!lrC=dAKD> z&=oY9Y=gsV0WurV`ju+&dH?$2DOhcMQtM?}?bZN~ycdKKY)IWn1f>{EuPl`0jcye4 z2eyj=k85(`QalcJ9~N@~;PbF}-Nf}bp^tFZx!r}9FA8$dPrTM9QF&HogHR*q?sR)f z?b9x3=SQ)m^QdHzteAo*%+nGXee)^kP11GpqMcRd>ltoW6gr29D!X*kKAHkcv3Af< zCZ6kq4UlXI1p&Zlw$M9Yi3)k5SLr{AbprwYlSCo*_)u`2J3eg7{Qd4`h*4$6qY(I90zKjug$IveKF_)EfCT#?feZnRa9Y>$z#ws% zmBC|;$&{*hRAK|3)z6&C$l>YkiBzZt7S*}FHkO(;>F*1IeL?Uws`1sE3HzqFi{c!D zj>zVi??^N^Kq1rTXG!Uf7+7CQ5+nz4RO&H8u6~=z`Opgp6J+h}Tb(UgR6?x&Q=?#ZzyRvlYeb}y~sWs)Qx?4-Pp81HG4*!L~Bje z-RDUYM~E^$fb?~(ZGZKcov!ZM(axDF2TwipfhaIK ziQWph=eg+G+2Pz`k200Rr7TT7iGKM?Iz3wTZ1CQ&eBH=C+^Hr1ly-#`+(wFOkn~WV znnf|de;dXzh_^p1ejt2BFMNX`TAeu)Lu+MWXQ0!rPRr&oI^9kN3hc13F!<>P?uFmx z=C-~KIW*_EUso653dr3}=)T)UVfLHne*4N2$Qk5!KQ#g(*+^;0>IGo7jPqFpgJNh5 z$(~SkX++l}{Y)?LC^YpG2s4fOpOPuAs>{;nfs+WwOw*@Q3hy9&g}VfHM=)mn7C} z@gxl{6SKOrUt5^3zJ6IWZ%=M~*EGRKdnR&Upw;m;(pS8}(hfa%7e+9^ahGy3vn_DK zGLx>V(BGAFCvfU2oa$i=&s0S}1{|IEH!v2?@CHp=Muxt>h}e>GflXz?pZPfV;>>4e z0@UuES#+39otkWlU5{uOMa0n8>s)+cy>82X&W9A3s`Lx#SE4744V=NLws0psAi7aZ zA%+Ma4zmfNpQ$UOpzl2&g_0Jnz69e3)!`CPAED9RsBj?}#H zPRZG&{Wv=sQ`E?x&5H<^#js8+=pR{Lm$$coW*-c|yatFXCE2bDR5}vrV-!PD2uwHNzQ+5o6&OK@&E8=Z9bc z>4n@ZnQjia8ZxTs%3{px#(_6!YU(mA1(G@-s|Q_&WT2gbLQW@T;Lb#G-CmU;GB#yU zIciiPL=|+PDvbaM(66VLOVAZh!OUZ+>HSK-T2xHPbvEYKsWX1emVw%+271Bxx zA$``gj3;v_?p3vS15(FPSsjnQoHQV5UC#{t_=oZW*wP>EdY-ENO zzZjl2=YoLJbInd8`FrdbDS7iJC#ykcDY|f5sxM+ZRwB6^6{_6d0uH7~6H)b7rEGlHr6iN)!^zw@d4~ z+G!mK1)C|-QhvNaftdP_2rP0;7Nu6hh_(gBkXmK`)x_WLbs`wF?PR`-8bDTja@SE? zlq3~!<5C<_6NUu;STbWlE-R;cRFnqWZ6!OC?k*+0yo>(Ce>*rWlAiqNNOTt_6F^pB z$Z9ZdyCG&UEYaH_8n2Bi;{+|ss)BQ#733rWEvu9Z*a9T_BQZl@k#Im*6u=M&4bK7w zJ4^!nBYeVzffE8lsA;rtLR8d65dific_*2~%Hr~G^T~0;O%N)MzRGWIhMKR26HNfP zv~@S;3dJ+$+XuaXAgs5*3S_g7ewN};WXXSx0X#jLpI!w4$2TSdLhwu=>IuG=Nd?tO z+A)72x2d6NF{ii+av+TEG5BPYEV?zWXMwW|8oEF_F$3f4b11=molt~`E+$DMw2u5k zW-ieSgQp6?mbZmCX%rgiB7>+48&nc<_WN3J{Og_7vNGASGBL6;J+Lx0krac0)#t|c zGptwQHpgCG%T+rr4DyrL`c%8Vx>|;2=Z^2*+*EoC{H}79e>-))lt9C3REL{kbqxL) z=?55jMCfdsQ6ff7eZ4VSzsbfse*M!){eg)iT+K6kb4s!cfHVS493_cv0@9S_rK#H= zOcM>oh8GN#V|SAJY}W}6np7N6OtD|t&Uzw|xb4SbOou7qMB5betm@DzYw_+OIGKB+ z6R=J@dmjN1I z@n#Rfw>~uGdPV-o(9th%vL!lqO|0s`F=rbIgqhHu77M%;SEQL`R({CNUMx_@>Qht` zPfW<@i%su>SI7lz3%jfnTDZPO-g|DE3b8TD+(g4M4evJRI=MZ5G@X3o*x`oj%#P8j zf7bhUx-RP#o%BF!iVWF(RXMTfb z9wod_-E+aXE{{DyHJLEpP)(`PHTitp3L7jTmb0{FEEX0CWHV5t(Og8g>(UR3@Sy&E=oropYoEx{iq_Fn^?`9hX?mNICe^{1 z{gz2JPnP2$tKT@aIKeeknH~~Z=;X+0_g|B;Y(Vp@q#!|FiR+w%2STk%bRxHfpk`az zoZ36n#{fov5|?fY!y=#W&k2|hL1gwt1X+;%2}`QG%&|UI9(?6w*OmA)1Z}c+&5(o8 zs~@c4vb)b~d(SK9&+7^HX5>~Pngoc*#58g$bn;%c?>P0Ybf{NAeGd4Z7Yocj(cV|& zR!l;2rpPmaPfAa=TtT`tl%kpOFTst01!+e$=c8ufeI%#zcFC*J$pJHB?)3W_-G#0bwWcn%qfBO{`FJ(MgitydeF5W zyIk`7N~0i;Jl#mW(QGMUk@5BkF>--EpGXwyAWIrkV%L;!fuJt6esicBPIxL$xV!j@ zToNp1=6rToNoHFoQY9~Px$r?9R_ZcGb^2xoXHEL$L{_RcK+>iQb!hBpQhS0>z;O5} zBZE#G&o;}S_JI+^kqJ|Um~X_ijG90uQ9{{iBa*3qDB0RR28nD7(#fQ4hGa&mGq!LE zHu9o3d<#_yxH9Kj%}1W0576cd(KLTlFEbN!y3LVF=eA-4?U6)W3v$%BwAuE$`6efKu~C?t%N25L|b2(z}?@rp7{op zENrMBQ~Q3=aSW}5**w7yIyhYgD;8=vb^U=1?3RHg)D|EqwfCL`GHlwVT<)LIh-&Y1 zA0>{wT=KA}`zZ@}qgm1R(oB`wi2KkO^4c6uvn^5b97y3%`rRB zhJqfQnmGN+1`ATh3CnZ6qcVN2Y7>G}G6@HRX+JWyA_Cv!!8p8;=g0PZbB> zgwp2~dC~GJ1o&^=4QYHlM7;92j)Iq8k?xD4TRH8I5bdc2;Y8*cqPa`~#j2l;BYQmr zB+@~L|4fyXT`}TpeI3DPD(7n472s)pOck93XV=O5lWh>4+e=mx4VQRkrhOp z8$gMBA+&~*0c#oE2;3q<7lXsw58y+a+R#u%!0QYhl+_aPz>WDDit7^iV)9racM;BXvkKX>iYA323PuuSC?L9tMpI%0;bmT*; zk7Ccgn>Pg!EI3kgeoI~(Jit?4C7d1wSp!RZ7AvTU~?-V zzyAXb_KC{02!P+PJrQzk!AxBc)o<7Hstv*&HY8LVF90DS$}FVD2fSdcITF9YujE}) z8cw5q>}ZI~<@>gxN;yDPYjz|qKT&%06tkjXqMn>8e|rzBgd;`#+FJbhnzQzfsGeP( zTee5|D8@I7FF)-D0(*V8_z^jCqc$8X+Nvm42TZ{dNP7`* z-&&Hwb+Q4JZO97;RpQe&n!Q^WOY1vTxf=q>QR{Dh?7GjgwModI~8UJ#8poZTly~TcogF33RG1Ph#hWNg^>7dGqZd9Gu5Zj^|zs0 z?p4{-bTcRqePp%2*p%|EVtaGPdzlT@3-tN97Fbhvv-6eWsbW>TN6GaQLwGb3Y5+Rz zs3xO*kN)~Fx3fFOUd-2@mP5`j#KY&;18Km!np?Aw@a&;>WMVM98fK*YY+w**gz{QY zAO&M(yKiH+@Misf_T(o<(B1i8yrA~sLH+Ye9F~15`ca98u4IXSNY zxxgnxU@hI1(`!t!z+fb)Xcy7D9E9t6{~QK=d?JSD>!NbfllrX>m9ol)mP0wq z6XBbBv}4!UI#i|FS3|wi32E5B(;a+97r_&9JCQXYv9$rCodUhk^K&lE98eB80EsnW zaFudVwZ6jYBs#{3xvO+aUth*#Dxu)oq@Uz0n8?mracw{?t*#pgp~hsYPo(2Exx7-3 zCQ`=IpK7egv}Rdjyf~IEO}S|R;So`Vd;A!%ygQI@V3_9Iu& zDDV1*p;5>>u|V*XdX-1ZvvhJ;7`+E-@alm`nsq-*4!+=3^)#|Pqczs_{Q0zfX+{R< z!ihSPQiCHtoWCTUENhKJo)jkj%5`Xz3O;87k!Fd~H!2ToJ#dOY`O7kA=UHwPPTV-3 zfqHBvxApBdlMSDY_Tu4x=tZkrPz?n&M7mI!>#W_WqNP(yE7uL`X}gHpK9_^g9Zh_Y z3wsKnppll>f9Tv|c zRZ^m3x*d(jx2Fg+T&uZHq`jynbFzn<_fM{R=*O4d+zB$XP$(P+$5gh8c_dPD;~~ zvmnCr25+M5X)y~Xcp~fZoDKX$Mk{Xjkr;r}v2S!^?_-GD18z~bWh;OPQ_}D$h>}pDWJ~DfI=*SU(gqIPp)mN^kY$t zHn(Lin>R4t!G!C%!0f%R2z-DipJIpyHwvVrt3DYXr3pk2(?=%jC}j5H{rF8p)%Ok} zD_I=#V|=`<$3Ymz1zewxT=OP6ELi5x!u?lHJdk+mvZ|`}Y|tN4KI3%RCxK#WHNMNt zVpqEwv+~MFhfV&u#+yyr8B;XsdeppN1&>#tQ9UM|*jZ#3vzVE(7#H|8?)JVcJ z{M9zcr)V7Ic1NQSOHu$oY*H0XL+vSeT0}?DIAQ6&uoBj`LHx@M#J&GJdp@PV(0<@+ zr_x!W#9u)2g0;a|(z;pK6;-&%sNCr)V1^^gEGmbAzdjo?rPt0ZpucmxVjs*Cp^tZ0 zBz6JV&Ho=%T0Fbnack5)F(bZ*o?`WTTFftXIh_s3Il-_~6;9vQF!G?bNDH?UU zmZn7k4s`v65eAM#WnO|prgm?w4r3&e0k;siAtiZcJ2<~r71uWBR&m=%u?1i*lRa&$ z75ZqM=JW#+@atFJ;OOAM0Dk=8Rk`(~F%HQ)no4fF%4DuwAr`T0I$H2%x)ck##wF;D z&C1pD5r)nH%CK0jtrDZH&Pp&xMfhm--9SW>&Z;8t4VD(w#_iSW3~#*Z4$IZz1Wa&d zw#xcT8_=oHI$f}_yfNQauw=QLJj3w|{O0ZYi}hM$)W|JMqAftkIsUoEOYpxjRo??< zmg&mX8z=vi8xc#bmD}*2zp4R9y{PIt{98zeG~9OKUjfDWD()-LuGai+d2lokvZ zkjhs5vDM}T;q7a1iCrf4kP55ONRK&3%$u$Vvc;;al2YLOd9FdqgnN_C`UskL4Abp|eKPi)2eJXoB<+*BE@6J6v{_cjg0)jIgD~RF(_%^C(0OM{B1piL12+&bKT7@UdKu&E*vBVk4tG$D@ZEL_1DU5$Bk zE4CY!2Ko%-76BRnco+u%ed~<_@&QMHwR0DVSqzC$9Esf;Y*(WRV}#v3#s{3jzf`m> zKM4dLmL}XTyjs+q?DCo40>@x|e!$34kuogbN>)IW3SZ7bmfmB|2`6ux1TLSRB}(n_ zNmYS3A;{=<`*CL=OKx{VfR%$aQxgaKhfx9?GmtEr?Fld15niw*JX;}4RJb1I$*g{p zvil-ory*lg4a>xpdoJ4C>#1@U|58C^VaAQe%vG5j(9hpTnsUDBG!@-T3^q{4^ zXlw6UJ^bQEz1^#J=an4_^&sO72|Wz#MwoCTkr6mMv5r*rM88;2RMr(v635g=1CGLY z#8Vv=aS-v=D7ki!XN{Dj%H8^!gPYXmc~T6_4V{}JCz@%i^fBfNgsh}M^W_~Dp6h<$ zlUn|``MoB6+S1zs``Q7CLc0@vf5k-c{PMCxOmhG^fW}a`8?>x~KGcdvw75EY3*zP5 z!dYI7#S-qWct(PV`5_X-_%d=t|K=B})|5#pwbWA5ufQ^Al&_uyLWfhZjAVlIpvNwE zd8%v~NnNsE3W<$Idhs5BM+|IaBvh@k6k6cx{igt+_GQ_aHS zX*HLnJ#fnz9N|jL8(|=@{+6rM@r?7%H%#-$kVBsR4y|I7HufQmek*x}E507TXG))* zEA*XmA1z$8%HPdfjv-`a!zs2Cv>P(Gb_r`>JlvGvKg!GMj6AEBx};q%69hLsNmNdP zoJ@j@q)bt8UJ;&HIo)&GoGe09>0j1lCs13(2pM1XWlC`@{iXoM07w(Utdg88Fy${r zaO#=D=uTlxuvv{-3f`exSRNUDTAB|eV^1Ndr@B@&#Yc%p-L9Hjc9DR><8gj_wUV+W zECNHEqcw;%6<`W5XXOR#y1OCeSI%$01h7tz?dUkmV>YGjrl;#ne>d>Snw#6ucfLC_ z(ck-|2{97wkZ7inIAUzWbY=?oMvhCm?2PtYL=PJ_kpzj$y=YRP%8eI;YckpxG9M(w zD~Jm*LDe0zk3vM$zyr#tO|aKh&ar~1cXNYrS2hkKKu{!o?hW$-HxjN8+40{go|Jwl ze9c?GH*3I~=9hF=U_qBVzOuw2GU3L5nBA#SChVOZ`)Tkese`IeT>U^tsh7bryCTS(q50q#JrG znOLfkhwrf<2YXO)fVhL^%x^a~l#3GsL6%HFi27zbHMl0n2%a5Fa?!9hOucz8^7@ep z>1!B>b^7AB>xvi?*Ray{of^7%^VHv%`J?a{wK%EW8tc&1(4E}@*HX7U4MR>Pn{9Dz&6V)?MH&8WX@aR{ z>63c2_l3k_=LoFBrz?6e90yn(@j-cgZlC}jM~`im0>XsSyD^AN?PqjKHj9p#w|@RY_3%DFW#xI`Vh-|q!F27OT>{k`$m zST5EMC=?V-W&!_T8rtp%s{HuIHD&z2GDV%?9MFU#^1A&6-E}>+Sb)xZ1WvLkdHjPV z!ltF+>5W>W}9P@K@`OJb^hKd;`w+3(muxNk3M{gEFZZ}A@A zzg{c4eVDSH{d6zq^VGwcTJPBhu2g9Z3VYV|63A9zu^b<4EbQLRU4yb>Ptd`{?CtD% za!W_k%h2l8jG9)lEV^uqZWc{UyZQLf6_`yVC- zASb<(TSI1Nk}=8$LhQ^3*kiBU?4k@JA5g8{$J~$G3|dMjSj5j$?P2wm#d(`om|xRC z-wT>wlhJiFZ?rW!*8^p%5%lZpn+-a!A8V6Qv@5JA9&8N^Mu(F+=$dPH+)$66s8|?l zcU*uU8zkBQanW$m5R;X|!688rp6i=z^$-0+5p;Bs4%Og7trGx?)F62g@E+dQ{Vv{C z!CR;wpXG0I=pNKB_zn8lUD(&qQ3A{bI%~LohC7x$<6O^A;l!tUmm!Q1)1`J+r3;=7u3bjF3(-DZ0 zm+n`;kJwH_f^kV z3D~AFjlr-*2w`8wyTc$Q7)w&is{Kk_ZxbohKvggwE5_~0e7^bG#RK6gtB=S2Pfnt!uHr(B^!?11WH>tSf@6STBrh~+h z`MX%3P*b zhKi*d#LA$B<38E#HPN*5J8S90at`p&bBYHd-39>x?p)Hwi=zlX?&)nXINtG|CxUre zfGZULgg-*(wHm~IEdZT}kCMM#D&QXCzLrV99^`%6zZK$M&7|KCexGl>-$A{sH>#TG z6)93oMEKRqdy67wZRNhRW%0HE?b#Eqk>m2UVdQMJ>^Pqyq93fkd+tVOx&6*6DLqsJt6D z=7-$gj1;uR_F61RkQJ3m-mXFAnLWEU`^HlyUcqshIc@qlxqcjqO8@@9QEnP&wK5QI zxoIIAf~)KEhmovibgx<39bo{_&NjlRlWDgiL=|@cdakSiK2ClfUYOs&>}s6=pCpp! zYW41UL>+o;V>Dj3AQ3vJOGDcIUu6(|$G!jbtK{!0pu%{Ygh>NlqD#_iTSp_L5o!sH z*^_#WO~~giu;mdkjv7$fkVRw(EO8P~j|&?=X@~&4zKV zNzJ@*xDWfQ^1;+!&ES!0BrliB)H{g3>BY*~1yOjsXBBrH!nmH6&zfmfijLn7!IWjg zJA*}k8)DWLp+ro8WXi1GPJc#*oo$sm=Sc1gVW$Gr=gJSP>XA#PN*hbKIZjN`LRw~R zku#B(8$ems8O-yMCHSBrNaJZ<+tTnbOXXIGZ7;htv0gW!vb=MvS#N1&snWZGVUnSY zG@sneXrDM9t@u=QmK=cBDgKG>j#JC)dNfzaF`z69Im0^H4nX5i^T`m}qHIW6V%{@7 zX+^55g5MU{oU@0x-;lzdQW9L0tPY<_sgul}gAyi5?q9q$p-ZxAJJp1Jl z7m%;z3m7B}0$T|x%|-->)Qsd@S~7qEv>fLn6j!K*E<+NZf)k1zFcG_BSfvuXtS)C5 zBzW7y%XrP^s*EHhaoE5Kklr6cgFR|7S~5i3MjeXP+7b|CFaf{+v>_)YN?5As=0t4D z0)C`_eL&MMlmbij(EvCXudD1ohIEqwsAMqpK)l# z`E#ha2~1JiS4hf!HoPi36}$Q#bi!K78J$bZ>%7W+by-Nxqw(~sOjD4OQ@$EDz!`D_ z56I*4xZ(0dtbu0MexOgC{RW3=|854AN$R8f`>s`yQqo}bfhGZx zW{X(Atb0Plv?f_aR<$mdd*tFT*{OxH{2ZkWGqVscyMWbWOhD#J`)O8GI!A!#q64`h z8fP2cR?>AYJ+&fLQndI=)q{hmAK-Pg*Ma}L8pu40YQys%X2j#6W z`kkX|*Esz73;fdS-d}(B=>jE#`bLDZwL!pbq=dSn@u{8xsGV3+^psi1BCFMG%=T^y zKW&N5>7GS}`T1GbT`G3Inx^_!z;Ryt?5PFK%c;K&JO=Z|+DC_cyNbY?K8)eE zSfiZTB$mg%A?Z6lmMlztDs<72+X9`ukhmL}fKip}?c#F(HamYQzO+92*cDRf!9WYZZ4B&f;tw>;k zCdYQFI{Wi*@c1Znb?`vwE7#o~pnGro@Tpl*yFW)fmf{WdfMXl=ZJAuO&_ETkQp9y6 zDbX&htF4?AQ3;X6mvK4LQ|CA%Ml;EJ*NugC5*b%u};y#iN7iFK-Q1(xBiyZ+ah@xlx1@;X{-I^ywVsVR%y z!|^LG#|dOfP|{H&)B?xD!Mnlh;le6X=v!!*MqS8?{4_Oklz7~>`EFQx=PH+`)qAGx zMnjW%*Q09T08mJJG2et8XKR*)E|tCG*aWDW5lJjmP;zl7w1tNh)z*pn+`1;#mq z6t8?ejcL-D3K(`E^9Nu2Ey&~1{(HY&O7VPYcJ5IC@)B;*5_^i{*ct|flTnyDYuvWk_ql#ft8O4A! z(&$LWP$(^AuOZzXUqC2xqwbpY?lBlj2+MnR{%dz*XXmWY&g{ty_4aCZ0+KR3)1Mnn zZ+?95C`%Xb6R)HdLAg+&b>bu>O~e4V`>^`k`CZt``S~{@9B>DTt=WjmL##S+227fV z?O*G_D7YT5&qifYEB#ykBpGIsfmARR)C3F2nije>(K$&WN>j;va+$;zm^*EZ8#cvV zLX_)KN3(`4HaXptsde?kz=aJZvk$G&)}99d$=ZpE5{)vjp3(D|2L~4RV zuKvQ>1U(r9R=(o~7YTJ%4h?JIu!$?2FM#1?jnmXkZvNtPl?yp3bg-Y6(d@{Oy9lk1) z{Hr8^U`8pDCuZw4zX0aAPbl^f-zL~^PVs;F0J)6!XYqEJ3P>0-Mh6MLsO-Tf9x*xI z6BNveTE6cxWzF3Y0W^lMHDqWpmm7`9O3xt(&x}#)BJZJUqD&^|S8esi(Ds#UDT1gn zy~P{0zht!PZ<0S6$2@sXUi@;+veBj~ymGmXkMzrLmdrn9oirrUXQ--2R|OX(EMdlU z5HKt$VjA~UrVcA$9-HS#7_SW_hKz8yM%eIr<8_&le@CT>JrJP%10Ca=={`-4_lNmw6+=g4hlN-A<}}Y&Fc`M^1FnnpgiVCr;`Wu>0mZ)X z*{f2Dg=Iuee|&;dpCSYf5?*eY9Kbuat%NwS*h8*`tw!iJk6=RuROrJPM|?q$p>w=j zpVOd+OZ+rOmGzCvT0{5)-G}!L4)xf`9d3IOaR>H>B21>%M}kaLr`KqGJSF$C90G*K z`t>q+-h|>clLx&kFIAZ4li;DwXp)L1t+t>8cX(7w1w`K)^gjCoTZ39hqO2&&wW*5G zF^5Di_4KYgfGENWC+;WKG}oL|iQr6yfT9;Do24q(w0e=DA~R@vdrv8=#jz|j)}jOU z1gc@2;~?R4E$gS^x91=>eO=LVYgLRKmE|KdBwerY;Jwc2b)#q_gtTecBE-N5vmzw> z;fC4?KCp5G#0npVQj6dWa-WK*7j9BI1Y?_95+4{IYbYSEEWqB&-U~gLcI%*Of3^~( z77jhSZG_}ol!Oz6ew_)(YDZ3A3iD7SaxV@Em+&RedN;5t3(WFAS53dMbfeE{Rs>Qz zIcO+(nq0idEDW~CJN<8Y$ue@avlC&1|6SF>9tQ??BL#4N1;9V0XT&KQtg#{hAPS2h z?5gB6C$!l`V@W47UL}W+jhf%vLg*VF4fTC8^o_}W1E?F%nL7luPpcNvUeD|hH~tW6 z-fwvUWmQ+(xhy9_yYgCAY>bR+4B$1Mu)7x24v#IHa99Q>!CJDbe>Lj9mD>Fzvs|X6 z#dvO1A(5`9Wgu;XGBrE+=TJKA1DuLFL@EiTGxpvw`+aHU6HJ7}*8ilO^-bV73DS)6 z*BoJlTuMdGfw`pO0opNwFfKm96m^pv0g?^*;<0kys06HPiGE zLrv49gfLACgHQ>GCF*47T1)vQCK3@Io;*qu@Qq-&_E0jY6+zvzF)$k*CB)UGrwUD~ zoXNJu+3M!~qf^a;i%G`=2@PX#t+oXM3^0O3(*ol6ZUOOPDNaI)sOXlVWbB~iT?q;j zjRT$?+;Y*%UbJv3+W9f~_>d+xbXa%AqKDARkQI=NYZp5?U-_gAJwm+=OVkHoBHM1+ zm$J;vpj)>$)4?DDz%$Rc;^d8IV=wVxVbJJz3(MEZ!30Gql^r}3yu#-H3PzmdU(l78 zSj@P+LIot8!kf&}O|-D*tYOVq#h8kVJSiMrh+PWZS@Bsh`W@vAeEii45q(}V&@0jJ zROjnTel&CA?GGJ_@PXvr_J{dvk++WJIz)>>bgj9v>ZWxL^kSiN)?|39OXRnWrYV-? ziy;G>*Ib(O>(6Wg7*u4E-ZMSJrxi(@{}HUto0m-DTNF|~+3EmyXt-V$UG9F<#ePx* zaZ2B_LkWq=CSf?#w~#f|N9GxFWbL)TP8anLpjSu^^7ntGr%@%9*f=R~}Q8JaK|WSZC2rm#oTy^%omn+=X^nWCf zkrp3rSG#Qtvv5?@0vZ{z?*!|!b@IuM?zdMJ{xfKAU`%;TTOyxoN?2`Ci=ow^zy2Y$~qk21S>*{sX`}o_#=)0K}&jA~2*MA{`p3-Mt^avk7CC+2LtleO} z_AC!8H~MsQ)YCX|j8Vi#vt)RG1+o$Z>2e}*D5i0(7pBijDoLcRFj0SRoB$FGGKKp< z|4(K_I8Np*875aejKf;ul+c1xY}Q1IbZ4I0)B~Fzf*}XEp!#8QNs={ ziSu@aV_s`@!<6$??`rfeDYZ;K?@*2K5TWA01a+qy?4v1>lkqtD2dfBp)Q|ykNMH%? z8+`acU=10wRgTa_V;{*h$s0{hCl+fcts`vr#_iUqjDAFQ818|6`n`DU$j5til-5}c zWgj~YiGRMfmUct()_y_3C@{xK7oZQuV1p!H)wxkdp;x@OIqU*FQgN=}z0AVM{aZRl zFA|$ayO#eNvFBLM6sW^T?eE*=tvRlZbR02)m@^b98ke<&X}`_gi5bvj_%6-IB~>L5 z%{GW<9VPCIB15GSp%!MX%|A*k=n&um=jh|xAP_%N!$qWEFJ7u^)f?%TXfmeoF`Rn; zhAX}2Jcl%~Og)06dW;OzR-pG_FGlAZJj9*jZNee9&Dx72sveD2k_w1^92A_R39rF4%cuP`CepLbfch0! zt(%dezhf2?>s>L=?hm0o}6XC)7$C;qHBd~*N3H&7#Nl=e5B2wELW8aena0Y5i-R^WsiJ$oiLX}Z1?&?AQ(mf z(Q%w?fGbPslXDFtC9{qEb$1jD@kJEC*_ul|qUyZ}K29wcTtqGd!3d=cMTVmFtVzWy z14WRm)v0Y7XZ>M@Av&nyDwD|{O0kcAoUJ)SHCT8uK5?_;ifcp$3B^MdkSxk}TusiKsr!5} zc&Mc{*sXq`Oq8I#$>Uto5?pmT0?Y0LN9y8ZvNbY80O^(dAZLs@BSLYSlJC^jbmlT<2lr5sX)%GrIw(!zMrjh=D&p)66V?ugsS1q~nR&owlabHyg-n<5BwiP0`Cjj<5?fMd~J4Pk8NCzEAF~~V*QK7O>ezl)6bK`Jv@r8Wt-5e+jB;5 zZfb7DUr~~2^BNM=OVbC#w@glrKfx$*=6m`Kc2v@Z&|lOUyN9Mr{@dvR2zo`od#?2^ zAJYlOMT9Ebunu%$$Rwr}yniF$Oo~rO3scZ8eNE-%FCu372H?PicVZx{)!`vOfT!j{ zSs+Mt@x{MYCYA-6sgA%$n1<_@*BDa#uWnu#CN3W&aX!F`xO0~biinCri4w_EF!0CU zhgO@)H+MgYCn=9RO-fc8vyL2QatQUL0jGrOw&w)+0@}ntY9MKoJ%~pNIn+Ek=#v9p z=+Ak(YY+bmX*Ybx;I%7l_H)pC>U_ax;(GX4>dfMUvZ{)&s0l}*5FVi2SX{4*YEh&- z2jhV2jlPaQzyk${tHo)G>`hLA%v+VM_;~TTxC!ecB?3RQZ3+eNs$_=z*v_Sntf8H-)PD>8@j z=LkdDz61?Wo%O*W42|}uxB+WAjDIM^3&uD#Yv)1CJ)cf%C*6ta#-?%zmw(ptSDbX_EId)wc zvK-Mb7VZ@96SvK*oVBZ{sJlFl7#?F%uH?Vy{Z$y?G<+WQJ6`2CSUV&J>RAv%O*=`1QO240=!{Kez|{yM31Vg6r?oJGW&(a}YD$MU1#BNH4OWqc=N=_T$$( zxeKEtd*GVLBa-o7rp-JS5Gc@g@EtaJ{7cUNSgj6u6@i1 zsYv}pQ<`77GqcKLTWp;lB(j|{%a<;PCw>o(+~t}Ea3spT)&|D?UNH9AvL^`iZ9QK$ z-L-76&E+8+LQXaAuP2PrDSpYZX9_;%$uUmu6llsPzff>-sJNKpB#M~vEWhQHf3N}| zN^kiFS}R6ItT?WI^8M-be26bul`Y*5c&dneR$wDIa3=_3nl!{s;8}SkZs{`6mGoJf zWHD|`Gl9x8TEg1AqDGl3Lk9#uzlM4q1_vv|OYQ*q0PES+Voz)2m%1s;WP;D)rtHHD z8z@4X(DbD^_2sjuSf7#FcJD)n__1s6B#LH61>@q5IyENjt&x--#gASc9*Q9d32$36 zF{={AS%tgD$kOr&b4pQ&&mmXW^kfV)UTd>3W}5IOEa@p65G7Nifuqe1H3ycRx$evu z=YemAL*LOCHP!~UjbTRH7VEpp3>XQXn$o|G(9%U!Lm~H}-A0d*MC~ArDB;qM!CKa}}P`e@}&e-`=kjh|SoC_sN0)Q&Gu3}rRBt553bS)CW(fQ*)$WK(wu6vf4q0&>n7*aj>w9hU?_uaNrL1$j-R+Mn&qI0s8F(&ko$%uiA;738(1?kFaL3^;FNS^ zfT9xpaqkO0~X~)2uyRH|l{e@xFsiD^X9u63SF!F8G?zZau9I01c z{zbIYu0t3*PGtZbYZGEv&WdGq0E0#NQ_3w+^TSYCdPbN7QAaM&bvduKPkGZ}#N-CO zaL&zs(~+`64@MDm;{rcKw~442deH%&uoU~hK@PcwWd3W226{514-Xu~wd6^vZD)ri zJ1uGGGp{~GRnlj%MR&4Z;IDFs!Y(pxO05=;R@lJOZ(Y{ElP=K=cmgq-uyLt+#U=|2 z<6937KX?P`bHEf{v7LEM&PG>1)rj2f`NYSdU~MhxjZDEjlP0YOa+w0KNd?@b9GGB2 z4;?(eEM#H9N?TD4PT_l<;)BufCC+2^|1%1`@_P~Y9>x5$(`NXSj4BYG^NaHR#oG+Q z*wN6xnSBX&{V*PLN`qhUW(!UeOxmaH$BBcW?8K#Cg9-lfE3OYW@wS)<7e&P{?R?L5 z3*oz#*+X2QP+IcbTKtxXp-tGjOv(XPW!4R+9E1PisC6C~MCJ?PZ5S&I!$)NEM-{B& z?=;2Rpj&b=xl~spLS>ETnC=aGYxwoQIGB|M={0B2L@_M~9qYWTwRV7);DsP1f#hO> zoC1eQ)JiW5W0Y*5EFR6|thFY{G%M1Kl*xHpe%t8HUF>3~F9kO*2~}eza-lT44@jt< zn`)&wk~TG03*X!^xWv`Mo-&r^z4={qq(!o6fTk!4#KiCzazHU$4=844otVxS&uJqfvW!+*)xv%i5+1)>+sW}>*4IBDn=l(o_pQ%!9t#q&}BZUw(XMadFNQ!jRA z+&9p{;jOwA-oMA6-_qQ>61S+krOhf0xPUz<-JJ*H}Oz;yun~)d@VMC(RvB5y?)aM5Sn%4%i zmislo9T5Eu_y->a0|9k~CVuAa8c1q;4-LyEbgwEB&}}p&&91bDbpT@syH4ty?`5wo zhUGJ*^02X1V2VL?npe)BZdoZK-CD`P3tV2UU^&xbvq)1gX#D7}2#i4E;nDN*h|W#G zRRXu7pbLt`<)Kld5s>Aq(LU6hTMwF9N974^c}lwPm{TV{&R^X4G`M;>t*TkWth|i2 z8yl4f!f=0%n5&^rTh9xjKdq2^>YGbeB999VDTCm0J*EjxaZg@8pa_feX_z0QAFX8Qc~B_ z+g?7NhJL%D)^)V1{_N-#wke>k4xp$$AWw#{mEul{*f^kU*3c&@kEzS)WYG`CBsCPe z+si&ruwQ+-OC!)6(fPkYzxXnajk(`ZzyFW7IfVS+lMMp^u*3rZK=r>%DO%VXo4Ef^ zL{Uq@X^R!nx7HVQF)UKjnA3Gr*D}USCWkZ)OD`#k%MA`!E;JE8feuAYpd-n@( zHS<*Im%x|q{$qdluYUDRTYA!&WQmZ^AX=w7+=Ql78iC~G?%ulL`BFyx$ zVq4E_E)x6HPJ5yd8GmSsa;C9Z)6sSI%p~!YT2s6O@!v7~q)c1sz)g`F_9V^pU%+pl z3|UffHYzm%xO~c-4wZ35+NF5%g z9cbo01=UBLisoZE-dI?bv188k!f9kTUpS1p@uW(*NOM1d;%87MU2_N*xJ*;JU_P)t zLx^~QDMOOV36Q^jhg2{1WDC?ha})-dq9dMhI4Wpsn`SZ6!JuX3$joAN*r(|QYL=6S zR`MF{JUq=MYfcF*2t{fiWfTNjpjRP_aa3?h(X)J{F@gnb4;X~Dyi7~G1w+SaNz@{9 zR0jqcp7yYe<|O5Wzif$G%U2^6VT$+l6i@4Rab{_5COKlpQT1UX`SD=ZNoMr8F4&K6 z+azK{6fD3D_$W(7?ez{#b=U|^tg-NYSy?q)HrZI~hFeqOQ$spfe5g=8Xu31H6*~x2 z5<;jYm_Q^YonRtm=jH2ewsL0Km!`1S1+=H}sX;&QYq}%*L-rI?II!w|8sT|XNiT)1 zz`xI*srcRvqdL9E>@58^pH@blksqkr1XhRZKowEtV z+_H$^b)tzzADX?bDv{f5$no)d3=Zz{Mik{lxPby4kpHX%i;qYv5URr!x=zIO> zVDTJ9PnLf)5q|}h3ub=S9Q(>Z7S7N=fD4h-X&m#O!O<6Blgt)I*1bCWg>(}7d*tG^ zFZABoBo_sV$)+ktZkZ7mto+pkbst5?Ci~%;B`4pce;P(Ylp#Knj1(Hyy;K*LZ~-}| z5-H(0%o==#kallx7RL_up-{Kw!<8j#fHB_w=@tXNhYgt-y)W!+hoP_0vy~;=_q|q3 z7Kg0%Zz+G2Ie9qf{R%jHLk5SBoVhw+boA)ee~>|WBF!Tcl!DM^(P=R3ejAu{ENg&5 z9(&SkKwYbSbAAwSPW$$A1iRtOGjJ$aQR^lA7$HVzq1|+{pPq%Q{T*yd=Ht(I;L#(G zYS!H;pw$nc;#?+mSEmYA;wj@9V@DV=6wqrc&@gjj%5-XL8~Lf*);JBuoYM2;r0AMN zMh(XZ2J6`mWNp?|v%+o;13hm*uQ3xK8Un~|4(gEhpme|z<OO=_!>xpGkW_zQ@zVbC1(;cJ?RhX84slDvX&%;oIX$m4OPi25Cy&^u+{0Sg=v0Wl(+xWTCkhPY}hvy3_6= zQge1?xOf+ud;ZJzHj#Q%*?+FB<##7+G+wDn>ECOQ*YX8Z8YEvq0pyu^gUkD1>qL}7 z%9ZGG#IC2kKYIBD6zcAIqejTJq=(V#G-c(TX?bS+SoDL&cnMWFY|s26J8fVR1q*=h zV9koaH7$^HktWc7Gn|PqD-O$*!od&x_pOB7#!ZIu2&gx?H5dE+HNdZsG1}UbD9_!4 z*sBce+fffFPfE1b2H5Ce!2|Hgcd86pj+lyj9Dh>c0XD^@gP|}NEw~Lh{a9^(sr_KE z$nL`u?WVZ8vAYjpTXmeQ2zL@S&xKkTq&p@pPPak9&_nkxB|Zesred^>ukG(VpeE?FF|XRp-_bBPZS#Y zo1Wg!NFMX;OizX}l*As&i!4&iQ>lQ zJ&QP7vSgOs60|pqpto(9?S%-nIybi=fIs7~@Ubrj-}L=A*dw`xH~b!syEubAqB#S$ z6uH$dZUB^idUX&l=?o)P<4|EWn=b~SONZU^^J(bkEx~C zNWKs%Fh=ZwKU1q>#-v>MIYOUKyHVbNw5{ ziU(2}Qv{kq-cV^U60jZx>sU;&tE|!yh#l5l+Q$;vz%q}x~n>_PsA&kB@%XjN} zAQWP~)=Gc;f?%H=7&g<}1_yEZ^wye|u4&5#m4JAd<PSL4UnqrKM6W_c5zusQ_@y z3d=o;lQJ4bRwB`p?`9dH78fnS*671=JPq z0w9yz2a?@sedsE9OF^~zdx7ihnupNrieL%%6T*4LCLn=C<5FQLO9v$3Vl@W$j68hw zSm~|b%+t)UijNvii;6GE$}|TY^H;HRIb@X5WKM{%V(+2+BA?S%+hdrh`2(u*MrNG8 z+uKLjGfQEBunrM(wfm_nDk`q-Xig~`PWCJTv9us%>AQ@A-F_4(ay>(9hw$R;o;rT5 z9_DQle zD%jSt%R%ZI%YR|l)|w=%RDl&AbKQG1jfC-VRzK%5UwD~?T@#fEP>ierbEyTHHbM(6 zaA&!(Lboej>L{n_8O|VTQ0PH9IgR=-+S|Ev+dHRoF6@!Jc)O*mofY$){IJ#)Q9FcX zhtDnTC!L*LR4JCKQP;GyE-t0=r5&5!_3$1SxrIR&*VsHQ6R&+%En1N!u{cgwh%P4q z=dJ^L3B6r<3W!X`1bVV`@@~(4 zmuO#9B}bg&FFV?n|FtWu$_QgIRg>aQiSaahC&Y;`!h^*a7r(WIqZ%zNY-JC}C)avc z+eWhR;MhH)i2CdX|0$*~h)JQf{5@N=lYT`P@gmGQ`)0H!V#z;3By5T>;$Zio=i+Jj zdpZIBNe}FE?)oP}>P3(U0lCEQQ)vA`C#pnVVZAGvkdPv$qTv>IM>GDS9|%3f1a zqAbB^(_1AwZ_kD@jVYaHaWI;|7#^$KA>Q!XCOVsd()ccu`K>Lqnj=?+P$gl^19qlf zZnr!cd3Rkjt_E$6@pELE*W=&C-9{|-4FtwxoWEqZR;8YlfG%ig@)>4Pmzx$jCqj=; z;AwZya}Mq#MJQELaeGj#(TV=EvjY%v3omy3F(NoBc!4U2@!m#cloEleDCb4>(}v(n zTIO-OPhHX|RqeLt*t6HU#bT5=c(mI@Dnx*3}2F59mW12pHfJi{pme-y6L6PnhinF_hu* z2k!rsDvXt;mHUGM0K{Scud8Slw$3Jww*S|Sa-wcyx5Wzod#g9#TVXt$no~@p>NU%1 zOr@Hy169n=XDpCE-aHeEs*)giSo3?=MMM#jOu}W6WV4RQpE@2k=H=ne%}7p6qIg2B zFwo9~9*>uDO$L>zeK>YJ@F!0xg)*a5St$2^7(0g`QFvwzk8Rtw?K8G*+qUP7ZQHhO z+qP}p^DY0~O;xJ0$|{v~-tK;0B>qqMpD;zg5~gvDk~DF#;JCzOWoHT9Qs#JiBWqHh zfprnQQ|jQ=9{>?wWF<=#9<+5Tv&Rsu^BsosgrNN&W&{TY9`~5Pxlqjr?`1fCLiC2^ z>RAbTn7N8+WZ4y?%rCG~=2RA(- zf-HS0dE7V794bdVhxG&YKxC65Ld8)NB@UE_S&dC?fWl{e8FaF-|LYBA)<=SYkGjMX z(jFr@+OHD$xp9HwRYh_Vl5`Va+tryQ1{q2f@2EFO6Nv!`J15mk87{$7v_tb3B_I@m z!BDjW988D_8FnG?yDLPrW5#Gs5_Z@mP%DLE#v1nR0hQ1N1tODQVF~>a=ifO&G{PSr#lzVTGEPPrt(A%;HX`6l zjILmGgX~lq2nerNf_pmOgppAtDs~FBqc%FzRclTsK-5=}*Btn&jOHaY#l#xtu#2xx zj?R?;a^Yt0jv>3Qb5&$ksy(}}S6!+_RzA0w4}EYi?T%{=>$gyPq%@!*tg~xVN9bI5v$DB z$TbICxx5;s@WhJm@mSk5y2gKHftqW>V zu0$;bm9m$*v#t?WNDR8~r9K^Cir3m8sp;75kIVzlq0Y4~{b^j@9*)}-<`nHhS{41~ zf>5;-4IBL2zM^fdUvnRu$xzrxX6auu%UyD)xRtG_W_x`zHyZdco$erq^4QY>L`8RY z;B#JjZWS#17=V_cWD-@X8{CaF2Seg43+n&?nKyx0xznf=dnyFf>!#LGWw_Ze(~4dv zB36kyxo|rSpL66T(-1%~#rCwCNiT;Dw4UH;*7rKae}VV%Bk)Sm<{P&E)!~neHc2e;vLRS1a&5e?N7b zBW}gy=2lVQr*o`d3fMI&xvA9(+`PXvCqi7~)aaWAy8`oZPgG#88A^@UfHtZy@%W64 z9q{Ojy&@XIoOvQsPyabQ&vw7r&NjbU%5J;hM#JP5n3C=NGjo#*#Dj#po9`VtCFJ1| z%d)viR(){IzF{fuI8DlATM^c(cSA1cl(92+M4H{hBOTPqH#<%yO;=V@D2uL`;+8QI zXJ-n*JuL;xOe8ca7yv^ak77mz>m7`i0D%Urff+y`^i=!?a~Vk5=_`P7EcUOGpMafT zZsr3#Z-bX&u?iVdbJ_&o93}_c49IcavY1CoTAE1Vk_`;?l#?@vwH3<*Z&lO{y&Q)M zuF{CWSrWm@$Ldz0YKH~zC-oT?shZ-Do^Z+c-EO~O>E%~eX|Eq(^?Alku#z}VkLXuK z=BRl@$I9(xxE#rEz>LZ2hXM}b?m=$%(#Kr6>+3<}3}ymA`4M}!ZF4*nyA~gB2F)z5D@K;Q&^s_jR6S+PTxMSnh`_Yodqn@=w=8|Q^Pmjx8+Cl^rSJC)4-Ycq_l9SDlX5DB9)m~b#U>|aO)R;|6?qT(Iy5Hdqb<&_meJXxy z!|0pYe+8?I7MZoJ&b4BA34*0_cy_hpj6PQ!(79R?u+p{IYi{@m-4DR?#?qNtIm3y~ z-j6ihnEeF2R0@SOH5-8`G&L(D5eAd_owfuSd<}Qba_r98-p!{=$)t_szHeLCkS7^z zW?@SBd3!#5y;iFel{$QOEjYD8jlB3AcphTfPWV+*tSTZ7DU*43jQBD_*UYB;hgYRm z8KvR-F4pJ=WOJ^B+=C%Us=Te}23E1xkf!~x3$IcXTUgnB9J{kF`6kexoSvTZEa=r& zpSK#+Vgd4@_HK6&Lt3bfyUD`g5O7!POArB9m9~BAtRdl62n7Z&$W zEOy+LAW3c!^|OmDCJj7d0jx56aFSdg;&vunjguB!Cyc?|IeEHu&t5K6*}sylIyg@B zw1O!z*tnFzgwxNUF`UHUPD}PXV{9<-D0=dhDdiiTf(6v_67bBYSxk`us_^=*VGwQG zmS7i2)k+u}v)i3sQG(X5iKj+Oi_d>XHZ?nw{>C4Ab{vC6i#6Tb_cWDo*95L-&mtk!Y%?OPy zO#%Fhqc7Q9I_t}=4l$B*VfqrN;(B_#=~=--%|EjmWIPPB;SGe|q`Xg6yRpq--_@OY+hkfB&Vo95n9?w4j6TXiqOr93 zQ`koJu6^^eC46Jx)V24|5*v?&@U=39dF3{-WhyT_H@6SQiqWKn^{5D+z^)bG6deBi zwRxxT^&%qj+FwCoA+J(Qq$NA>>S|wn{d2NzGK}feJSNo>lM-Q~;VtE|>Wq!;8x?{R zz!LzAk8a!P=S)uL=GJ_0u8-u_JcI0V35UvN*$o;|y#>qe9S)OgP*h_w4<=aCjNpSe zFi9-}c@ z9@pMf7ToEYm5Z_H(O(6nxYG&{Cjd!vAvhqRUh~DBC6r*Ya-zAoCeUPd#ldHMS=e-W zos2qdWM_K;)1F=&7A$ypc$eAsXM6!#%MR#sF#H)<7miytTLNF(vl=^0r$)w*XbSCI;6>XPR^6_8L9#mzAXE5pC;!^|XJku}o8f^i0%o?eb^Y8*hq>X`*xwlBZANSQ2&&;L z&)krL2L9WYx+odGyZMCdrJ3t{#g>{g;q~Q%`#KId*ZL7}Atwruu=6D59yYZAa`G_C z=EYy)8-er1e#KBs3mPGocGWKs^#y3;`yvow>ujVI;u;~vF@HC`?~qJb&PUx|AfQM4 z-`8?_d)vHb9SHVJwiK7v8^{ZMbNl8d*g8u)V?-OgxYWwh#p_yEVCg9Fx8>t)mdMHd7-!p$mKt77&N|i^Q z5}-7$k4PMm9#yf-*2W;xEy~srZ9^NPAhzl}B8XE1?o+Js2hjU~I7|tlLN&Ygb zn+|eH>?qod1tN756CD{A=4Qx9n7IA*vNxWKboyT-V!OdbKCcE_!f>(2e|=|z+vNMO zEo+sXC49US|QjG<&6*2j4;+Ez4CvJ;q4Pmp#xx$nS-r) z#`-{NxURUH6<<@FCe@PZS@f{*Cx((CVaS|ZR+$Ok3k-?ce9b<3&mNP@6_->B0G3e{ z0VVwZRsv{Tx$ysduw%gY%L-{SBPhmdhH`*Rl|~mL?Y zOGr{M8s+rG^-x8N$P^``fEeO%tqBQt@QhyJUlz|D^qfJF2%+9=O#?JvGzhbCZw{H1 zy)e;^p-`|q&`v6SY1Zq~%!uJ=?l4CbG%XxJy#^EhWyOe&w)OB7RjGo>K19!s1JcmE zcPkXel8l!{nUKjMzScAzs1!L(f6A8*d_P(eF$gZnzaaqGa#}dmMGkr^X(HE7RJsU( z+DJT=Fh(ZyfU||$by{cMXgfK8@pe-L>fvGk=rO6B8URl;BWnF2w7MAJ=nZdEH!6=n z^j&wMepsFn_Y9@EFhr?Sb)A8_D7EZ_!<5SAA;X;9pmzII6U8|x%6*f%PIkT5mB)#nC7vLnb%)S@BGuIGx<|B#3(42`_#ii>tjjM%f2w}YXI%Vod zJ!VP)h9S$6XVKbTqDzom<=JK{2d>3cncIS~tvt*=(y54Q@_=l4kkvx;OM*St7|>=D zjt{Eif;IC|tP{7^g#Y>|s<#{(yh{aQcRXZ}C{n>mOAcX?;`F4XUC3G8S>Q%-Y?CFL zNTX)@tH6gd=V1!RXEA7jwc2-gOScC0?a9&w11iIMgR>HqH7KIqI9jr0+zIUE!%;KU zF}6UT8LsuOg3bq-hWl=%6G%0L9S*)gl0eromOu%6!h`#=nl8KA~7AXiYwQgM@{jmCbIbt?5z> zGfOus*lhLxEDK5vmMCqIWO5XEo^^2HF$*2JEz#i))RaXvyed8v z76aMIW`Qr_p2t@J|9RR`P$XaP&+5; zvJ=Zfbrh_TPlhN!cMVbpC512hDRwo8gqqu+4)K>gkEG~K9}kXB5#|4de#gZZ0NGGc=ib(>0m5$I+T25hsk&!mct^hm`P5>R%fQl71pm-NFa ziCl}%Ws{Mv(&@vzqkZ~}cqxB0LjnRzr&C@`Y+OD7+w*fc;ZyhG*Z~l%x-R8y2$aJD zeM*LPZu|ytbdV&Ug>^78CJPef>$#b(($bqglg{*6NxV(Nkaie>pRJ2J*;~ux`j$Rp zWcT8r;~zp2F~f)JyY~mPhUo>ta?3Eb35ZX#wjx#q+8D>!meaF0QOy3Vl305;IkR{$NgiLSQ; ztq%;eOrMj)2W(YcmX8$&GZTgLxzeF!5ONNY4+#toxj`@4Y6@q96whh$j+p>4kEd2t zH8{J+Fqt{**3V&9r|0Yul!TvZgenM7jY3be0DhSxlBWO74DndDIwpwdM2#talinE4 zWEs9AqA<9C=XF} zO=vv~^M?VNUa|AJ@QhnTJNTJqzz?Gv`0u{V_EWXX2Lz?Vv?O^W<_-Zsw z&(DRvuM^{!luQEry5COL2p97#ujEfskC=WCLSqb0mUPaN+~y8jK&Hly@kRMUu@g(& zKmq0F-a4Q7)a3NB0lhqBj&rrwuWU_RIjM?+O*|`O$C%I2jv7s+Ee0{KgGA83ADykP zeJg>geQLb7!7650!X>TJgSPKJ*T!|I*=5Uwu?Eov*2hT$N85aqo**ilRTx!!${~QQ z72JK#a5vJc$m?t9%s|t!52msk7#qt6kj{#4NJVoCM{Q%j*&`;6qy+PjC-NVOa#vE* z(`Vbq&&&jQSl}k{WDZtBTXhRL%C~SwPYb1Zr0C5X0DS1O9BJ7H(13FyZlROj2EMhA zcHKG5()rPEal}XN)gCXy2AsoCd*qn7M`L6?rc@wR-_%VHD1Cw!XT!?pKZzde1)cbJ zm~?MSiw@qoNi0IRBEEzo?hY{cPy_XNgK|Y3$BzPwo9~`tM{icm7Sk?+m$R(t(!Q{r zV2pr7;Hl|Rfk4y+5dbOJ0o(-x=>h)X#=d!7sG~RtoV@!S|8N}ZQjOvty}Qp~%D6Gp zQe(?A@$vD>P}>QI4rTKG&MzeJWR`#_2mPADfSHxlfe!d6xbNckX4~~$*SxT@8))pI z6e!T3l24-&RZK+6H6$Tud@x@IbGs|3(gadX#EL*Q(NiIdBK>1*Q7DBZanq)n)ue?| zaT!j+_tB5jiWKe=Orikx2=++mPfs$*@qgX@W-o9C@e3)IMh%S{{P0&lqUD-xZ5cM! z8OJfLeYFH<<2)kR6H{W--hAFS0mu#16?OCJpy~?u1zV6O)be6;BjjK%k~D-qmTHy5 znQZy~r6NHuNrRJ_5lgUmoOaDxM%qlR)C1j6(QJ)itrV|Sgls*IN1G1K&#VA6% zw<6{F=|)-%@zZkK>I?Q1u-?xkWAru2=jZ#`o zB^x{BRb~;e^73(JDEZE2l@Y7&rG2TL{t--dGV4!4cq<6O`itQWikI};Fy`@nzlY*S znLvjjg7N38u`VMOIMDp6#X(cmTpDu&CJo4M>97{^b-2Z37{~B?(TLx%phw@4IN+r zTsuyxtIrVDQjQv6wEx@YnW}50I>z~JL}1dd;=tfQxR>!?WsJOUMdD)6;bZt5!g{EJ z`BlZ0-Oy}>c|!&I6p>(^YBtCVxE_)6*FY823yJp5nOD#4z~C2>NH_ zYb(8L#{&H;z*_>b{te+=@@a;ydURg|;u#@-=g2;&3v%&YN~8*q#nIY>Vsw@^ZzmTx zNZ8>xCTtT31jQM83i4)b7qYOn`ojE z8CYnb5!FU41PiMin3|rJ1JYSLj#qdGa)~ZryCW&3nztfQB1wUYlpT+o0OgFTIB*VY zb}rKjH6R{>shH(ds|t&*xJMTdd*i_6ya9%}gvJKG;~_=6sD4ZUpib;fmfp z(Fxu@JPwSxKCUSvzJ7JzuUF;UcQz^x`L^}`23_>K%vVKiwX!nNBqyOu-MEkl)7qKq zs5hdEwL@0y_HJ~s`S(xRVpCf-?M}1b^u3zZ^)JFjBnv)mgGc;yiI33O_-L27-Prz< zWlI~TA(chEgljtn9iO4YC4LgoXrseKXB&T}pSH1GZ6x2cO;kov>-IJvLihC!U5a}T zO^sP(PnlnWF5Dv#w(R)px^b2e^PBj|H5&><1z4xksT@+F|6oA)BNV#mb0x_tp5Qg@p$V@r5=f zt)2xfeWZ24X)||P;5&9=69M|;c%1-95EG8K776T78y(rY^E;p<(JdxuOJUIz70RV3eNv)1-fiX)y23({IN3(xdeUQ&-3RaZ8-(w_z% zv48yEZM`HDbJE9S=aWlH8MVZJmWe1|&g}XUhfkJmSt#i1%l1h^q6v2}8FAPmwPKHl z*1;B~r@+7m`%U8L1%Xptm@!Qsj|L9krmh@eGupJJ#FFAWCBx7w0Y=dBg%W%=)(C;D z7HTDf*z^3<&n7MYoCq4j2gFN5-89e!rKTR6=T^YvqDfO?bpV(%FUW7B%=($Su;hu8 z`)9cFRnyeg7Rat(0%>sMB*=N<#JRK)&eC-JPy*Aig0R>SzF9qC2VML!JAZ(BB@P#L zK0VWVJFv;p&u&d6{R;(+af`d3hjvm?k`7vT@upNc451TMd6SZsmH1{$8 zi)6nVWjbRI1^#8{PRcc++nlUP`(lE8VWK<&M@pC(q0v~@qg&E!tGS8J`HxXFy9vR_ z^aoX2H2*-CXx!NjzWS`96su!>*6tL1ggSIG2fVcsj!=$;VF6FgyC_UO`j$F*c|j-U zq8%D|GH14kHD=1z)0jrWtmF-?g4CRt>7qA{#oe}|C=R~X-Z4bMoIjv-l;Ps z>kpgJW5crf?wx=NyJiDk8)HnWsZB)vLnN1L5jm-Nmis~kiUjuA>y*NO)wN9o8Q=t# zx66_d1dE$!ZjpBMG+0?F+OS>nOZ;WGKr$;{8F}`cH_wUN^7G#H+y>6Yc zHaxejp<>aEPlt4C`lhb7?wWg!PH_LUD|(+{lsc-D~V5^on)P zOI-K4<5n^`9{eS`1LPTjH<=y$Tya%Mypg3VwWno{Pioc|pJki-nCmQuk=7q)^_leu z+Gvrn$J2PU?R2`er$qTcI!sI{?+1GzE3y2~3h2*e3{4rEX|CNc0*^`vJSJ6^>ufdc zEe-DJVchY*vVC9Z7pPv&&*0o7_=kUZyx9`rzg*@3{9&!PV;T<@a8_z@wXU}_098X= z)ty+zU@amV1d!#gQx?Jv7(S)hIi=ZHP6jU^orLE9?x7V)gjLoimmyVcG3Tf)v1t@l%HCO}jnv~~%o&Zr!ySQ#NJEJ2 zk`dr;8erkf#G8e+{; ztR zgva}T5+UxI`KM==J4{dAk@y6vNWv!}%GVj+VXWPun6gJgfN0VXB_x2V2!N?8CX_J9 zI}_1X&xs(#87h*UU|HmA1oK$FH)qK6sw}PT?sF5;uh_0VqkzV8*8O1t$3#xt>04>_ zt7toqUipb*Ph%t-puyHhSwT2noEZmPBqRHd3=zdp<~l3wc$Zn3S;x>kTgqIx?*14L z@+}^EEpJ%f+dPBXWcF+|2`)12P@ekJ=A?3R2O2iG7D5ggg>MZN=^QAEdNgx4%2A&=Pns(rN0>Oc@??Ih9KFJ_ zAZwvHh#Q&b+F$NpoZX<3aHw8Pt8_qZD%QB^T+a_8xvYHJZ?n=dan}^k*f-Z6N`0qc z>|&k8fG(K~M+jkbOA=UyTLNrC?!qTW38er8BwW6qE1)SYjXiiryATrNy4U-Z>oG>4 zVKJNf?sAwodGHKe`84?GLq{=@@^rq@K#;F93N2}C>>n61rK1mI(xy$5;_r{Jn-th28z2szdcat`L!03gWTP+g z_EitsdANi``*ErOnNy60uU&S3N(8P8_Ufo<9s@qoV39?sPc=YzNq7+7f#JRvH_01HadJX9uKqwm9_du@op(KkuP|r!?@BvbzjnRtIckwj zG2rN&3>U5c@?c_AVRjAnuyG#OkbH z+P4qiD%{$TBgJDZWA@sI>3BE_h50&g-B zDNv`z5D3(1;1`O-}uTobkRGd_qWDyVgE!plr;%(K|mTrwum$fUib zG>&f0_iF|4Gl)TPn8TT~R%o@0t#0y80x0htmNno(^?LOwG@xjA4aR#u&9nSaHr^r> z#LxZG*)ZiiG-1t*2$#ygGP%W6AiN(VM(W55=Ij!T#Cy7}+C>>pKsRuC5z}crN3PK|(ccpwl}#&4h?#PA3k5?u zHpmKLrKUwbO*vNkHN=M}6+pu`=>?QTNWR=_Q*qTxL49i~Hb&$WL%o*Xt)IaZQ%U!?7`0Er&ma zO*bSXh7W+31cJ$dOH;|3oF;yhdUCN6gfB3nO0g_}^;XvT*vnaLiX?T7IS<93NsrQ{ zs}VCTl9bO!csMz|=NTB9F1&vSPCiv-+fMpJ)xVt|E9JoUI%SMY^WgiQDC7B$UG8E_*uh3{KyZQ}B8QQaFAnQtH*j%qcy?}F_{}qsLs(_+ zT3}|eCQ26;67Y|OimWZA{>ltnvt+7cMjYMG9S4_9TNK^dD&j=ZaRDZSk4FKVu}uk=yoUyX7lkW_3I+j{;tF}@ zD;=G43~8!che$-nBV=Aoa!-ab39Ek2ZPrNNQ46)3g0BixwSlim`pB(KrFXBSNiCPn za7fTFs?Ts#D2t*GvK`v!K`hCrK_KR-WtWagi^jqPi4E&6NGexSiYFQH z#WB5)+h?Gz^Dow$+#O&Gmqj*ay`VMg)|w?kwxLF2mxW06-2_T9X;Pfll?{YwvDD+o z5O5;u2h?f*#>rp@lG((I@iuF9mB_{M;0BTJs+-&O5lZ!<);<>U8B*^P3Su}cY^UeL?Up8l>Eq zMI)(Chg6KPe`H|vH6xuPVHK_WiR8>EEqHM3Pw-Vh7hTw{s72Zt^H6r<^i!3w4CZUK zgDK5gMtk`7;gmx^VSaN`*UW3r*7Z*leneTY$@W~*4iht_DnFbQvuM|GTY0HKwl#5G z*UzbrY``{a7}l$OtfDXJ4Aqf?PmL03$=2b_GhbUmE63ANlxlXs?Uks%lz;yr%j*|E zHhbiKJdOED%v5^%m`cl!Fn>W#{u}81(GM_1pZ>HCi(KrDaOOH(n{p>83Hi?e4^0w9 zbHtgF@d#);b%Wv)=2Wl_9sx{KuM-LoqBD6++>=R+YyylvEAFt4kU_@|2d1GKS$2<&dy%5xG7VYG#@rR*m08E>Ms2A?J5Y`fT%|mRU-dY);Yh zPGyp-_g*>iGdagUx)rqNI*M(-TdNnhza6hLsNk^U)a7C`Q&=1KAHt=(2NI=4pes%9 z!wAU>09g~6W99%X;oJhn+;+VZ_CkqJx6Z!SbbGo@C-@On>7Rq+5#!*6jez z-}FHXu*#<|W1{aq%CjnS5J2uXU~e^lZ{ECX{}jbSu!V5-IFMh-8$3-td~}{8Me18- z5*is7DG9Y4LmM(AwAC#w9c-nucGZ&_-tqOL0OPS7m>;`Ql{K-%|vVfDS zyh^}pJ@9lMSgs(|R$N^T`eG{#77Ao+!N}4jnDOUgJLfhdY6{Dl;2N<<*{CDpaKD@g zc{<1~&O_xubu2`YZWq952X1GF-1drz9^YG=xZHU!#-x`WWmxT#JEw%aJISjL#2QH3 z8y%N`igZ*k-phKCT5e?Uy%D(uxb(zdZaPof*B{)*@_?C)o@hPxV^;*I;jiYwr4wB> zaI}X%KhJqcoV~OIjnMDpROqBm4202wf)EU)R(3YSq9fUt!FWwmd?Vh*#D9e1t-|u!&T2SBZv}hv|1U6hIQioBY;{#;QJ<(OdM&|08JF7(*(63&uu=q z%NfF3|D_Je1?ky(@m`0ii^BQ}0cQF^sf9AR4|7yzR5)w{ZFTa{j9O z3;LA!@;>kTdrUkwaJ!xTV;dX$dd&CoIKGQSxoAEi*8{dO1j)Y!bLdq7Lp(88IT!lc z@-D@#QD1Ws)-8iB`IpE2xV79PAwW`7V4R+0YrWo!ME4;6y=z%_L03aJpZ{0#)hAwK_Nnady_(=$TYv9db zxuc*@YNPY)Qc$7L_(FLBR7YPhTQs8sNPU!DM1CR|Z+>*)MzNVGNU)?JLUFAGGeSK%f3k>W zh%ie~j&6XE%|rb4@8IgK8xoqp^7z(0V8RZh{ljK^wLq*;>r)Oz>*+W%;q@?q!Y${G z?4CdZooz>Ls!oJci78>9%!D+cttL`jhO(g#ksLmxseYUL8!-|@Evi{}+iQ;Fu6;>> zCn}R(s{jPpIon|@Gol)wq_b#Ut=1`vOtB)V=HAeYx-!(^FcGk78t$aM6BAlx zKhLhW;G9cyE%I0@Vs@TjYFO&?rjE5z1?ixIN7SD?kjlg4tx4W~uq=1G9e;+!>9#d=Xy4zf7ZC*U-%2Lp8H<{BQmxgea0}ZDde^2v`DuCJeufP0$^jXN&=aDZX zq-gu6C)J`lfj*oIlXFlN!`o0Wmcs84tp@5?xvW&q%$rzsvP_c`Yp;nXjBe?%+#=1a#Rvr@g8W=*-AbL-pVe12g+DgVlf$TTVDPK;MHji;SL{xzi8pHtltpbA;$Wg6QnwK8Yp{+%+|kjJ{j%w zjcONBts-YBaWkzsaspOXR`;me1Pi^kE;uYFl1;}60gQY344o3|D1qqYB3vK~s38kl zLFKy)&8dJY%tm;CPgG~JFku9b?g|?^F-|>RT|Wg%&}RZS^~THoFy2NH^hm|@7~`H| z8I9JIZwhLhF*e4ECi*u$YYv>!T(H;!PO3T4$QL>yr$(;Z!^kp-JhK@mPej|(6?-Cg z32lSXi3(9wuE&+Bw+m7@$46JT4o<8B#Rk}1vI-b=tJwlYA1rdw)}?@0zu++q4@ zqkb(LzqO1AEgmEX^y*B})sW@g6x0aVyR>@#kzJmM1}c(Zt70V6%@+kuaw=N{h*VJR z2JFIB1?TIQQAOoJ>uJlsuc&Ats8qHMwydcL6sxbM()S*PW~1C2b=2(!?N&W5VWHJq zc3pa|u85w4K0|kJuJoj?kUchSYpJt@me#I;>Uy)kk2UF#zQk?ttiF(0K9I1yCp@6b z1BwL#3!!NMQY)TPrDiQyA?_@u!T^Wa&-|#>nO`tb%^Oc1{2f*VNShy(!;P7P#izSH z+4>X;4y$ddRTZJHPVX>BCtK|n&K@-JS(VbRSoY3i9hPC0Q;Ze1pmeM7A`sPwB$c0H zo;F_tM2lI$3tziIMg?+{5;-z;uyRJI7~z8nLqF44K-ux5@!P}VpCI;LbO+WI%)J2S zUx7lo0VfftQwPB*Lc7T*ecNDn^|JqoQe>L5SM)~U?zwH>Bdpb)ygV&)WDq$22+Dy6 ztvWY&oq|O;!EN!H8Piz;Q|=K@NkUYwX~^6J%AnbwpHgTB7DT<$L?xT`rz z>sN0icjY@hq_^EA$9k|MT*C2Ua_xcq=a`qxvl+)0F4u{j*j&_%dx05Sw~&*Uv*ll- z&*Y@0bx3<)^_xMjilcAmJK6jumCM4t->(J8??Kew4D^y;M!y4 z!seYoV-S0EvO*AS(h6^}%35aR7VU&x{1aySO~x{fB(}?m$Ro;dU+Y`h);am0Q`A=W zs>eVE2i>enpj{?{bl627HVz=T=qU1GY;$aWXJ2o;3ytl}(*{*{4C8SPBjahB<7--4 zkaT#Y^pr%&luSuRAq;gfv>uIRa%-kwScYS2hNUbk>bB)U4C||Xb@`FD6Z~sNGuPUZ zeSP`4@gYC*%9*(nyjrH_3|sTI4N$4U94zsL^CNfrwm08sCjH{`3EvF+^OoHgwca}D z=w%dsYZB{IQWwL| zLn<@cR4Gm*L8@PK-~=y>hb=!LmeSQStsHQp+a;?(kD_LM%qiuPJE+D^Y=y`b>Jk7v zm3V#AN7|+aUy)+jsS*oy8sU_3ou-646NM+}Wl{x-!1HXi^-tl_bTO3KZp;UdcYvTdA{lCZP7P1k>;ljl*LyC88ube)XLHzsEfZ5Tzv7*&JBpwRqcUp`))>y@Mo`Q z;dK5R0I@$9#__6m_$PSyU4Wd2Ac(r~Hr!cJZ8s^V;d9K9@aU=d(8hw$@5L=7rm=!| zIfw0FyHA`5s;Xq@MC-^3*NdSdpw-)STIjtX%J-ScY?y2k9%oW=86+{XR^+`QF6Bd)V9D|Z-m|1J~@fnZp zI&OG}`OusgJlRg=QcGt&_sVW`Io%_L#y0aN&e@94sh(`0CYdlDiGtdu?tc0e8eHuv z`=t26P38rCHLp7L7)<_hBXaOckCdaR%(vNEvnT1Qs(ANdo7ni~_fbi4h|J_5vs&KP z+YNpZ%T4%3>^sEBV&uO7`Gp173$BYt^lZA?45ho!*$POe7;H=IG)4%OQ$~OpsD8%b zLGG1IYw`0%e_c_^CkB$!QRU1vLo8(z$%#03bnf~aI-n@;Uy8VsmkCOY8f-6KxK$lV z4Rg>Ij>rlIPqetCDa`X^AndwUPm~2lY0+ly*_i{Idx|+QYBH9gCfIoI+oN%Yl<%N% zuxYA1<&)Wp{=v}|mz()Z)<3uyeTc0S$W+2)y{W0Nov`_=rv_846LQ{xotQ09%K~UF ze4OIkbh^oJ!o>^iyy2@&5!Qeawf1~RJtF`h-1$#xu%&$g6jcyDlV;2LInv`SafoR z^DwkT%E-y>4+#T)M+9mO|I#rW8@>s6Q`JyLM;y6LiY%jrUJQj%kgoICu*l8MjB^&| zc+Tkga$n93L4W3xC@~YMulc4=KD4S|j5;R)!Lx=I2Qoh1$YZAiCx^!r>+3DP?IPU) zR-=MWnJjh05&qDa{~bB!faxk@MJGo9YqiFU=y<%d)X**nFZ{ROcqAb3I?c~W7q*d?J8h@en?)`w0GCId&F#SBcVinpoQF}dpIO=6)y9&W%>*&n6i+%c zC4+uiQG~`19)Qok6S7y4@pVb8aXgp}vIX&WyNZNzzDV-#sV+qiaAt+h!C`}eFB3=} zs46&~^Rn`OHT-qTR%>oTcl0Q)?nayv4rfb}K(#k%CQfGLE~sXn47{*HcTMb8+3M4x z`KAh+^wNOK0@*o}sk8y7T*noy%wbk z!P-D}891Tq%@%ui z+I9slsmt!7wH>2;dpjP>Y3@6R7mA3|N+Q*w5$l_8uJO;bHd%ac;Mi>&HI1?vPG&3U zhj67NHt*U*bB0p0LmP*MaV$*Q`s=wt@2CH|~ZC z{gF$dr$TkuJGcAx3m0w-p*^ap5rpD3JCQxXp1Y$S+Hq<-I zCyE2qeqx`Or1QsUbXHr-<&RlP>Uhh=&08hfF|RL9Rl8?wBor?k1KBHgo;8r34X;TNIleqU=yNSr|8xXbAsZ7zbvUyFfg)JvYu)Lt}0EUM6!K=d>L#aP^;wpdIzr?F`umy?E5$1^!$fGS) zZqCaH&xVcMJQ;egJ?NtysZ?pO8~wexreDP9H?FF?Tm*r0pPGd>wa8gKB=&VfrS$M8 z0LlC$y!+f*pWi*(T4k&PwSL+1g@;t^wjE_aNHQOOnQg)i_U5is2X3M!(N@@>enhLi-SIdiu zt?C-UgMgt`eHjmep@lzYFIEYa-$rpz5SS;#Sf|bY>MFWwr$(C{mQm&+qP}nu71BKz5c9c znPi$|-JG-cF}s+qkqD#EO&$tAk0i@?*`&G4GSM9dv^3eLa64qx+)Qm_rJ$GkM<{Rz z^$A(&c+`~z!1cPRW{gU}?}TlOF$Y^M(PJAGsPO?^nghn(4+~zWYVBYsT(L5X=9RKH z1Z1;F$EmIw4ay+1ojUEN)#Jt87OtY}ZU(%SrTd_K2KKccHy@{G2Oqv7urhV&VEfW4 zPF9!4&-MKN_$xTw%#1JBd+#V38ThE(+i4v5Ctv^RSLlDxZb0EOYj)Q0)zNM_}zhOesAc!&h1SCJtezL8%H&TLDRNGJkZ5ISuQHQf~ zHufNDBHYsWJ7!C?Ix&moruQeOZco0a$WmVNXjf4G@CGM65Pglv>1f@YzYe$NH(iTB zT^oWjce46{^~&R4hJUO)-6l%aDpfc;HOZPROK}nM%a^0T%v5K>b^kGG3F-2^nEl^r z>Fw<2!Wq3zNB*2;GeENI1Jkry%gV80^5xN4S844SB3I``t?IFNh(z|3$a#$6?9oLi zQ5rNvz@Zr<3|D+kI+XHpPym|0MMKImw~|N6*+ziiwEp1{V^nQ1%3+BiVuh&!L@l=) zN)`Q_iy7W4{U@)i!VIFr#F=#rb1UG`nz^Ua#P|6@`$7)$xjmF$gWOgObCJSXp}DTJ zJr8r4bW?9_8tgdct6~fKk*UO;e5Tf`%-X8V>Ure~04}ws_f0(|-r>L-iV~HLT8q$j zG_G={ti3j_@#U;_6$}fKZzp@UH3pQFy&Q|^*0TAy%-Xo*Xs62Esm$8D_i&SakcW?1 zOxO6L04>U)GM9Tw`uKuToBs@Ig?Flc0xo(O8P;C8;-rE+?Z#%p#KYj2vA$_lG2BbL(;$E`&pV zLy{4k)%(pr^iO(c0Ex@Sb%d$czv_IksMbSUccgTUuG0CiUFc(|VkGo6HILp~w-US) zbeQ(yXUUx87TaMr&2gKHZBGut+9-iZ%5Jr_78eX47!PFY;LqY#?N#}|ArY}R$}+b- z<~ViJSC}sUSc$s6Q=^6!cl@CVPXm~OsMG@1roxtr8F~H?$CCK&v7{6 zcB|oQK+Hla=GG2o0s$YQB0*)X2qfAzP7L9C88Y_+JKKNppfju%ksNZu_VwLpKCk@d z{ji~Uz@yh^@31i1)Z8QN)`HNC-u7cilermeo>eF!XRuyI!-}9884togygumF~pv+c-FQS^i{T zs5HF#3Sh-@vx*>-I^Ct!qR$QpOwu$#0Jpt#!Tj(Co)=7ju@i_T$?@;fIE!95I6qGJ z{adVyk%~d33MRA+<+^Hs8Z@v~DajgCqbi6&vFwd!0S)oPC|_JSR#gA1UH@Df6O(RT zI04sWNRxd~A4=4xS(d7nPzgjd(df@-?yT{Q)u$*lfxvvy?|UOYzb=W%be%^7RoZLK zgFY9pA2`%s*SEi6j6YvFvyl?oVW&*?a?l7Fik|y5S`zV{y*$Ol(GwM{plpPZwy1j< z&D!q49x-q|Qh>LO27SdTC}O9q7ZkhCBjSJPMbgW>$<;KrSl=38l6*yWdhsC34FgOz zD@1DR!p#DE!oQ1KB+lUqQv?mjm!5EE5GA{w!Qp)-&5aSC1B!f3kZxT!7C33k1BVz(>r@tx%zXh2%F1~E-2;(#xw5x%?ew+I<_}>eyhR#T=zuk zRuUg~Wm`K>cjx3ja_utAuK7x~)UsK7R)>|%r~QGbMX4srL*k|*6k$>?-xFh#Ej_!B zBsP7=d5}AnU#6+;@VYn~OsAFCGhRO=t2WKr73V(&u_ceIJY$+=e#PGOu2ojR?UTLM zK29H3eseO(@rsb_StKqOb3nMkp-n*+}%kySUCI z&`JcN!KJ(d<`B9v-Xg9xA;H((K9s1_8(Kq9$ytvk?_X(2LJt*!7CM2^ zIHXPS`6r9$fX`N6uC%Sgw9MzjDER0gP?|4X5;FbJKl}y$@9=%_k&CQ$N!tU zVdrFFYijqO>^+Z%-zICr@23*}4~rBGsMDCo`yoG;zZ5 zeqnjfXJ)@ZAhG*e$#v1~@hT}{Y`?xKJvt1S{~ypKkbFC>d_JR_O%=RbV9 z%s=4y9Rb(T+c#kVe4H`A0%e=bb>5rMHmm1If}yJd;-|)F8PBJrB?)lp>!&^EdPetC zc;q5GZA6svTaMjUyE)Q>ypuK>HVr);FD(A*dOE*gQr4pTOV6JTKk+%40_K@;9yYV0 z$Qcfz``<3Evn^#v^6OteH}~K7wuMq~+!w&G*%A1cJTBJbj@kGi1_X5Ba(;2vxh*hk z^c%o`nPiWnle5U1%q(?V!zd(py9-h>>|_FD%yMounE~i^rqm|kYO^OE)J^M}mMM4(K3yY(3#H# z@~^(QXSO$eRcC@=t(O#1;nxP|V+7>QKid~Q*K67*&g!)aX{H0>1#@1Th6+^13%j)r zii1NhgQA}p|BaK`7z#%1$NO66aiv4kp7L^r3`_nQUnufZ(jcsByd@EOghGumz4tfmfDYK|9bk@}m2 zfwVz}UNLi(VS^G?l4vCEb5s=dPj2YnTXGaAk|Jfvg@l35#uqpd z;g(-+iR;nw_X%tN`Dq0e-HchZi1;p+L?K~c=TYjUj(i+3ecBIs38w8Ri zkQ;QA%`s7|8*V|Cg0faf*w?%#D)KGEf21(#U)bwNy!tm|M*fD^EvXB;bU>To47wFq zv+*iY(W*2vVu^!<(6R7lnCyV<2o+%=hQyN+5&7vvvb;wwtMH7Ha7Du1lyeUz&FzG9 ztwl!iG#$tx#_DqyNaP$nSg=r8i(KIVOa2JjIK6mk~RjM_8tu&DdaK`W&zz!5`Wn4 z5EX#RPpBsKzmobn!!UJ<(+NrCU}zq?>*Ocz%lg{2*hDFMkRxoswSw!zA{7A&i-*t^#W{CeG;3j%<&8HDFOSS7Q~S+A$hAqQOWw6K(qmtwD#>X zafL;|ZOZNyPTtPBowCA=r`(MwgiZ4DacOPmZ z>rU#(e_$kGrLgPvjl!U>oQp}&Z8n=k_YnOB9f85`W=@J@4A-I|h`s}eWd|+T;ubb4 z*2$N3ZL5|#te}f`Fh8?1b5bW7lIs>5+6iuFnU5b}hhu$vGtgZ!|0(h zqk6a`!EApZ5R%^nJd>(AfG#cfNaQe0`p*rub(H({$2_MFv%rNMenLj}DF1Wi@#yMD zw#|IGz^dU4AJi+~n?}(?yV==jR$B^xUgijpj43^`$n=N192NP{P~+{BW$(Bw7)-g; zpyK|8f3`Wd91lMLWh*!j;?;r!3_`+^TIaV2pu9UNu5`+L2fgG`t#Kf!FdImwr7B>gbfpV~hOw=CP zLeN!9+tsKb%inzxha{W-^g|8C^;t(G3{?q*K%fpAx^ZMaa>a=%>zLpPB!!*XCEdexfldisj%xbF zDq(Aws*^-~JyPIhAC%ctc;HOvDsFObvHD0Z8Y`0IOAHuNLULcpFfvHK*GFf!0fj1V+k<@ukjcY%3emd?EZ3A|F@w5aL zh_&;{IBWSjD$gThjl_p}Qn5HSLKjE`#$p+(NhHfzmd3BSJ=)6p-85%tj+!#$V zG8W@&xmSaB_x#;7RCNzy)vnlIl!EV~>Kb(TVt`S47NM~_)t-geASG+2uV$?Yu{-gD*aVlZLGb>cX*B# zvL&%wQ83xh7aQ+H8>6_6ob$L0o8wJuDxo@*+tTvhQ_f&&+op)y2AQkQy(>0?mWub5 zpTAayqQ^1sbp&4tre@Y0llB{A)a5WTPS3r`E=*tEEB>hP zub2dPc%)H_(dqmiPO;1*@JRfTGL#24aZ+Pzga3=`(i1GWAc+whXoaJcNv`6g5uhQ$>KJP*y4B8+6yMFRLF){9|n zQs;Gf=5u!RuqNWp+;K#DI^6tLqFrjct)T)~mXbR0xYYc1{bzA;QD_m6W-m7f%pYkAacWO% zWyoyV*or|3DJ8|}X=&DG#5`TI=qDj2lKJ$(k-B^Yc;yJ6Q;6+laZ@QzvZ<2%FR#`r zF(lNuywuZUp@~9Wo6-up=Cbz2Qh_nGj(s7ad4B{IJ?DZGd`473U;jIJ)BCZ(!T~=s z60vWEaA-fnNBIK^$2d53h0gJ0GeE@$&Va1#15b+zKhmTkuXXX(P#pF%Q-;U*>QeTg zhOcLOk-y!fbk9i*lY`i)Y`L!NNvOemBfovKJAngTmi`6=zb8BOy1UvRzeeiL! zz7+=Wb=snYSL+a8gS@-*gHGP@zvl;Be=R-@jAv$aim_HpYWE(%(fmm;(9xk8I7Bw65N?o4u|FmskkG*}NtE8^mwGS*}>vN$V`7Yn#pf`X(@<%0=a6;PTNtohAtzLx+v(w`w5 zGiMkh+zmVPC=9Zs7LZv`weB1CAd?2k`;jZC8Tj@gq!Xc0_1n-pSRJdKm4v8U1#~M> zVWt8jqey5fuVjO4W@1hA{8V@tyw!?FmHLdHl|az@Z75byF41JC79=C3M+fFa)uIFutav43dY%jmg~3g=bQP4v zI#SmYbl6nU+AY+KVI8C7HBJd#*;wk{gn=OX%(TZUSMomM7htHL;EVE1X+0EvkHQm| z%YYIZ>Okod#gE+7#^RRU*nnqH>?poeTr(q&tkU^Uz*H+8Iee7vfxQ0RfZDA1LC&-p zeQxfw0`u4WSc!J4MVZ)ne11B{bTXMgj59e|rS%$PcuG&OCn=Vncv5p?{~VEU{Zc2Y}3{+xp? zmjSFA@;yz3cv+4On~iC5jjjcj`Gt78zG<45W>bad^o6ioi738g;{Be2r{9+h?x42W z$@Gq54%C=Qb?B}oPSm*Ba&;Zyk1Cvi?3;gs4}!WcdRG#MDdgO5(FX>$)<;#eI<;j- z?%7eP7;5=P{KeUk5kelf0Mbq8Q>7B1ail;=NZ&=L+;Xl6ZYpc_bF-RBd3?Unwn-?3 zb#Qht!bN_MwJmpfOUd-T9(cSHRyYNs<$mAPOza22W>2WXTf}Y-l9o!!HYih$I7fHX+!hzpwq+WP$=eQ*cbJt3k+_>8PO0LlmcCTl5HxR*YnJYJj)L8m6R<)EdK4b%P1|I1^ z<=STnLS~!Q&u-v1>99kfg4soXCnyBuY?g?~Xe>e9*kAe*%g-PLKm8} z)q20XJj2&<%Z#SX4b-WjAC|LEU5Qjz_f+zo!$=IM+13nEv{X zHM3_&UR6V{k{bu==RQ4A*a+1`WqhzrP{fq*x7VqS>G2A;jq2&+7lc1y^YBO!q(j|dKO1>Ek zF1UbQDu^L7wni5IYmiR6%xXv>ZT^g|DQX0iL>X(hzyxP1rEfvy6s$?t+5zcga)&QF z4&;S3F4=}|t*qp-F*0I%zyNv8G47S{9i!+@0nZeF?i8m29je z#{#zAVHBOimxK5rJwE|ORv-_%Eh0CUizlX}amC1=VH&Ks^NY-*>`|Zvi%~+77(xlv zxHih>1u}K;5EbBG!7K$D?oEqwGxZP=rJDqakH7wEx%}d!J&3=;J9Vo5t9 zeaDooTR>lakA-s;=E8Sa+eQOIlAzG)V-_2H;rLcnijU4cSqI&iG$45+>jj$t2}#+x zXd#IZm6;x$wc!lXnI)SQXu#uK?P(FsoCeql&MXH1o+&3lypj5ZLXm^K`oVSF zZMz_2F=%CJZ_>2dPN1nS0<%Vj&EtFuV=e}SRvSyt2P!P^o(p{eTxpTvph_&eaKl_m zEXV^Dpv(%DnCZkZsHPXN@?EvVsA7AxfV7;`g!vD6pkdI*X*%WM9u|(%O2%?a=^Kow z**}hv8TWM0K>Caa^G#gmHC?@8J$#<*QS6Cd^a20Qisr!cgN0XQd9uA-(JRYZiJKZ% zs9?K7jOs^{;L+^>xwvv%)*sA|{uf+vHhrPzC!mxrx@>)~*9v&+TiFTx>jWV4;y?VH z^G)4bvbWF;xOQi#UgSL>A`V<9%Zi9@hFjBXE69ty;M?{0`V&TlJuho*a?kbmYO8oy zeion&_iD@dSb9ZJ{m_NBd4hW)Qm)NlDGb?G4~w&(_5nCs5x`zfjTk#5;Ba*AIk-D$ znEf#&Hz2gBorDD3P%^%ODSJIgoKSlgu#U2cl9&R2<8Tht;2pSyaGcoY1#0DWxuI;u zowQw3QTv6oSbO&Ry{kU9sqvwDh7n`~5L3?ecSUKpwo&^;9vd$Mr|rOWY+1GhbC=zw z>r!q`(j?;GK**`+&}?RoL&N!rScKzCuqMzI&A3$;pQWTDgj>$mY|x z6L5Yx3oE!a!xe5@yc%6xj$_VLvC;n$LL*WBa6^pAQC9j4qC-|?U6m~FfSq(t#PaWT z)Ew=>DZs&_2`M)txtpoPYwwk9lgGBM<@Iejujw3dTi3ro+Mt;Wu^@HF<{7i}ie7mN zf*!++5rwTB;8cA~drh_Hs-IqHMKu3)wK%Axqnm^t7ay0%jm#^-Zd89wcF5tZPv&L( zNVnp>4CEP;J^h(lEMHJuu)jDFr4%=#TX{Oj@yZ9u4PqLZgYRJ!k8meEB; z-|(PG=LkZF_vwzM4WMh^2J6U6MVJyD1a_S3(#c-+@|Ogcj+w5l48Rf7C^dSoXA>tR zOJo8k1P#UoGTp2(DA4L!;5l7)WpLJTj(D}rsyiOE6vWXCq=yqbGQ7s<(OcByt2esO z%j57>s0n;_&7rLQyqSGn&#{B-HT{umM&csYDQ9K2D_8}gn#w`}eee_%tpm-??vUCe zNd?6ZY+tr2N1au}_xrZ{`{(@pZg2UXE>n!FwDhy(xHEtYPEKz33OiBF{+MYPZFmeJ zmnLB7deCIyz8vNK?SL)4PnOi{UXJ(Bl~}j*^2%B;{5luG3;I@n0OIqa%8Pv~;~-J< zDxi-eYDM$M?(&mt@a4Sx)xxg6OI$Xe+(gZA?TFl0?kCnz!}A7M1(vMt#nAa@?jP-e zP(jO*=rtquqTRTBE`G;fX)5CtHZLDWaX#juipl}g3@hc=?dq{6bw*_5bZi3Ye1SZ3r=dU#3LjM-0Vh3(B_ld z!!p@A_-y0;ijc@Ae%mXGBxtiB!_EP|TEuGmOG-Lt@?&cVRBk4}G@Owk23tLh)lOus zAE9meiIro=>LD-B+GmRhJbe*|g|S|pNv*OEi+6WptJ&5&Lrq(DCUrep+%rg>YO%Of z$VEsWLpzSgYsz}moTMrm-sF9~>MNeD90I^Hya zBvK|=y=Y7YXm7eOwM()T*+7{QXgd8F*G-}$Pe|gvXmb0IQDV%&n-qcEP9k8k_6KBZ zwW=?P*#bH`*QLKqPxnIV`yra$S54%dols{OR*-MxJCbH3>y^#wRV#pXRru5r?Cy3b zfkv%p#7T^5V;&iQNU;GqPG|e--a&A0q=jT%yDJA_qZ6Va9su@Og0<4#zIeh1Q>h*UzG_sLBs(pnV?2@G4REkXPhD(bboZ&XIYMn_-u3u z21$(YHwPWv#W&DR8)&1l;t+Dqh@%>m2l3H49LAhmz{o>rIsM^j^fEwsI^m8v{l#Mb zj2`(M5;U^1t}w-|OB{|r(cli6u8|@SP-OK+tc4)nMPkWradPRdgqbDZpFPj_uguuH z+dH>-G(CI1x}T=n_3n)EbQcN1FJLn@(Vd-BoEdxDq&-n9M*0f2WvHF+y`Mp>&|{~t zljg8v%+Z#)RK|L0$XuY}#Pl}YxL1(8Jt#oP_6?tx%aMUpDbnBeDRn(wuJ81(ob0Us zkk0)~%LZ(^PxihDx*cThJb7Z6S~bj;?&1Lky}G$yarEq#JcwAO+c!NPuHUr+UEhGc zXA-X}o0(iS@I2@KdR+AV_CMzE{0ZArybU`sqQ~3mR5T-*tx7?&CSg|p(EIQ2YBp#? znwo#YBbI-{qyHx>&ff8Vl}G>ntC#=JcjQxkv|OLvwC&$!p+-D>(Qg&VX~9b@kSFdu zC0fFqFafRk`?`HElJacWsS#uYc93?oeeeFdbswusO7T~+PTnI(wN}hm$&o5+;SLPk zi|;E)QK`SJK+v^U9NYH$4qlQcj}e(#g?hg;IQ~9J*;zEyJ0V=dztK2q=t>gg0B~Fi zFOLu}F$HX!tTxXQ8L@hv>dhZB0iU?}+ zPMl}kK#aObTe0;!ckrdnDN--2o6u*iljyjj;v-g0C)VX6f-xiin4I-m|4i~Xn0NVM52|32E->q~g)DbK?- z76pyJn#cg*)<|SHki)2Z3{0bZUa&&a);Ol3x<|cIUKWI8t+BF@g&I_ogro;gwGPFc zW5tEUv|xauDR=pz@~jmRmf+mi7{5^!P%^>fDk{Nd=Ma~&5@i=$w5z`JfStSJ=<^$B zbeMwl^BxII6U0dE^AJ@UJM0j()bkx0daO!92{WOTbMFD}KYj!h=(Iqw#E1~inFT&E zPCoo=qq1+FfN)4$a6|PnQwKCHX`>P-X<#W^=kw6K8#4$d?xCE0-pw9*;m4GB zBxRF8tylr89e3Nyv}W+u3d{?F0brtXFPY_2{F$=-TXi~u5O82a=T^@~@v!v7yA^ZB zqlsBEE@P~zMk#mHQBYajDf7eFw64m`X?&T{nX(lz^RF#CeRKJIL#NspXn)LFd}^dB zhfiQnXp5Jl#kvZilzLO4>?|1g3hD(=aUP@*_-e;t3G|^DX(DxzS*@NLNzri}l+S=7 zUo1BefNVyVXC4|e2}fbFfB=DU5=Tsk4eyS6UESV8V3r6&p`lns<~c-Du3!-=d#xed zDAr-+eCa->tASKR3?D=PWNGVtCDtyXv5c6@282QH3MT{vcTbRvC4~~&h?Avvn2Vfs z;q4m8mFfPp%x6ESabO=0EoRBoVYu3!Ir-{S z3=S*ty9CZ?*x9>-2H4XX;xB-`5O)>he@0RYYToysba5K*MqZ(#g7s^Y24AlRmJ8J{ zH*O#@@mJ&b>{jjf>=xOmD|CtIvhqc^+hE1xD(b>iZ0P)e{m;_kv)Q`CcV6Z;cks`0~4p~N65lUVy2$3BMU)6_4=PlHG9Dn6d|mh+oMbC)-&R!lS!Q9P+3&}h@qZjm1;SL}_%zfGgy zeUVUs4M)XlZa5*7?Z4s`8=gf3!|uTkbgmsfZ*Vf$eL;VC$V!}g@qJiUn$ zM&{b%iw)a@NIcCHs@M!X5~)i&U)CX zWH0(@XCLxw*bcIGD?x?Co~Pwmx)^Q4ErX7b-ev!qIh5v}MP+gTs+T9JM?-vt`VJy< zHE7Xyzq6Qs!~XZh=PkrT^+*T+;5P~Y@Q;-WU~6Y=qGx0Gk6&iuMCat;6_6>`Wu-;$-Ls4js^GiH zbFQjH<%AORK*B)SLCm!z-ga9nZf%{}Fq4vu-3H(h*Tqzxb=1^GGZ|whEVE@Q-M2W{ z!+*4sKNl;VKZt(Vd!FG1b*iH*G*c|r{nQR_zqNkxm*^H9J7!c>RF4YDBV}tRDRo3= zA3f@IW$9Tq;!xK&pN)NDhGXE9B6U$3lm5O{sq54>PF7k9J0@DNabm;Z0fZ0s?+a1i zJ1gm+T>h!`%jn5YQeho0v}+iq24#M)>gXKl87r~SEy4btJl);hzJmq-J`0B5$6+aF zqIqbDjAZ1DT{-V%UFVcJD2VPfN?}@cJdvESRMaW=c+)y5!CNfP;OY+CZ`WsHym?{J zqw(_0W=k1mG?INNnLxD+`2j4!2h0}H6hW&TE*hYKFhNh^l|!VbMb+qehaf>Le!F)- zPJCkjI8GfK^IvbKZAiC19k%|LEIUR;XBMJ>>@^(@TTn!HjD<^1cy!6=p)pHIpcbRh zs#@66O*tkvd2DJxE5?uQ&#opW*Xa#wc3U-9ce;U!VnmUxlxU{-W!11=NXU-_ zzbB7mdyn(DCy1+e{Q|0J@p_l9OWk(sWxmmtb}Vcaoq97581~$!}gwZ^;tRI zA>A7W=b31Rhjdj=Ye7~cw?Q{&FOAzMTqd7PUEM2da3QmJgulVnb|vBf(#hYhX{-{c zS1-vLhp1TGEB+|86{8=?Tf|Nn5rE9$WsiF;a_G6H_saE^@a;!Fcz)QXPba=@j;=;;(t2T^v=KtI%kxsg8 z>x_T{*kphT}x ze7kgR+AZs3?Udsi-V^K~B`&71prQE7SPfA`i(N0eAt#d4lQTQn6u9*{UkK=Je+wkY2RmA@W$idEmV^3Bh$$>*9+i8lGH{VI4kZ8G zh1Ji-txk-#~xgV+>P zl4$9PLPD`?6n}hnDpFr?Io0FcorQIhlO+iJ1}KL9Dxo2YguZa>2!ugTVhf5G3KIv*4BJ?|be%4+`Z=3xGYg00!sQ9jNcfKfU+*FS~}nhpuUz7}*^3 z@BvTs#yuJgvKi##6VX)ud7MOnv0_8TrHbYhWT02@GeI|=n+SoXG=U;QT2{8(s4?qY zTo#fz*tm&DurXXDv$o*qF{p&IY^3NyoHo`I(Zn-dd{}v86m;4=T_pTdTHr=ess&b0 zDaK*w#}&ZJrLP#$XiOXEI;LU9hH_>NZ}$y_1azf_koQC)*14{kRFJ8-#n3-o@Q;uv z2q6m1zuGK_{I1a1>GP)BdDF$9fma~E!vo+XLHx6FoqS6r|5bSH75*P#>4&NbUrD*z zh2cOO8}`u=(GbvDfQOIeNf=dpE^AMG7kDs9kE9i(tW*qTjOhK{)6sdLpWEy6X@bRf zYA!M+W=0JDwcg}*_+AjI^(Y9ccd4q9>-(nq zmO7NTwy(n)pZ@)UF1*UYd>{j_O!UP>!}_&8-JEzFSs((gDIYvIPi^%-^)UrYoPiEp znvG4spI6$mX)+b#6zeh!VpgDui3->!1r)xg1!TTv1th-3fp$K;!9fh1r)w)5&ph(7 zXO`^+r$DQi#10Zmii?(jW(-#gcW7aUX*foAOmr`3=Op0*^ZRJ?{nS2w@phJYSB0Cur)#(JWWEXT;{jx+mmCW zNI_o!g#d^kwpQ98BI7C1O|YLWi&=BCfWSud)S&g)tx zjktgHA2qz;kbt4yC!@JqREne-HdG9MKY^a^C#p$Y^E1BgI8ZuBa zC6S()qp3T273%)^NDz2HXiS#nGNeuTY}skWz4R^oKpDLVgD;2L8zNGgoUgf5SEPJZ z#d$15{BmgcTPyXSsD1tk;mZ3}oJIl>yy6;=URZjsDPf8`SQkOZN_r{lmG^;(FW<|c zfQIqyz#a;05h9R;ot+T2gZz6)96mZqejU8GAyYnl-fi~q{)uA?HapY$I z#PZK(OfNYQouQi0HKmeNM3A7b-5a-{^{2#+>3Q*9tq@hD{CFxzR}cd>T{^b}NRXx; zK{fl|Vyzxu@R+c1RGoWGroqnW@N5Oq;JvrhHpbx#;kkCYM(&%xyHMbUDs4e(akem1 zL~fRYr2x*nTNGh3ygCqphEP4gCQ_Ks2qa<$bZ7XtpRya2NNLM5*vrlX0&($cP<)U8 zxjayQfb{z!a;4I!z?*1;-dyM_ykt{DTjui42*ImCClP#N#F02i2h}d|d5J~)1Yf;{ zR-&{=fXu!4M`_CP{+KZ3mhSm7V*8sM^UlY?+9xFsT6EK{bdOC-h3kSbg*N3%jSP@j zY69k0@MxtbaYY~&Y{-LEUk=5Rq&GumOV43vpCLa_R$A-+>E8{>NOmCYh#F0rO1tE^{iOigPGgjW$WJEmKtHCyLli(`#3_ABbJ zV@^Ml%&cm_1JA9q+sNlb|3LJLQ__&*W$tuJP{HnjmxQ(Qb%>zo@KRV?-mLi#yO}I; z4SWK319RbNt&-+NQV-{pkZ7$iqEEA=R&_)9%2K5DM!1coh?vqg@S0-o{yJ-a5Li{k zu;B@otqt(S;x*<^EHKm|b-=<@3CPIN6{B1qgM@UhEd=s`ls}kToxLBvs4Ej6NMs$` zQh7Z&mg}lMh&f}|SBe(uc1(gOr{x3@8mRO>&<9chkARPa^F)d zrI4#45`--u%SA(Wv<@Y|jejG7a2FeqPX2q@aC=;OVSUUd>z5Zc^>*Hvd0MBl7jQUi zy@{tdKqsoB%a*)Yu3gSOw}P#e>z6GJty~V5PUIT_`K0qY1@j*(&1=5Nlvx29mT>`( zU*Hc{y)4F{>o%i$l;ks2_gUMcSmnFEu#x$nRpY|O@VyP7yvLo6^-F}`cPP_Whp*Dy z`~lWj{@^z=n_x?$lIHhZzYmQcQ{0+8gVx`?&hH`rV)*FwCcVC+dH_-a!357)(j!HQ zIQRJ?rjK6|>TKM@wVa??er7%NZ~mEnlna`OT`9u9XJiI+gb5vs==O0Yn=ydVqZ~5h zw1wCaPi0(hVn1;YKYS0snKOE|n6x8=DpfFx0t}PlV-eMA$Yc*2KBP>o32IBh;vFd5 zv=O78f_Ve`vFT$;(R*^uJ4KgO!OUQpxNbqQ zN(|yR3(AW=p$iYS-cO=i-I1=ic=2-s-rgH!j9dbU<->EHe6E|g4hLOR{K1L5Jp0~k zhwUDRZ(maFOp0YysO83M96f5dW})#K*vw&r?mhUiansVLO;2)?vq@W_QhnK*d(c?! zf@HwAraRk0>jUv8xFhibFzAB2032bZG5e=2-~*G+omq`HNsl$tG4`*XQF`6hs6Qds z^xxsQOeT6;*6gUM=$5G~!6G2D#vZ+qofig{ec#MgK&w6TDl)HIK}s+3-8w_xw`0wO z3M{kXk3Q8G3f&j^3dx?G8GY&WB5A?ct*xY2D#xN$5taek@s60zYDf6?N zJj3Y6BT4?^+Ku%TYwjkBRPIk}nAWLM7^MCgU8B$1q;x!RS9d%r#tI^fQibN1O-;D8 zZ*T(z-)#8PV#)atJ0d8>m?tshCgzAcMQV!PpEf*6U+w^$VZnF^)=;jIgZ{^*k$?s9 zU^mv3oXK-a_B~JZHBa<0PxdxX_M)%IQ9ps5{_GN+858;9DLq`Kie#hNM~h9j9W-rnSNkJiGKb)@@-kP>{qMQ@p5?ahWys8G7=RL(zD0LIvqLM} zRA<7qvZq?TBU_q|011_vg;;H&G;=n3h6<*}#6c2tqD~f>-mr6`m9lB-pKM<(#~pBO zCDVii7^))2X>J;Z8lc8TteOKo0c%K)c4=KfSt{fi#G1n6Ai}1}FRZfawxAx@IGMBT zoqFGUz=k=E$Oq3Iu##+TOBQCBb>I=mr`p`-Q6cK=w z;%5-!PGe0%8RCk^p<$_OxhPT7jBTqKp|VVoQK zT|#&}2249buynA+h3<15fABsK@G!$s#DH(i^z)C!3r!?~5AZc(y_>MFg(rc1xK}jl zXDTl17(DifP6Zy*xR>mE>HMICKIg(-445{=FgIK@Li2r&gg(nKu1hgBNe#gFzL&yY zm5}Hldlbcf(nGa13vTMmH03TFytj~jP72SMoG=?QJLbp2yPYTRE^U0bk~6s@m&)C4 zeXfK))?$-FKK1J&wsH!#v$9Th|9*yX!>KYeKFUe>wu>(&clW(E0Yq7=%>D)()sm*Z zT>Q#3nDO_JJo<^B$PGW(q$F4q{YqKZEiUW~{SRa35F}c#Wzn*2+qP}nu6kwLwyjsT zZQHhO+w9lfqd)tRgBy{<9Nau{^6a(TYvqRSBa_<?;9$MQ@eAdm6K6cQR4bLE&Ou1V8QI?Frr8~gX2w1 z<3Zc9ISM4#CxVE?7#f{!&y|(xgd$g=QG1?IZB(Q3I->HHq5AAmaV@ml=RG+U0UjBB zJcoPp5|w9gP3_>j2o6!rOOzN6*`CMvq#_XHLS90$WoXDaocG7k7Z48u_M)0pn>TLU zF*KpPiS^6mn5AJq+3fi1qlnPToF7Qe8%BtYGuk32O;VF%F}BcC@&7KET(xrn8@ezZExc+gOs1V*y&;U+AXVtST0a7f5maxo;{ff2Qmd2;tH zX8M)HfoGTjDh-UtBEFZUd~bayMT82KT5u!P`=uQA!AB_)JE~O)LOwSg>ZLeGeIBn6 zS%*SYMEJNRTSULr%_!z;E z>agVvT~k}M(sK5lf#Xf)t+;$Ne{<{N6Cu&TEK{2wLE&7V_TbS&5=C3-la?W$M+miy z$0K#GnOV~%=lNjFYDuMP zdJg^bSA#!V&*np0KBca^+rx}}_3Lj>K>Gu@-T-r_ zqCD;4!6(X&{M$vlN|R@gsAwg6S*7{&S4O1TEZe^wQ(e)@Q)SfZoRz8qRqham-mPDS z={y~VSGud^6sADzo270SRd)5X>K8R2BP*{A9jONgn8CkVl7DcEyk6=IS8)B!Z!IjI zWMdkg&N~*%L&_sYEfKCo{1QRz>VuqX^#9bR2;8czoty{Jo07%8^d0rOK}JaTAYm); za@2%h4r+^Trxc>k(&hBHJA7G3t7kL%nHe590mx4Fkptv4bh}e{qdu!&?PHXA`@DwFJoTDIEgTF_U0X zf;mz$qAZpmCuGVJLIjCZUWk6f@OD;1S5>23fL^e(959TN=nAG_{T>rEZ0c=E7zWoX zzOWFmlc^_{@H2h-k~7S9!7z`zzxvS~<|l-j{%&Y)M53mK@rr zz`)=;tC-bEeXcrSOC50rFtro@$;;nyk@n}?x$gURym3QVvQ!qN zQ9E3}Mf-@UnqSE7utO-}KC0!+_7GagwDZgfy??}(a%l}NV8oVqDxG~yLm|BW4&YB` z7`hd%j?5n>orJ)w`eCjc4keNX1U%9<34`$d8!2Usmm>d@hUrr|_82nJ&7+eH4F#<^hQlmHX9fPFVqXKHUTN1eUSmvt#p z_W}uUEFJDq}#|F|G}ln1FK87)e(6te7zwp!90F)G{3FVCCeluz%5OW8vkLkmp6?3_Xt4s@B| zQ5&VFQX~T>PjY29dS5?KErqafzm)TitLZkNQeJ?CF};@v+9SfG1Rv>s|TcM}``ua>Zb;%EeR%Q~^KA=ix zc=7G@N9nXQ>DWsubdKyInq&Y}cQ`YB2oqK;&MuRl&F|o*m8F=Yo6Bj}5Ru48Gpx zp|$vZ`FFAcjWUOc z&neUd7*cyk!@&meuLZ&dBpw@qUVfgRA370PtsH!Z9YCA^oh6`lNSfVaPbvuv8 zT&pbxkhZJtJ31l1Hy%eyCdqq6(Is*Z;7bLsz6gu$O9k`kde004i7JT$|XkrI) zTLb01O~+)T-wP;K#$jK{&p4KXIT)3GGXvOj2tJfK(lJH5<{Ucr5#4ZIoPb8rk~ic` zpzcGlmz7hbPUTRB-iL9&;ye1<9%aQb2EzMBj5UZXiYK~&9$R@4GMy;p@ov`t_0MQJp$`lNr9yPh2UtQ(M+W}1j z)ws^%Dpo7SoTXDM*{oySUK?n-c26mFk&Y;rvGG4ut^8@}SG#2L;O3E|xgKoO3Y*7T zUsi13T&uizB+jvc}sk6{quDM~x&*4C|6 z^1elNia1CSLksWZ4go#6nR`C#%g*5Ap{2d`zZ8QiH2wuDHBr^kDYGQ6na>aQlV=_Q zWLQgq?f!9NaljD?GWQn)kcABpuoJ#~mY39Wzs3SA<>4%Y&68(23ri-r5?VIP8+DdJ zTb%0IZzu%jiIPVknh`cYhxO(~Wm+ner*IV&onsgmOnXz7g3+2<5MIgmO|k2r9CURA zO#?voO(_?TK2FS3$O#td1poTPp}Xt*?dEj~Nk-U@rpbq`>v4)tk5;F=T-=cX3_Q$4&Rdf7c`4}|MsbWA=7$~!^X6YMf=tq2 zC2<6|eqvhp1O!jk1(lIli18)7JLcd zGWvSS%^<^5Ga^>$9Cm0eu^1+sj+xm{J>D%oepPS1+88REB&w)c89sT4Y(t-PFY-$d zxLwQm`0eX^`fR1&E>0LOW%~ZcHV9|yX>NBJMiap4oHTxiu9&<_&%I;^E?P;zE9L9t zK{8|z(xHqXp%BrH7C6OT3SQ(X~DVRON2V6MoS4>i-Jz)2KD$4G^vO0RPnT z{ExigqTm3cGimM)61%`tpnK^R)oC#b<=a~Qe#~ak)fDI7Dc(toK6OJzY+%<12uf5n z$G)=F6=QSF%C}2KHO9V`tULXbGTj|lhIkxlq|Id2C^{~k$hx-<;&d;tuhFrx(7C#@ zJ<3OB3XH4$ESnql$0<|r;vMdf>czWm&&NqeXuD<}KFj=2O7Nxlu`ra6wn=JY<;r@@ooSHMUtX&+d`2O<{eaJ1YMkivXlrWs@Cses@n5=@W|$6}ML zh~+4?X=##2M&EOD+o-|$1k+@@a5uqq+Ej+BPJi0e#Z)}z0HZ*lk~{gpEjONda~p3| zxHZNzK}iKQQgG^Ep%R)5vG+2$E?OP0y1M53QG_Z!`|G4BU;P?wI%M7vzYL1LFvP7n zVmxpm)twq~#YyRPbw1}c-uv`n)OQ#=5RgzyyV37MfEWYQz&7xxn8>wc8`XN}wFWFc zgyLbrW8M;vyqJ9$!$b=dMnr0HT(-tvUqO*ZSrAMq7f^J0#zUc1B8Jw5fc9fq-V5yh z*jbAMV!T+WR4idT*nv9gfLjSvi2K=5?wjE&7mQiye$#Ja?QdLsmlg&rmyvFdZ??x} zLMc{JPTHbD&+^Q>Q=$7qL>|E5 z2=pqPE?M2(+RAh2zb)))53IFs2%!2wp0l-EkL52}k=-^LB1!t(XB%*?m_1(wdxGjf zzAe!=B^FqHUuEW(XPA252_uvT;OLEX}csC}@W_GSyDl z8E^c76W`ciDVyWGLY(2_u&b<8<46foR|iic7X~`aiASWJ< z7gm_lB;2p){D+O|;m5|2q7zx*x|T3&V8G65EfyZh);bCGThe~S^T^;OBh9}3NROoL z&iz0x_~g1c(n|$VYzc#BD8!r*Vhi0*5|x&O7x$=K55X6@p1`Z;6p#MM9q6(6g$G?q zc8FSW>!I7!*mZ#+WL{?KC!ld_azz}_&i}&bw@YHR5qjdw_`sM8@%yy*&8+uk||p=?Zm)kDcA?rK?-81u5P}$GVI}50Q))Z@0+wh zFnygXAZFd&5rd<3n>!??QUw4WRop{ob~x|6*F~^2sDmme^?oeu6j?;E{Ar?W#u>%X zC+#UAtxebvbHcgUe84KV30L+}RwHbdX<%4Tl$w<6OmRT-RPkq^T)E#mf0}r=E`R_t@KZ=IU|`u`z5&oTJVx5tuAR zB~&-HO^?xqXD~oui)~a}@^8uzn%85=G^30yuF%FISAm(hM#cfBJD*E}8i%7mC1uwv zKVl1CjCRKDTm*SMD9z8~!5G|Pd?C^yQA_qlqZZ?9jJTEhLoBo9aQDp&&3t!%O)yomNH`(z5CJ!XHIY^tbjT68x@Y}ZNRz@?e-4Vp zsA-|LD__XW0Wx?g*P1(3D!AeBBk9q0HndVmUkm8`TCxWFdcPLZQ6%hk#VSX?Wf97a zGK}STL?`#}jgTgnlw}W>|4|90gSjefM12bh&#oGL_-zOY$qvV~k$O>}Jf2pV*`N5| ztRni#2}8%=Jzf?)E^Pw)U)qp4C271Yb#cWt?wA6U?L@i=m2u-BcH-pU=x)hiPeQHZ zOMA%`L+EO_gwqmp02--uWVs{bzSaoVqC91dFv6nkCduvzeD%ts9MHY3F z+oY$zI3Kl3^#MY(^eElXFO`Fkrx83# zo^bbu6=6|v$}nbZX&hyZ^R$A=5p=Xzy7oJdR7Mvb%8!|we^t2!=cYoWMZ>E#CmDuHy@B^I}9Bj>wG9a+~dZ4%1PV$QTDRmFT>UpwmY~qJ8)!3CB(G}#_3aNlY zh;z1dk0p1sD6v6Rrfv&^&rW7QKRcjxLsRI~8C~r{Jyopbs^+83AJr%z;MWFze~gyk zIQ{@>-&HlE29{!B79v8?uFtF`)xYqPi4Qe$&V&z-xzo?W8k@J=`31Mk>Q$*zT|LZI zawRJ?eG{}xy5hrmYvwwZKwj7oRHP<=1yzROomp3uu)P8SFp71b(=bousa+ZCVE}bCFv+J5>0jafy1y$W zFOLbP@HG|~s<2+XSB1pn=iE|p@hGNuJ4bo~cJw=}<@RZmL#6r!%_ecX4sb+OeqQ+I zSN!$xX!9*o|3P62ATpaQZ|BQQ7gs$dxu?AB<}D2!(>b*waDo(JVy!LGWI%Ent_@Yn zC%u47K}%D_1aBmJNS)au6^!)#^;(KZ^o`z+6oBV_hL~diqPaVuh!`m+sk8j(ACAY* zavOI}!qAgCYSa~4fs?0qe0IMXf&8(>YPWz@45ikKDPlbPE%cUYW>-B8YZNZs*D8lQ z(thgby+?0T<-~^5Ny?Hfy=hpaaW+WMQzb3#W*|Z{I;c@PN-%=)sZQe%CT;WXYLzZodc zA){;Xx<)}>;gxw!a$-+$ZIz`n2}SKGvdWkfbaD?@{b1sr#WUsLjZLE1Rk5O+cb;WF6%=j+Rd=c`Dys^s4F50Fg8DfwTrr1AD%oIFC)k=^W9wL<)HC9+%=e3?CJzvyPAGcx$p4w)HODqzGGivG zx*uTCz~2`|A6`yAP#TftA4YQ*BCwXFPGq*Tv(uL*-3m_u!CuLX8AhCbKRZApJ7CG0 zprlzG<=EK%!`962sfPcNx(vc>UJ+b!X3%<1D@IvH!`sn*LNVOpkJP(l-RN2-FlGiT zHRCxFjhfnGsR4O=8pbu=Q;o1jhxm9Vnh&~3zP#B|IbgzUJyIgkZ}~pu#9C1XtBpP$ zB614X$?%6BWtoU2xKe=~wW*~vw_gUG{PMVa1BYIbKLH7!lgHMwB?$=|g zXn5wrR_n0FKgEm2o=@VSr-rdQt2ueNk#~$I9v27S{=W?0jUZpi=hA$vCjy=U^~3Z* zkKR&H1GfwB7N+;t%k+hO&?T#*aXEOORO8*|-=I|s5h!lfhxqV88$!6sibjx+V0U5= zZ>g!9LBtsT^D~`YkJFMu;kHH-A?qu0w0p^Eg7+-O-VIpaxfY_&coxU*Lu0!GGRgQX zVMJ`#?%QsRu7$Q8`C5EUga`({mH5#gme~50F)aX8wH2GpMQsP9OG5pGy>&fEviACm z%%EE62~SDaW#UDfe|A|<6MFjSg#iLW^Yo%Fht0fyl0k$!4JAy`_nheh({ZXS**oWd zcPE%r6Z#aK!Jl>!;r9TMY(1!$G*RZs9QvliYnbXgTJh{#5&w}f{*?Z zI`JIV$hAIi_I2<+Bg#hDIeT@3^ypUMQFS~Ai(=W!5*&nmM%i$irg4vL_@<+5fEB8s z7FTjMzi3L6Fhv&P=vE5Wrp!$nG1k{47EpU-coZjVz}d}$9pNblJVjWD3yL;XB6bqX zqIqD2gGV^ED~_1~EpRYDbrFK74jr?1L??r44#e`c;BT zpZ=J5-H+P9f1*@@V>9)u0UKC#&^#_Gumy6CVnSmon0Dzat}J2l=5FxXn-fN5V@T9$ zF{HyCDq0?qUWFD3&`!0HjV(QygNjd@S{QPNon0HdKz6KD5XH>WWauG|q8SU2Nu1hD z@|H1xhQZw$4VvdLG#r5xZ^MQBt5^d~iPgQP`;>O4B-wBZ#_E({^LeYE>M8+{Y#$_1 zD$t7N5Lx{zHP5U?l%~ddp%KS6ja+R^+wMa-S)8f5Fx$7^4xYXSXY!9+=$CKv5V-_S zJkPzETQR>0-f=6Q`O#dTElujxr{)D{O*FQhRYL#R$@-PhuMQ2lEXATZo$(AJb^)aD z(;cvB(p=fqYpS&LJxF-Vd*^jWnIuTM9Yi^ha;msXx;RS(H8x>&1Mu@n3S&6yX@98dj!ezQG{+xD$4* zu!z>0Q?Xj5e(HHRItax&huN-{5*??b@Sp+{c`lpD%Ax&rl~cZ9j6>XVQ`V_Lz{@CL zaT`FWq5)kT2VEW*A1NxtD8UAnZylh%W&KbyL{)a^HlOHMWDd%_YLROAc%;gKf8{i&u5*16?MBop?=$si`#JZVHmbUs(kw@#qRZf%(v zDdE*B`Xhb4c~B=$o5t-;sJYu-=TnT9j^tbHp|qGODH#;hocy~HJeVw8ZDfJ6&3TJq zDv+{O%TjEYdF&xrwB%5ZIZJ;kRt=_=>@k?107dZ9-BX04kRmWJ3G01Sp2sM%KYVs2 zGNj*c-8MuR=lLsDCOyMMFq>7+kU#(&;>XX;X9TSR+qRT(pYmfLJhuCZHISKk_c(^a z?hZO|&ys;!P6N9ao=omTC+O0%;01 z{k(coJ@c+dCQ_CUis?dSE^5x=zrhf2(7L%{vEGn@%mqIMRQL02@R->@vTA;qSzWu* zx(6K6Fz>hhTj8K|1+>wUWi~aDI-TtOQI#AiKQdPLA%QKd7JV{M6`@&bQ}&>S?Y`*l z)sBj0 z%*=z`{wfoqBsE*2m{IqzTjG&0A#dhp*YrO9p%3Ag^uI4K>IaAHm;XrC`^)UJE#kH< zEMg5#uXK@i1jt+TnpPr=%mEU1S&5$wUHsFq*kd8hA;w6@%@=N98p#k{oR zu0UKB9$HEez|!H|MVx^zvwo0?6N}Q3zf7bHV{g(c6_ONgXN>^ zH`U^WW1gzE3URFH#7su>ukEuu6%B}T8!1$s)a1Kj$240Sdo)E{S#7*U^MdJEaebc# zsnc^g(D{D_KLi3re*M{2*!9zXz&o_o%hU)8EAnBvTtV^=8I9I$SSVP*tL4;knA#WO zT`b+L$aBC;P?V`90l!lUKG>a(vJ^^v!w~weqz8XUVJ)cE@DV9W?r!6nB(~t5K_ZId zB>F(xSo8Z>c8vB{tRDCIORIeab=T-(7L;^ruztiC zWdU>vF7hdT9z_$eE6wDhNQMl*83lmY(phxw7!cxJ-C}#hH;zrk#3O}=FypmdhR51) zxL)AJh-on!$`Fo7k_@se^-I!@lB7QCX!3|mDG}fk0;~5fS4&DIWR+?|K)$1a9;C-0 zt5L^2To7!lW=l1R^qPsK{J%G<4Xb`1}TRhIYIpe^-@S^La=B#XS(< z2-xCu!h^>2eimhRma-1TQTP0Xq~)({TEfxF_*1#Rrxj>It`=LqvdUrgDv)`pIf$qh zQsO1w&8OZrOrM&5bx%v@&$bh*mewiS4H31TB~Vf1qHugZTWeQ>Y97%!_E6y#UN@*~ ztyS&tCx27VTH$bG_stn8C=RB^6Ib(M!D|;y5s4+OH>AcdQU?jSqWkxo{WJAp(6rN@ zVqA~xyAeNH=lL7KMufML3a`P17s9FCAxJ~YVzE_FlsJ`YLg+BA042#X2itN4u%H4{ zeBPW8C+a1{cquQHgQPh=U$|*p7HfLC5BRK0g8vLmUiMS)JBzSbRvSc?+DIeDX+RaH zj)EHumY_rvNofcCkJ2!9#^yUTSP9@54uBIS7ydvdLkIM*IwRT-YFoye;`lXoN`+jY zzOMtKq~;MQu?E`^#0lv{8uFUc%`(bq-gY|(tr_mmH}97UzGqyiuN(%C22=q?cD?wb z2;-Rygm3RH$JBm~iFz5#b#xK;>&%vRVhPdR;Fc`P$3CITePz7&ViXmFK^r0Ogfyyu zl}ZCN(&pM1h};pU3?I(EiNIYnPJ}W&YVLqmAXrw2MKQ1|prEw}pQ|vaN(*7= z&%5UuJ~|{Vu1~7&DqM{MGibN0jbc`^7B<>Dg-2U$8d@Ab%QR4ib?#p&pNnn3T*hC^ zfXqTJE7IcJM>fAg+E$k(;R5++$&wAf8z=7SSR=TOC+;{HVo6=NMB>+QpHjQy#tgd@ zVs`jl-%1oeV;e6BTRh`Qetwz!rYmU(b%obGr2|wdreL9O)NP#J@>cxc->1X0ho{1n z&0lq|HwVUBi9_U==2>Pf-sL~PD~G@MUR4`;fAw;$4x8B=BTSI7g*j&{))2EEFN;(( zcwyUdk{%mkW@w)gJ$!~PV_>BuRXMt&sTSVoP8zG%=}l&RDWh7dWxW)?E_Rsb4J6#n zpF8(|H`hV3F2|kgV4DH}fbzc!R=PMD{p$)(YkAonvLXHM z<_5AxO4)uzZgOu8XFef;oBO00qn|bn8zL7qh>UKG6~q=i^o{I(htfwRlaji+&OZWa zMm+Apu;Tofl8{R?N@2qKoJ4B}0e*l>d;K7Nx_zD8Mg6v|&}6^z7k^c}4*Tg`Qp)*Y zk^@2IHB(W9E2KLU&_)BZ&cqS{(TM@S4pE;g3?TEauA7_wEF3{#xbo zchw%rOp-fHAovdPafzV(vO`n4;`%{Ox+f_d9J07@`N-i@??i_rjBn!KA(k@RHWN+F z$s&0~^SkURLVb9eSDki73~+dXz^xka^N7S^xXnE>Qz7mJC?SD)V-*wKoe5*8pT&a& zA>RN!#H-Z-9fu|Kx94HZF6IR)E5hg{?)`&OD8lSuG+L@jGH@)?kg29dI@FIv(Yy?Y zb_`!d)34T^e?3t4(*^PCqIgkn3Fc};+?NVEWQf8%IUHbs9kaxHzu{z|UlW4=Ttmjn zI4GC3YEXXbwgSY}BCeqbHNCCnsc(W;#sRG(J&1QA$>n zq7{)wWU~Ha%M_)nR&dM&#0WX=-V10jz_PhS%ivnIe?1R4 zpovB{s~WY!(7s)`R6VA^1?@5%iRU1=6Wt1Hy-!Cm(X6&b;Y{y2dz73Ji81F;n71Wj z2A=-)>c1DPE={GVF702EPumZa^spG|W*a#A5E;;jz<%+~BN_8vF{nE*Z{SFv2^p6v zF>V}hv2ae*Ho8~Mz-5*}&xs>XNGoY>nJq=rPXccl*+R5xI+6_;D^dQ-BhTi{`sR8w zjCt4pGYacq?8wSx%5>uUH^`)w4TP;*Yn@CjT*Z@ZkmaesGnb@$9(z3TlhAGw4?`xi zrE~)#YPv<;=2;;x+6b6w=EG|&wT9U{nB+})`2?k$K2vzXO`M1@ANUA>Ss(})4p!%n zn+oOD78fhlXh=Sg*U{$)0RyI&iF08=LnWzzP?{o=Xq(n#5dnL}I#$Qp0r!5-f~CT2uXL9sYFfrx8BvI1f=cb6Od{6s zsWs%jKBX^E{TPJdBsy!CXcnD!gI2dF@LDhEQ>)4R%)b+TNxY-0>uj>+V(bR`>;=hv z4DM4lL~pPK4rPN6VnA323r5K*!H|;1?*w*!=4rdW=+a?WJ5>ipO55AysKM}2@=tbi z)^Yd>IJ1ZO?QX2&ioUu=mCz)*yW;{s+;27%!xg_7&%ZnD8*hKa3Xt|5gg%>Jj%sg0*-)#BS9%Nm%>!qPLDUYVe8?9J&}oJBD8D6@4E9I}A~x@y^A#BM zlDQS?Lz;t-K^D@)FKFF9?=p2=bs5T`5aYrXzebvbGaLXGlfK0(bo0ai-n+fUzYoAT z1h^Z*H3kXY$XG!08X!+LD#Q5U^ztKoZC)r>qzY<$Mu6RESBLk?E(|d5KF+ruZrx)g zR;mbRT|#gMFgh%WpYBdJ(tQ&D+?;*z{8x!94>{hm*COrA@&}OJNb0*2O{=sepF)t< zC?`*Zlz!dYCsV0TVJ;WT+EIa2cp!T=Yc7)0H!>!`~d=q0$whLB20 zR$h%H=#+b|Xs<52-Yh%)a&Zfe3JQ3zKWDhHv#+7ztN^(Yl?S>vT57xLxmizXQ&CQNn1PLFZKwN}!V#ZM*`|OBP-!a#7H)+-h%Pufsgkz1 zv^Tx$z8tEu$WfrthwJF;zIClDY>w4XdnkdHw3s)fqL6R|r`bDW!={dR25w`Ka&xHI z&CCpI#7tyQRAA{sW}!!mUsO7H#uQ`&c*WEZ$lUe-n9~dCvcp(!={;>+yo$Q)3MPqK z$r&R>_+KxrRiA4Oxd1)v9YPn%G;*I5bNz_|ZrFeu2e^HfdDE-Wqlz6*%c|f4OA&4^ zoeO<_&%ZZ1sXd2Tzn*E()Gl(r^rkR5U-0q|U4n+*`_My~&Nu1Dw?gb?^xXshrV2*b z3j>b0+3&~4qpbemwT;GKH#ysFuMwmzNLWhb%C2@r9RoOP;5gi zBU9FSZuYJ7Htk=z3C^{tnL>jA$8lqc7v?8GygLQ>lO_5GdW-8woDk&$Gpw z4trEoxNgl46kh>ty92M#-{p@7RB}V?_A@U)9M+Is4$k!f3?zr)yFPtyCSLuO7w)G} z%x`2%iS+tKPXO)VUHaYS!eiU~1OA`I96agyq7F0w!010j z2K9ei%$Yd;A0Y$l+Hq6trZ?BT^FU^!9G_ zsnIW#oR3*GE?RZtxo3oY-<{}gi6J9*df5@HV2aC})ZJCFf%<%`Z8)AYAPU(S0jtI(n zq3pvkiZ@y~BUPn=pUeIEScV-7c8oH^?lU-*l;S}e(}5Ud12rGtT%x2X?>5arP?tO_ z=pUDZ2s)tq5EkJEddmcroa@E_TO4P0cTK`vbmozyYz`1W906mDQ2&8j{=oSikU;r+ih$#t_Tod6HOC`@SjT*DzcKJd2SB?7TH&HUDZMmbZkarFbg$VFF65JS%77W zrnDSa{oglP%~b_%j$zUyW1Yn0P-eW*1goJt1zc3}ZyHX)iq0G^trtlyIO+4)G#H_I zTwv;C5m039?%T-R`!Y`>+~D4{6r5i6>_NfMyJ~&W^H~-cB5m}$`Y9)}F7{tDa|oGEmbSysDmg%lAQZp9pb&7*kFXDGa3mgv6Oh!{JW~Tcz#d% zL`)PEXB;KBOluqcmvG^}#YvtBYIOX+U2g%|VHH9fiI@;d%vB)-8J6Jh4OyM6!FBFD zgyWa{nK^7)s;e9vOkjn1|AZ`Tiie=s+l*p|-awXw`aYtGfIAd*fexm9^i6Fbf2Q(7w&hT*wkG=`GbE>iEwXX@?~z zR~yDEO(TJ|^~b*Zhy!o--30Tx1pSK6V21!1pA(Ry!}PlagT)TuhEj)Odsp97j$Q{0 z?)4;jpdz7HOc$U4dJSPb5y;7H0ke|xh}&YsBOTKpQB(1F%}G+*KWL^=pdd$dvAY1H z^Y$D~^8nW~eU>CsPy}ga79fuV2(!##h>J05;_x=w(+5QbAt&VP!uI72kW zk{nkFcE$f@VbjS%bc2)9Rhaj`D$2*&-<86!MlY0&7L zNifV0?#}Xw_a&l`qR7A~F)WM>o#+20B_jy43>O^XfoE0LEDPU4(v5&5{h3b_1pGqI4v8C<8)LoDfN(x;=O|=X_s~NUlIM&|EP&A%I^~b9Ubb?X53pn3_{6ts7cp((IWgxVeLMyS08V zZ-01^;l$E%G{y!sYM^c?0oy{nv?NvH*>)k*-0p8WWo5Q@^VKEq+{xBn9k04PQk|;E zK>pk3f^;#_fS5_yl<@H6JgOyZi$O9jiqIpByYhz7p@+6k6xtR@$szsYufXm@gF-v| zMER}I9XaS$Qwc~r-Y|oEWnD`Ow*xW<8*T%(nveeg)3Ca~^M13x?>uWJS-KndxIoSl zd@4KUp2={PM9N}JLiR3E0icEaoopSGjaS~CgC?r>l=qEhGC5%t@(K>K6Mdp%poN4e z07EdD1H*-COo)?f->Y8!NaGTXA#FMAjI%8c`xQ%6Mp>bPv%*^v$|p(gW?>5Z4MDrD zFMN4!Vg0wcp+>;Tfhadbig%Yu{H;^Sf}jeEIQ8(b)S)M(HrD#sUEjCWUVD9^s>i}4 z3P#(x0W@^BD`|OW8m;td^zrxaw*?OPRb)r)4|nr!zQfAD;7q;WKRW#?REdci8x@xUodDMlC1nBa!tTvp0}^RjgV-(62D_RiX@IA`vtT_-$5+; zYNP0OipJy6P+AM85cKhAcf37P&%^Zt86xXM;mR!(xqX;z^d{HLh$LRD)wvFQr0fW&Wkq{pn05MiJ!6% z%XCI_Uc*9C?eBdA4@_}R;<7>~&MJ*2pESJGzaFW!UTT4mPNYc%&h&x~&is)wR;6EW z)RYYv_w*nT8QicLGnxSoBU16%)EPq{*$$=F-CFTzs$C?mnvFC>dva3Xx}=xWmH^j+ zcM^BrXR&<|D8gx#C(r)zX0_(1GnX6(;M_2%RVHS|l(1701NHhpBj+)Pe(DJw4Nv}; zC-`QP*zxDHyxh>$&A^%XCE@6VSEoOp-{{&}-=NqfvA-niHW2{XXw3WNn!J4!Ee0D5>5xXuj zLt?>)YXlY0`MNN!xIr}Fg|l9K=NI1Ldd1S4tShHwdQ&4%L3_U|!vT03qA2c=DWPjt zU#9xf;9q(I;wsvDFe{xo@@gsg;F$?)s|bIp(lu6sl0U8DY07z+xeHjB?xm~3sd}QW z7Ewa8#yo#E1ZN?<7BdR$?8GIVm17!@bN%%2^BHw%;QLJOrMGVD5DBJx@~?P@f@eN= zdH~`;-M7I0z!cpA@+J4?r4^Lj_e6F%9FQ#0a`EJSF1;b0JOU_=YKYMnD+C=QGw;1NLgE44!Y^5S@llOe4I z`amXW)TGC~XdD@(1l+7L9Y10-gls1a$+(?d8!x7@vM36rjpWvX&+vS z+?><#aIh>yOz2R(gxD=7&C!l$)_&G4GkFCFt#tjD^~{gKPtJ1KI{m(_dH%1n>#UM$ zrOZ~fdHHI`0hX$`>JF)RCy&g4-93{p+M#$Io%ZS}Yt*0tKp!{xQ7K{)O{wV+D&08Q zQi3T=q^YpNz+?pPsBm-TW^lsEczM-mpMM!15q7|+lzcMj;Sd{8mB+h0l5sR`??2~6)eZOtd;%3V-o%2lZ%F8PeYQ0;30La@Y6vc_WtY;ypyHJ;67 zlNfG#G>@wQASIgCTFr`w7cTXp_%G01p*g|6ZBfn@VO|1XVsAZkCfSH7r2u+9V&+wV zvhZr>tgB$1^4B!g66Ksrc8%Np221_^-REpKMhh+=l}!@4?0uO008I%0s>I|mqog>h4sId>$2{z?GZ-ulRo};PX-M!t~AwAn>EQYSqRX2?IbM z1`HSh1LjK*%|kP1q`+ealXmd*xc%3lrnayu zW#pSj&XYUmG<(O)W9b>rb5(K!mT^h@h3j4wtK?O}_8TC@ExCyp(1HGZxAcBA(>rV! ztU7YFihYG3%Cx&Z7KI-CT{iJ%?5T8KHT~FO?a?=q`x+why!mlh^+k3o(o>Tpil2u= zTW4|EYDaeIT)f7Do+XYKhU9(eyoQTC_AM_r0-8G;0{Rk`3s*4dEJ$7zR9;f(J4h)qg9pV&o&+02WAtn=ZTWCAQZO9&*= z7Te0zw_GT;kR?j6{yF}E>&iGGT4_Cs1_b$YUGw4QYLph{`{tV97XINIkAdXIXDF*Z zwdxwsVIhLf&2@x;^Q@h6rl7NnY%m}ewewPuMj?L@2P4irHLdsiWplAHjoj?c&Es$4 zbtz@pAF)P1$A_1p=wTTm1#v^V2!f#R!d0)ZT4+vO6iIkJXrhIn-IvEJ-b;A>R33SV zZ+Qo76zd$g0xA&K!A|v{%S#9q-@+Z8$DXhR0AB_wB$u6g@3O~-)LCHuTX(x!-zY5) z+Np-OKlE=83dIjf&pqyTdU)TUiK5-`w{liI^{)z=o)mdr#GYSilzGM;+;Xm6PQCcA z#Jv~gy#P>Laem_yNfXHho~OQk{7?sXQ-Xcq;}##!SK(BfEb&=>?$6R6lH zK2xCp%<9o&3}R&d5&P4Gm#<-WDwiX?8;A#2;`bP1b&baGr{h{Q{9^Cx|4b}D$A;?c z#iDVEq!g%&mb4g-k(iByH#~-sgGtBwAEx}6PY3cr6aZ8)!C~X~fng4z|HIfh1nJU6 zS+s1s>MQG&ZQHhO*DKq$ZQHhuSGH{%{r9kEJvpO{jL6A}$b0wNYk2h)hTsww3%!XB z+RyinFiY#tg%4P-`~6~>(tN_j>lwZinkU?D{ruxw;~*K9u$5-wNhPr!l3EY-wkDXc zP&$`BbOoj*xWKY3bo(wx`z{bJwP4|=Y|*2J)|s>)uaB3CGCF+x&lh_{U38@Sfew=N z1!M_ouD3_|cJTV<=8hu_Y7$G|=}gJrawgis0jQhRkD#kjlY}zuecW6+_z*)&poFLr zw1A$v8^73_AO=}s3T(y4L^3BvZw+Qb`CF)>`|sRtW^&Ni*P#{o36MY+c*gIX*Cp5l z>$FC@^eNt8y#$5zevoav=7XNsL2WyC?z@NVo;_v)WGXY;b!WQ05hLmGcRc5)POzdA zZ%MTvXqP^M<_w-e zSRb-kcp)TX;^xT7ImN)JG2bV}(=px(zvI6_3Nb*r>0hRs9Td()x%8@b1ei(#r5NW` zy#*UDjlv7T?vlk>vBI+ImN*Xc&b$u=s}d$}?j}^Z2N4UttI=PI zl;2*0JB)&1;Ge+8fyJZbfx^Cl#n{;-as{MBjt}TK>getJbbc6hdV9YXyvy^iEVc_y z{b>ICy4uC!E;rOtFMm=62x=ZN)1i}y(RgGVw&<8hB^xN z@`aY?w${X02d%))W4iwkMWzAa;T72g{6>2K3>0&soGg^)g?G}u*;26EBH)IoRFL@Y zULpoV*I`Q-X7Bytfry8IasV)kd5?M$pv}v-e|YDIVIluXsEGs>C6urtO@2O-ay%LI z%&!18u}UM?XoTEsy=rBU%HqY?s9saNOw)>1QwWEnjgbBU%Ami!b>F^`>gxH6$d6Cx zFAi0|dxt%whSk7GU~!64Or%C*U{Om8q}@a}q;TJ&0RPZuZ9d-_IL=`I$<{8QYD<%s{<`v|Dq<#(L4_TJu^ z*gjHa|LAPcay|rXyLQTz?jv9X- zV&t*(1##K1bxjw?Ypd3+`TFCVtgs&>E8C+rldKllX&Hnzp@e;cYHFo{>dMI2!E8<5&)}JR?*{k=; z9%~NT!yRWYwSWSwKKrW0-F9@X%3uq z(~z&aqy@rfR6MLV)jtId%Z>fBZ9L~`b?W57rsJy|BhInjg?~@6- z;$3#lazz&p`Fxau%^934tF zRY5E;Nn+554V`g;sX=|_>GypO%KpWtqhm5FYTQsU;~c9@j*6O#(fU3Zq&Zjbf&2@9 zg5zf3l2m}KE-*>h1w(EnB>Zlm`puh8m5@WXHa%$=#DV114{{n-#M}z@y*ZVaDXY>2v;(C`47dHTSJ&TT^aq8}qYN=_UU3blWavV%vbTB*jIvBrOPbtr` z-~);f;_u0rzZSo!)lLG%^-W?+-MUI1XpFS1yv_a*guONjo9dWi(|zfNXn~h3lptB9 zsm-00%A3xXX6O~Rf(xfyin?wIUekw~X7=*Kl<4e(2Z?ji9LMH9HAAhT{F-(uyf-n< zn5zlE;;da(oHxO*y9xqKG%l4yo#;us-`p`|PG3Vy%Q!-G8i6Au8=ogxf&vwSDVHaK zt&~OGTl^5b*$rVlUlshZ|F{UO_>1d?;ZVTcE6H1CjfDCAC<^>7HZ?cUlwQncLhACWLc?W95TfwO9z*R zu0B%4;-cPtfLl2k4+L4vS&uIj32r2bjN+41sFgz+B^6bOV)9qd^ua5-Y5T7pAKdxz zpZcD;l{C#2&nq`f=}pp`WxGX=uma9OIau^i?9-o3_E`w9gYs1bi|nZvodVivaIw7t zn)u21vp;q=wK?1`3K}{QWRM{OPlz?T~88n3zGHJ@=8{>%J}?2*7EA$D7-j zX}gg0u1mjNr&Ie6{Caf1-v@<0jtvjjc~;zWdS9P;zn4SDi<7T@*;VaRWx^4Cb>8|O z1Cy2ZYUySu9PX3?za@&gUj00G9SC#jAObD=bOd=cdEY%QJzJm6JneojUtzzU)hgZz zBPALaA3=C1iq*^4hQ448iaF~|2Smli(r_+8%kV}z02V_D%gj+vlF~wwKSjAW=vHe@ zDLJ{MjaaKnp}0V>mz0j18U`1cb%i20qbJ(j)q3sOIPI(1)0|K3L;dl5rHFd{TijOL zq&7dYaRNLep`KO*NUb{E%DfrR?p^Mi1VzvWvDNPI1zI^XOOA`aE`r3 zCT-#MyLq=?rUZOykQCKp&@#<8j90pddyP#Aikq2h0@CpjGx6s$;gYi&$~nlWxty|I z&eYn2yNQXv#j515HH>3=%F_!6XhT<#DrU4aB>6H-`;Axhi;RDCMC*(18pwHBVt5hL z)0LZ%L+7M)MrO;l9C7^YmP7u{tHII4HwP+%E0g`#zmU>tlcJJqlsmI*I`~bP088rK+L$1C{y$&7GCQIh%Zc3xgbI_I)6! zQA2B1FwL6JF`sD1l&Y6qYz${jaN2BvYs-;Cmke{4Q35P2C|l||N#-MiFEhH95#{7u z_V3&9%(FbjW;pOHm!nYzaZrOB-zGvF-xj~uc`jr?qse}|`D4ZEyEY{fk7}THK-BU{ ztJm^sA`#Uq7%xc$Z-R}s)sXupM6WA3%fkS8sO{k`0!pXxIcjR&Qj4*&R^F$s#*Pc) zDn%=yxXVOUF1ul@>FJ=Jhi}s9=8Z=B% znW^6ngAWsLC22BiNrt;oF$UCSw&}OID#aaA0Klb_Q9s+794~E2^~#!$p{VnnB^CAJ zsMz{BI%#o?SND#KB-e>JhWR~#pyM}wqwV4IVFHlLVjGwYW3XG$U0J9#t`E;Gq`X*f zU~*4ae#LJywX-+!m((&V!Sm4*1g3JnN}y$dSagA`xlLt)@rhaTlw4@T+!dR60DUw{ z5W5?QgdBTo^@G5`_t=?pRZ}A#o!3hA)#2of<^Mt}z20Pq@eM?;4EEYeNN#Iut7l4i z-iPz?+>O&rbX_p|)1O|Hn*vC14~efS{&&g|v}Ss>wmv!WGqoD_*<$CVu~NTlX$ntN zj|N0-&UI@_*geseV{h6pWu`b9afg~gg_J9JMig@xgcxS8f7|!&@PwgG{H^X4HZ${q z5v%*zgLrsQEiZ8GW z4x2bm`#{BBPa-kUe=4rwxR25o$b5$`xOcb#s@ZR_yTGvSIKh?Tym$=*e3@$Dajgy4uE@tLfm!|~XpaJ|0HZK^S!AHsFYOO@C3q=C zrnlpGRaGR1D2fawuN?4`DAky34@sVZ@8H2s>RCYtlxtgm4;|1ufiPozQ>2#0u^QU7LQpsAz~n6uVHrb)Kr$mI zEE=jkZ0Wm?%TS+N6<*64Ly$J3oH4U?pjUR+kF<<$FcnK+DXbvk(pwJ}Of(~+qq^?> z*hMux@w_4g{8l~WsY0srNkVD$+JhaKYY8`vlPTXm7X9#`5cSf`CiKvHjF-=N55!ki zCMA68;`moEf6W`}&|uC=gq$QZ8huqfnc0^?y}vMHm0q?utl~cw0su-@%we= zOMj3OQ*E(mhhb=oObM+VjI|f~!Fofu^!5YIwW!B8f`odi{|a>8q4z$CwXzC3h+oUV z2DYpeXKl@e2N=$u(TtGRd@X*V1xjSIZ~y2-*UFR^z>WSpka3n&NC&)K^#7+1gq!_f=s# z55}_I+IG3O^%j1U&EEGOueZPX^?EnFdVUY}eYxH)=j;*UcJP14CeGKp^ml%*`G0GZ z#px$Zv4`oRx-u6&mpomwk6RGWDw*Z^yyK^0bSN$Jthz*{{w^ph!q!>ISsnAwIG3N~ z&lJD1ToBhJ$C`Oo=9Ho%JIq;b#AH&7vreATlu)z2%IIJ5m>Z1H1F#^@Y3i)%HyWTA}#u7G+o$ErUHMtkRGgCrDA<74C-x;#&iyRPR2|(dL zcx>C37FgRFZQgPJ7Rg6}3UwIQPFNYfH!PM~M-X|vNl;9dK*6Owwr4_uJaq@C3?VqOuvtPR0-J`xj;=P;~UKxHMl)CNd>)!i#WpVW# z`Y7ebR|g%3wl1&k`!M}uOfw=3b6ifdJ}<8Rb-hNA+1@v~l0i$Yj@9xA-KbbL=;8Y_9mpJZD=9C!1AEptHKgw#bpIi4DlnVYk{ z+)99B%l^RyMK2py`$0cWtt1GR@P5O7E+!w*dV14P)>$p|rI-WG>nz77=%0xZ#K?Rc zJ%6~-1b8NLR_c%FcQr?9JWOsw63{qfaO^iLD{S8sE{4mA5KuP_VWqmR;YX!4yRnK= zBH&CITIZ4fB&jQ=D6(e#bpwlDux>(daFvafI@r2Jl1rqKouwgGF?pCp80+)i{``&U zSSy^_?+G7LAVd^slYdFG(4KKvMOOtBB{-igx#30P=uPTOwIEN0|M=q;SOw2>C{*;X^Kn2 zKAdwcm+<|`=^sy}eLe<%v=Eck9YmWzq;;-8)Na5H?h`lc#wN#mavr6vjmzAr)K5%d zM&cnT*O&pOyc|5{_+wt)fN*+96enQgvB?durq(76CF@gJ4afGE?cxA&!(F=wf(q@W z+{y)ONyykq2jXVQ$z({brCC`&aX?!?6gcP%wP^v(W2gX!UQJ+^Ln>|0?tSJZ;A39h z-T|+5J`NX4`16wh6-p6$n3!v)rO;KZgGB{Bet8VU#8!rICc;0PyvOTydk&RIQy(hv zH@wM}135M(WG}tYk}XO=??>6+h8Ap`g{iRzi8N_S!V3ah)1KvYmF1t1zsw@bYFsdx zL75WR!%~fQR@5={+5}qu6&~B@^5f&k0oI3JYJEw=n%0ySaCWcX(iAQ$6vIiCR!nbadLin2gkS`Gr z;^uw6bd&gKgw1mC+@GLe{V}=j7 zaqa$YWw>~?1M^=D7rk&IJI-A%xgu+3V}I#?HM@~$E|l*vtf>Q;-nyrCWe+~a8v9uk z(GR9kB`S5BSn73k{rswFp#~FNI(X^gy=3W>83)R!w1%&HQ|`%0czu&~Dp*GJe-<0U za}rfFlSd1fvEv#N*H?hI@>qTOQ?{0k{5n-)tSaS2-y%Vz&`%w+N0*KEHvtYOtpLb^~aLzGxO;dBD4fc1ysY0c8nrbn*2XDau_>cRnxE3=gt z8%b0~0EV)0-sLuLmA@*Dzioyt4uY>qk>zKjiHMx_O?EwzsO>e{r3Si7p%-5d5QOTQ zr@lt3@dO*Ycov{T+h!c3*J`a47D zt3v!#lJ8gAPk%ECy)KOrdEu~oS3QD?9UAXsV3r4c`UJ<9{w@gagR$KEv?|X!%U>*D zs?x1?S>WiSwX_)l+?t$%vRDJ$^O|RgUrYyx_^W{$l^uFWK3+RBa$Pr*Ha=qR9DT-@ zJFQ1Ly?J7m|CsMAN7Etv8c}m(8=@je7uFiC2I;i^&wZai(3=O1 ze0IoHy5Lb)&krn*I_4%3V^p$;;ymK5vZC3s=xLo96yT`^E!=ewCnE>jnws@6J56(T z#J6nVn`UPTfsBFb8JLlPtvxXoaIB>mn)#|_s~uZX`9#nBBiu11aD}ikKA&+FHu@m@0|NJqn6L#$C+JEA8c_c}(?oip$iu;J!I(2p4brQwGqR0uEmsQiG#pShC} zO4pZL%qQ`bd1J{`vNk@q^9=;m;SZo=pjX45k<+H^N%Rfoo8v~%$jOJK9jNZIO zuXVW*^LWeT#^wDD+~Pl;?VfM5nN=z`Phj>7TiHV#zrf=g@>NJXXq~PqWHrZv#4-mr zhQaMGuEBRqh5{%rGMHY%;7YlDQSN4rtKX>pI$G57WxcL^9mx3GKZCf=d5SEM_D zi-U)JtQH^0bZ~b!K;7n@(ZIxxuUc9ao83#|I0oV(JXh45>tkm|&lVDBi zu`V3gcu2kYk{dh^jm8wH)Ip(c$7~=1$6D|1!V(~{KG?=ACy47jCR=e-U>e{Vk2Gg5 z%tTL-0uA?Ob=%*1aP_c{48yU{9~vbK!_=>tO%5c7z%tF-U+%?sP}!9Z94hr}5MX>& zU>V4}{xB0mMorOW8xxumz$FRME(2`5_QW+>$Ab*t&%dLX7_mV+zCJSO-M2P1IGpdH z+1ZbTKf<}5c~A{FAJYNk*1_p07#ZZ#@Yr}dQ-+cy+HO?aqwT_h>XpK}L4i&J>9Dwj}R|&&v8aLeIEuq$0mLGM8oB9kCI(gM8fa~k-=}83aTE1ySA+vT8aa^VKmAT%H@0%-xkMIHpfJ>%uSPqj4CpM z1E+k#>(EX_gT;BbaOCNHm-1akY_ef|tS+{RvzFqNY&dxt&Ew-me1y`_#NfFYf&%ln z3C1ekVbf)QZLzpoA1U!UqDF1bJMb5t6RmVwUpXyCs;7msDu90H-(oGAfn;J}?G{wc*O(dqK%r$yf=E>L-my21ft-L@ld*QLM#^I%+msCNeAm92mzbn$9Ywo0$qsa?>SXZzZot;^ypG{xO`$k*8FE6 z)aC*}sZI-Wqq2i|REqSnJ7cxtTrP*UhK=Qj;r~!c`o8LoRzyzri@{$Hs-+$3U5;8l z*U-f9-r`@S{~Q00N>?y+XF_)j!`pJtFTD^|v0fhiAT3`B%eR_EUf$9;23gLAKubjk zVZT@&?XG9VUAtg5*vthqbAoPWYI|V>u(q0mv~t9u+&kE(~ZHMrl@%z)YNZ)tlaZ*ha&_Q~>WzF>K|soIX!h68MLXH|55xakHWzB6SeXIUbuxTJ*{Of7AeW6H`tLV4Cv2&HC3M2K>T8f!a^xW>cTs;8Tyu8h&U9hW#aPm)!o4Dw&I zLS1L(Uoi*mIBeX1^UOs~P@B`85tr+IOj_O-JJ_}q$S!|m-hYz4opXAyTn z-r6{^e|t9`c#SsGtL>*vzkjaS0u~3|effK&_P#c#(ogy!HroBO^zrWE_7t2jh958Z z9=9U)##itu8=?7qSNg~sM<#Zw$8q9P&8_uw%$X@OLK^>G{)^mQAzs?u*b?izZ$me? z`f3qvba!H;(aUe$$`;j8$6S8{z*>AQi?aQU665%}B*gSFN*}V5D}P?1+N0OZh1z{1 z7g^I)A5Pn;^mnZ4AiW;xtz6jLsS&Vui?-b8>@8!meP_71W&ih3x<^z0rtft3rXJSi z36R~OY3B^3ik>mKd(?uvQ()U2urY=^DqWzB9F50wMn5a&rnxzATSt9p4rn_xzj)bM z)AM!4UJYHdp*dJv?|f(uvW{^BYWWAv6rnY&aM`e(mAkN+Jh;J3-6L6V50Z$LPWlIl zqjf`j=}-SUF2Sn0N*e%HkgV%)X|m88Dt)ZjSgJ};0f}zrHs>VBRYw6y-}2Je)>Y(| z%L8W?e(?jBp(fQxD{lec-b+ow)YW|v_%FSo99X%HdIu+2{>hd9Bu))yO+sywxJ{igiN4$EF`SDdC)?38G_Ypcu8?a>0r=EXBjyvVP=*n7)A#xNoFH>NsT42 zEgjVSMzcQ~23R>KZ~n<4NHd=~!pvWq&_hc;Djw^o{kbI{Uzb^Tv+NEoxJDzWwgQ$@ z=lPIp-q?oCv&JqhQo5~SJjhgIWK$!JszXEzTh-oo~4=-_FM9bgf_#7b7WJmOfvNm~g1 z*HTJm=H1Ei;?@YbyrKSwjjVX|s|;G%uL@RRCgk2iO5z!O@&yeRO5>&d@!>;#E7~b% zBG2%E`}yHjeb5o5)t4Z)WU1CXbuOSn>(rVUJBl9gD9W59Xj4Hnz2solkc1mK${n*X zr`QRkKz!(jP;?QOp!l4D)xxGP7E_VE&))Yg@98o(uivyU+3Jet_Sb=*p#F1i;Q8Ij z7nQ3I4x; z`{aUl&~pBvrw<+65f7Ow36~hZYiy`6PhDXeY;=3~lsTOO%{F%T6g`-t(zbdB2bFUS zl~u;%LCZmlT2y`yHDZGkqW9DTwz?#@`u^eToZL%2G>9K$ z4f5EEK{at~!>&V&F)Ycxk+`Gd`5Zc0s@CKH7 zV+kMFWuJo!bekr;SO63Z#2_ld7e{}hy6K2l*%yTH^?Oj)#s9E`Ys?LJhup37YckjM zIL6c*gLXn-j!kAMg67@_d3-Vz0fk*>_B)c)dq~5iT7dysKMJ-&%Ff;B)Skaqx{yhx zh7iCP3geqB7<%0xg$6vnX6tDlw8v!W0A{U&*@ZrnITJ27^t2eOw3?NypIa^xi|`d| zw1@fsYc#aSI5yY$FBm>C(u%~SU_DgF(t$WFmR(J!J=@vO1dquaFp^g(SF7Es?Vga> zuCdlT54Q8H3T7VhO7-9y&5hTN^u65k+S;nmU0vaYh3}lY#mEo!xS-@b_L9GMa{%fK zOZ2m?IxrpdQ{~m(xKA}m?HA)FOHME3OYl0ZJ8@7WF?b_IE^?)tB-ke+_8L$jAhI)^ z?JOupJ4l32gky1Ad8Yi<)xft zQxUfQ*1V>kAg9pzNlW4kW+h^+1%`r>Li{0?@!c-r8%%vp0>yjf-)g?=uHJsnaig4C zxMIlbcKe96zdYAPYS=DLz%@fpjF+FWOMB1&REH82GpBRPmdjACmEyPDMbeho`ME5Z z`nFKWQq+IPAekm1?Gp0DXWW`5NKp*R*>Xdd5_%8taa@g>KkdC)piU+kqa1$KoV}9p|?J9TX3z6PBeiLLu zJ!@e1&pnZ0=HgG5Z=8jsZ*pr3;Om?+p5_jQx~@QvA@LRRd(q57e~R0t9<^1LsDTUY z?ZlxzW{CIGBqULO#26Y~J*IB-6z5!@pa~$*BHY_1W)uG-T+uSz=@TuH89{6Ym0cgB zi4W`Sh%<9wDAC~B&d!APOX4wIU9-b3x=q5#uS4HwhycXHNwJ=O4o@F@U`B62L~#tR zV)H9wL{r;vgdArftl@#ZfcNuD0e9Dr91Ace0`VLHJ?Mm7P{J5r=1A_*)ahUp)*ZLB zAAS!}O+bW=l*38q|o*Xl$%K+It zBck|%?pvI}aKnLooHee@-*9-TTepFo2duylyLT7RxBY>K2YDnEikQDso~uR?!X{$% zR|@Sb#}RxfY2#5I29`&#-42%I>R!Jhk;oz#e5H5TEOhL0ZLjCss6(qsCRh#%cBv2@ z0$vkWUgK>q$xn+`sJ>hC9$Y8^rUOJ z^T%EX1?df2qJ@rRmU?T{Gx*;J}7Dg$!cOE+|00qSk*#Wkq@hSI#&Nh=aT3)hxj` z=fJZ9S)+h#H7M*T?|o&WY4f@Jl8p`n_@kJ^-2JPLgu4`X^TE*M1YVnGnOnp zfC=##2_xuA0Y?J6EqEgB{&A;h*|hC~k7Vg3;csmN?Xl_Z+v8(14Aw5%!YCsoGVRQ{ zmM*z6$sBZ62D`OVjh_@(U}%ZJkb0vcsuthYhq~?6fzdgW#2%}hRXFXSg>VeRbWS$eq z8Yr)Aj9Za`DEjMyth^{*+V5I5``Otaf00TaFY&xZCdbHYXu&GIJD||2zm@A;D-jw= z#Yl%H?fT%;$$fchvrI~KVftsnHdRKTAammVPH&Z2mru}hcA*oYz=@A7gyy;O%TX-j z9t-CSRwTr2Sb58;rM9Eviv5tPp-S!4U3G0Lmr{;bJ;Sxgr{xw2nKaD37cV#hGEmki z-LvGWB>nzfRrwx4u(E13u!Jk|MCu^B?t(%L9EKhPL#;I8xI1HCY}PubsJZuhb!h6o z7NfYj^<{tkn9iQt_T|1-C6Dt5NvofZm`7y+s}?J_#BDymykQ6#k`$pMDx-v_+L#;g zGVAuv?=p*n<$HTIG%%RFdg8!$b^UPKNExPwVtkd@bL1Hu^aj;T7OjL3n zG>*fG6f{;lj>AD`5YV<#Bo>J)9Gi*7^~vCziN$v{bXO3u?@kbU$P_e?KtT{@)e;+S zlv?q2%--VJ4#=}V)Mqop`drz-MO>}ztJ0>MF$esb7#~s6HBuW_;TCyTf6yCR1s?hH z#D9M-SPdvsU4uJ$B#f;)zTZk->i^&U7!R`dHjN1cq~#9u|K&0M!|^Qt+l<$|pW2(F zseO;?GF_j`52I{r2EtbhG{6guL;{SqcI-2!Fxn94+7Bs5SeYMwyG|!18UN0JW$nEB zX!QXsMUPl9v)P<=$StN<2^VFH&@nB{`k^#P`BdVuZ((K3ONDL9m?h6Qw6ZQ{2!GU4Bd-zw@ zX0iM&*CE%rO^chqh2ei9y zAElyi)`!pA;dbBy1aB1p{^z@$;F%RcjzHZmrzTXN#r`r9yFaH)qFH z6xn`#&gQ-kdtXW4wMlV+V1~rCkhxQ_hF2?$&Im9ZplE)wX4zhHZGUj(6q+J`8~Aap zp3fOROZy6-89K;)TZmRkuKH-Czx54l5R+lyMZBKpGPTQ$VtU=#WDJuC@AL;0!lL!& z+4)B!1%0K)#PlLvak7)@v&TyWviHYc18c7iN(rW2@?6~4a-ekFPk%A#+wL2Mz1+^o zuCEV{*{-kuNpEyTrExdA#px~VoVu@<^jy<=%64rg>&HDShw`q-bKW%iPX4tILjW`A zyxzg+*%`Rhb=@AiniJr zy-PP@>fMEwc7Ls;Gujr`z8P(g=-7t6i+^Cp+{+uhYu24hl7lA(sfWhWsofp0w#{Zw z=-D;|2w&VjfhS!t9p12&%AW!x3&gQg1nBPMgK;dfk@bu1-Vg@h69_^=KfOV5N#u`- z&kKU^@&zKGoZTbOzb+lhoJUz&TtAB>`I*o6a;*ylNUU92Fd|!PDxyK%%pO(JRGu#OzPP1g+ zS|T2Ggwshq_u>Zg_cMUCu67X!+1CsjF1-_mldbVa`M@^W+8r-y+<`wMls~as=T^3K zIqC_#Onw1@ecC`QZWqrhbp-?r=>dcAuIXTHpnI8#0h0H`-V((Alp55%&t(xsE&~8Q z*Ri($QXM4pj^CQm)gx1eIu3;6q9ID+yz}{#XadUBZrZmoU8vvJ|E2)+@BeaWc|Xnw ziCB@s3=Xze_fYT$4H(?U0>vQy<;W1nmXK(Qj>!cDWlm=}G-FJ?tsp;w9&lS0uf82w zqK;;;aVYNSIaMCCnIRdhW=3zDcuV8TS0}5?{}rjhm>y%!V?kZWP6W{35xcGQhb-&V zqen#9gP$CVT;GM%vy?HvlG{aZhj?8NRgGi`b_*0ha_0`W?MtElFg2`{?NXIjUgc-r z1LxCnRYIQ`i!Pxlb%A+%dAoXhIBaln{oEhjaYW_t&`c)O`F7UlE4{zw@dA(>RQLLf za4;d&cTFwPXn_LWw>N`|il%7nIuWc|0*E_?2f_kh-EeBV&*o!z=cBju@;+KRnGQXq z2Xqip$r3a%)=LWLU<($Wd#8;WXfdH*VyOvRS<3-}46kwJ4oxxs2&&ug=?A|hlZ^{% zF@0+Rzg`=Y?{jg>S8sP0M_<*Y)nBZLb>KvqT8Ek}2-&PJhz|Aoj9 z1+-MA@OO#mVn#0QsFkhTu{$PZ7{U?1bmvPd8aZ{=B&u<}9+3T~6HagPnXpL1RCOk?L)WLchNBeD4A=;tY|5h=;BZVbg$w*t{cMt^;X+ca<_i{1ve(b_ zR@-kTIpmGi5f!P>x!5x;1V&*fM9DAOFCSsu75^Ne%cB%@bzPnO&ye>TAq0-QGgv>{ zZGtZ5cIKNi^F2AMUWsyQf}p_noRB$FaXUlK=ol~tSr=ezH=n?Mf<$h=7tC@7H}WG3 zwAq?|1OY|X=2paEpl;MPIspm{wqshWmn}1Bsw667O9vQgg}MX28sW!(rT(;AQ<61W zAx}gY#%r)Pa5=w2FvlIOIec6+YNI6i6Sj+&ol%?WyzbPXr;G1rKdDOnKq$u(y7%(+ z!k)|nmOoo3r`tWGb1-x`L_jBB>sv`liYKSwx}+H8M3a_US|!m1$GH1hag? zIwtdswSt#-ui)L@G;3ml>aq_TAXV9GS#21?^%F>KTruExe}hSMHn%wRZ{Ym=XWt)` zs&xwMq0FKKZXBgC3*;%S@+BgDOBivG-AJ}ju_PL*(2N!bh&zvq)jiq)dtlbNCz`-O zjVPpqtbT*|%@WCSrhAXPgKRgx6~$Kd#@Z{=SNe+9Aau5ekTSB}A->Q+dY!xwZ0qAr z9)-3C4j%3*Kr;GWWE7h;K`(p^&DQn?0ZT1U9xz@JjNDZd?7r$d$Bs(^v!Kpe8$IBU zG37(pt@*}stX&*TQ9Psyo7AAArDMzJL>IPjq*VF|9EPl0zgS|F=N#@OvmdEEWl+1o^1(;7)jFnk{l)tmgxnvO)vREh~!8DmrvqR zty8e^6w?3{-l|6Y4{MdKSluTpDC|1j-{;zaJnfx^QYT*x8XM+(M2j4LcG%T0Vz}~5 zs_b0(PaYJQJds$^jz>(^>3hmKYH|RE)Ahyk#0WVTd12k$hqIyy{|;R4_^cUEE@mSq zk9U$`kWZXRkmJsHShmoU!Z5s00=C^++OgWbj}XH-hDr#(S&HHPf;?gB(`k=txLnJ| ztEh56;j|=@dtBDjTdhN5SRJzyueYvC1aOGHo48B&)kyhR8-9pDF+T{e<8svIUUN*U~=9B*>Su^}dWG!b*dnaqu1U?JI(h4~3|$WYoHx>l)S zB7*&0ZQOEn{ME#)M zR^E*4M)D$b=OXAU0U;=CDxKE_!q`sJTw^eHya4OzQCM5XzU;MaPm(4QOq(`m6af&b zvEw&BShrtuci)x5BhrL`PV`4wB=+O|kpKc+fvuZy*)8hv-9{k9H({)4K*Vn23T5jq z;=oRIr{m_ zVU#m^tuktNGK~n5*k1l9k%U^!!%2aoh2Q}u+;^KVh(ky;kGJZc%ZOf$-e43ifsV?4 z+MJzNa=&8w+8Czhq#f$d`cKf;WP16N(}JUtEC=far0GaF?2QBmtdt4AWel}R3Tchv-Yl;&XqFY%CtP)9fD?!s?fV?HZG3lXkdZwnB#f~En$aszq_he!M+M5e znxB!a_BbNxW0$iDQbUBGQtZ0{vf|ISsG>{R2&J|cg9H5q{B*eQ4Va{ z*4bH>8B&5Yu+vuE>!;BSotfdYV0uMMFJjGM43bQaT?h(>KXXIy@A7TT zA>}p-uWHP3xRlb}Z-NYin}WfBc>ilLvQvNJ{T7yrRP87e1WHrqv? zwMG@Et>kIk!gPr~nZTzxdzW=%i1u$#No94NiIOWNFkyFJ!8F2j^uciB~HrW=t^i^|mr)rGdq9HwobfvG z;9bXOZvQR2mLp)Fd_Qs0wNG}?sk%3Nfkrqn7^7vq>JL)+uLHJ9HT*|nE{C(7?ybVh z6I$ZQO|8lT8S+HvV3E@pXK@jFd z9di5LV+6CRcqaEC(T&C)Wf{GV__H9lAHPjC@OtQIAztPd*>Gz2M085lZP*rh@8{J% zC-|%HSr*&{Nv`g0Z$9_mtI}DB0!=Xki%uwas7B>6-oa|=Dis_KO>IQ^`vD{E<2cnG z)E|_6>=aX|4fJ}7B+L5{bS-Hnijya+S?nMCVKeq3bGSZq=1tEH+h^76_7*f*AyAxS z9IV7N`a|(yn@|16Wsy2sjXEI%(#Im5JcG5~d4n`C@Cyc_E&hKNTJVb5;YVQ#n&olC zjEgLeLzdh*t`+ZDyl7_dWvXx_yrht1>A9zP(0Dy&`%DdZL+#?SCpNawIB%=Xkb&(S z%7QE+uB44`u83Tz9B3WRi1<#ysFTYLmJ?0Ep8OyCkr=ONlIo8TrLkC(oI)m( zD?}!jT*ZU@L>y9mg$n|CGUn>q@)C}q7m_D|yc$}QPDF_lxa1GugMO#zQ$R7gA$3!i zlIopbEG0{jO3;=TCTv`%;)C@yTm;~LL|df^qJgHIj}b)XBGvF>bJ3uVMdq2lCFeDWeFnGxvU4;$8k{az7r`4fw#NyldUb&QL;K25{E8Eu*pK zrF}}X-zUc*t>JBa1zySD{s)H0%*aw>m$rh{-kvh^&RxdX{|{s56r@?uCEBvpWxLC^ zZFbqVZChQoZQHi-m2KOu>Hpq&nR%Ls6B&Ew!@)~N#@Rd9623q3o6Dt#w#G0x+=??5 zKtPX5f4RS%-T(wO?rjZDWN#JcURa71&)-M^Uw1vaoXtD2=`&}I#=rfoo1jLQJ%)rZ zTK)V-t1m!HrMC&KKpJS~!`8(Oec;S$8wj5ebZ#87u2=j?^8h_F;7dfsjY}IPJht@H zdfb2*xe(3aVh~1>f>2dWN@2fc;vs>6PFHfs0-;bGpG-oSJJ8%1Iji|hBnbYL|SC=#}F5zLymG+H41W5m$geBuQSTio3_?Z18q){Jt@06sZN?Y-1 zT%3#sLsPApKQ*!Z6r#8^mLw3fW}`0&Z@Vmf&ej&=d?A*YjB~Vm`(W~3P`|8w4!JO) z98%RgmGHW&6IHxv0_3hkO$@MWQ>K9hKN`)!mDf9J>I`RZoX%|!MJP%$D^g|aEKpC zCXC!EVRb6T-QeR>{4K0ls)xWN9ox5PjiToCI9V=D4`BvfN1bms-={suw{lQ7l`_GP zIevbYeA}1B0lPdSqRNr)Xr_=7!*@1tIbpRI(Ga#6&8J4PIB+1vO0dJqAH$WSy(&3+Y0-8gT0Zij@=p~Md>@4WLs z0#I7;b?i0I)aEf1l;q1hbHA7S8IRjh(swx6(=u=zn{?IF4%#gg<_HC5U`1N_GDlN}bM_@RsIYWLyB=6MfZWy}K@~mRh7)?4eExQH$caK7iejd)Bz;ygVuYU3z7X;BZQ+I8z=3kiG8QE0>d#wLEfV(`MSNFL)XOEb}>)+ugmL~ z9o30uhi+${_E+sEpACN{Zx7$jT~1yWT_ zBaSLEco;qF)NXWg+>;#k4uD{*s~9u9(ognJ{A*88;kjw2#=Z=p6b>Zv3PK?@R~x} z!bI!LkTOb0)1^rGfM(fcLb(K|pQp9?FPZ{Lb>^%<-LG!xts{VfCo4f5WY}qivmU#r zFMdQc_)U{b4!uUqEbNjtfOJ0%5=E=BZCY-fBdPNvY}B2RTC#|eR~wdA(cS)I?H&_D ztz5~f1)ue%q5tI2Ks*Op0}P3R8f<3yX>|r_I~TF+gv~bf5H^BZjATns)KIw zs|T2~4IXVMi4t+9B|ae~b!eP-;2lxzr;%$cvniv^AxiVNVSf_O%9<2HCC8(~!M#c)hJ=$UPu4|jXeSb{nJDM+1eSK=-JpAyI7kz(f@x0v%c;xKrHSz0J$L?S}zLZ1#MWzBQxdD*bx7G7yO$v*04*DpgBo7H14&sRCDe z_EO7r!{H;;jMH`4v0@W7y4qJ@8)6TQ8424aHl!_3)_tk!teD8!7GMEOAtWz)6P3@bkBT^ zc`de2?YFWv<2s3(<~rGwnLB678N_KIAT%I_df`8 zEZP8OzD&BgJ3sg`ME<+X+~u0O`nsQ@w>!Jk4J&v-Z3)=>fCBmpI)ym}MjTfH-v+oOb>c(^?&Lb+8Sr2)gwisak36V?RmQd{cpyVXXqo^s+x zgZ*qfAn?56Ffb%#= z91D{sPR!66y9Nw50`I_}cjNW48YU^mfcVHKtoYh}bIEb3H zCOBeSEo}n0Q4m-&Ai^;QesmvBKI~|!=)E>O>~oyo^Fi5qk#rLWqx=R5gE~M=|76NS zq0f(f@e2i#2i-GHFKaB2{YAIR!4G<;=wd z;eKzuKdlWMnCp+Qh%UxL1N*T;`6HDQnJGxO$*?)fTUt+Wo@hHaD%VmK;NQys4xIu) zqKYAD$3(NbStphOPx}2n^Y{?qYFKoVwdnS$4_H5W9Vu;JY*CZYm&)65Uj?U?@*w0agDBz^y7a(5nA^&MQ#fHUS3ZxEk#pd_ zRUXrS62&Df+P9`%IEXz}`t5o180w=W2amz)9~}yM{iixV`A(x2s#nD)=nnD^QJ!6S zeSvV3PN{rQ(9(dZL2tgbO#djk-pT*?y=+oebqYz8t8r zDXi%z>o~4WgT8fZfGX1s0uNbHdlZX{z>HtTad=A zq%(~{f`;QO0e^^ycRzAkNDzyx9}arS6EGjh>1Luc8xXkgxYJZg6R9N4G9w7v-kLs9 zNVl9BaD+;!&ac#x`Tc+zP*=G6#lF1r3cVc0Ei~j8T82ON+6k8{kbkC#X6in~8Yi(S zp!Jr8@@3MbegdeVKiKDd7BvJi!b%Z*kfR|QNe$pc$FQC?7rUaEF&*2g)R&0S9=3IH>T#`uw;0F7e>zw!SU))qQoNNu2$!g=8lF%K9qXP!P{K%oGSk=?n zjIhEG;6x$)Pu14>4wy44P0%0<&fFSgW94x5I6zoSuPjI%Y&CkEfh%{_ z{+XF?{!q%%c)6>UxbW7d=8JUXgdFUPPln0@d3<1>+zNh`(abRReom&J-T7Sz<2YAF zx7xL8k6Ma8^Tz0<<)N73R1e*VOsC*if&CtXVP|L0YthPUNqHv|Bek}ZK3Faq2?2SI z%FuGFc(LYR3h?i#x7B!H3O=c1W`EwjKAsH$L1i^@kA`F5j+l#R*%&Yp+Z)ucO6u^< zHBE$L#E)E-KaeXeIr`G*`fcT}EMxwAsBfr9wgCPhbWV=}JYpy6K3VEWAN^Alp#v@Q(7FH9s=FjO z;>)^WKQV##`$_4J{^y#%WH;^&G&t*CPDp_Q^?9By2~6~%#$uqaZC-un*0tlVs>egg zFgs#zJ|Z7YoUZ|-unW}}|3$3*c%@?MTZDThf?df;FGC!q6B?zz*jlrlY&;%WNgs{~95jCHE zR*ptMn555GbVlgPC3+M`8=hMMmR|usB!uTXA&!{T;_0B`^jU=FuFuo}ZCinWbWCqA zAd;4V+WTIvysbebfn_oArKj?;3yIwtebby4CRAY7-&OoLDIq>lC&vlHx{k{Z+L`7d zSAEwWiNe;TcsNBkyXmshI}w!c0N5u?nnMgj9AEBb-uR-_Nt3+^9(?{(=GlFK*I!{3 zQz*;0f%j541bG-=@^ZnrmiJmTa^Ij#NKDLM7>neS$9Pb`;i4vkXa&=`+O%o5?he0U zBOTPi%$0VGihbNru}FiCR6u)Yi{DYt<|eD}1~uS3T_EY*ZFNw}i^ezZ#v`t!N~<@` zz|So2l3?CZGUk9MD1fCqymMzdA4@Dx^ou_!NY4*hlnwx2V3>_{yfe~j zciYC7&oGe?M0pJ=@hX?j{05uDg1ZLPBIYc26uC1pzR4D85>1l;iES;eUYV-JF#VTv zAhFcI=<-C_nynVc*41&^rQQzNT+(X`9N2vX1T?q{5_+L>; zh6B*BT$ttsdjJVx6Zg?pC7Rh_{j(wPeii?q{SpqacmA6+k&+20y+uDVay&-Np7#R)!c)F z>P#{*UHu3PW|Ilr4YJXi1qn%&K6T2?hU4VE|15$@3JMIS4-oH?G;amgx~w;2mf_*bapm> zi)*gWiY*`WnX8z!&bzR|*57SR$SUQUl2*=FfXc9f*HFlc}oJ zWy$R>Boiy9j>+D3#YfZ|DiCb_w_w;A@IHZpG~DI_zYL^ij}FG%j2*eJ+AF8te1s` zpTmsv0PdU(TsKP^)>;+qCn%jEf277h$mcQ?-b)0n1V#C!N#aFhVc?_jqQm+6^l`hg zm5piCnDb^AULo9f2n+tcZjde+n!b=N2@6?q`DmY4?tTt4 z@{+%Ip0bI5*?3_0daUKOye^#j>??RBpaD&jPZuo_O7!+u-vyBy&#@Ru(GTey0*3%G z=>XjgvJbmxq3)2LWq0yAF?PGxI8eYqSZMW-XK{+#z)eW_s$Mk0bmfb0>w96=#$~N4 zSfJjHRmTj6KnuV8#(BH0`G(tZtj5@Xgm%opw4?d&Kr^fo6~gLr-+0u@mhM!j|}c z2+bGXp~$ZnL`gCu9Iz{0tM{b+MHLS0hgK?v!rx#03avUcE8M+pc-^Z9Y|MQxFY}G{ zS^dp@bF%LT2Ns&0g4)LLrqYGfH0nTXF~KMDjq`$nOdZD}>TVleFVUdVtfFxr5XXi9 zwRyI)U-v#5w))3R5p|HzfG>g^w@0{6hZSy%s5(c6r5(0j z$V33;@)mO4uL#0O4TbLR@<~{K6ua={EnaM#f=>cUByD0D7hf z$rSMfSq#Qe5 z@XBTCGpDZ85y!NNIfxjKE{8`1$;65aF6>B9r8IVu_yMWQz=7uzpY8K=`u!mKoLbgP zTkpp+q#W6M1Bl)#1$Y)naQG>nModh2Ddr0VsbA1-j~v9Rx+M*1dEPzi%K0YFoflqI z3yh=Ob?8K=o zGi^;lp&^ zwTJ2?2J)-RBq}I3jnf?ss79N|>TM2`DScBj?ou8#vd59X3}#%V+VZowaDm+6|1SyR zG@2!!d=hV~RpeBbF5v?`?vORt8(&W%aW!L)3TdDyWTq8nWCa)73>y2*X&kCIyas(*R`1g)E_uOsc9HTGYiI=y?*>PLgF6%zu47gVAAq5tJ=C zj0C0ws7mtLM)>mV%tn!*|4d_H{Arj<3(U9^3U;uLD9)eBXFS7(U~G(PqlC8f{y8KJ zyB*GyxOEPPmKR^GRquuSks2Ko47X>)$LIL81bJWJU=mY+jn#>>=mb7^w0x0F}W8nEUj2T^wJy<``ZBtnRJfv$5C7HR@TU^zR?Dnh2#ee1K1bQ1K#?*`RNW7TBW(u18#( z69*~@413sZv`E>ya4dVcO(k>DBOPU+TC*C#4N%;cF?dCKnRsQ;Wyc1$6YZ8x8%viSOfP?A$r3x%NN{j7rP&y`T6B3vNu998MXmlrWZqUrg) zy_@_hF$5iboV*mY(=PtLEF;`-MT(N}c=aM=*|4-r3UAh4k44)DO-f%)bCf!jR`Php zk{1X%yr(Y^t#i_~UNU`FOwP$;s^=mtSxuhfcww7_-7iXrS_^{w#Wnjr10<>Lr{9eB zUyR(d7jQ%>ydylndW*8;J+qkLc}?T!1sAC5UC@2rl4Q6iQ~mmSC-^@H6{>w58h!xR zU*m6Q>3T)@^uaYdJ_;>7i}(_p4+i8l>U9Hee3frx!t!S%GWFM%_meMsb8EUvLf@%@ZW7Ul_`K!2Ub<*~<-1 zcyecm7T2}=*Us-ghaC3RdK7N}MeZ1gcMI^-)}+t6_FdWc{jV4y*lvO-qTYhD9ju~Sy#(p_(Uj(d1?#amjueonZHofDQ%xlb-BH%lxLZ70sB zeMZWt)rx-K{3;FfQAUr|42AV0|0)3}?WCilDtlj`vcOQTE?E zRY%|KXu?<+dZo8QnRI0WtV6@2#%yLIfSnCW4gUdA%(LjBiL9!#ZmnbBFb#e+B&ocE zrsu;QtdX3Ky;UA@MIvus2k%PV77{W>Ji7?h2TeSqI&V2FK1p+%yW3|+%lrwx(4RVd zMGulhwb%{29T;;*s9f_ePQ@!jW|ebulNjUs&HU*n1Qq_hLDg#{vcEA=i7rF_Jn_Vene|)C-NLVX9SV}mF!OY|5KPo* zCGgDRl=`*XbcB_ ze)_)zJpf?I#iRH)yY=F>$Q3DFxRmZb4~e3@sRaY`ZLlA|*<`dQ$|>Q{bwXY_OZBT< zBbnJ{04{YO%-YOQm?S#flwXV_8x+WHy zG_L+&-1Oy6Dx~8m$DPbb;Pg$KI6z8cv$g=f6-c7Eai_e{ZPbBfOUQvou~ea)WjOD2 z20=AcIB_ZUSul_Ps=2J)g+Xxra2dQ4|B<4X0)ce>WuL2H1IUAK1#y|exRB9OoYhLH z(qJ^7MQGG*YS-*q(?q*kGgyvlxlBJcuDL0m%fU14Hb=C1%3_;TO2usYGT3E!40Zf6 ze?ekllee9vN2Ko7m{MWm(Sh;UGKUN}sfH^bMXlH;KG6#JJ;!#s*-3b)lxI_Bf7Vq$ z8{;|zn&I2>;F@VFj#DA&O7_M}@F1L?l&WF}qPbxiI5{ZGR z8lAse0Q(T_m!6OUaEcK3*OoGvjkDq#xc79k zbFFz8Mkr-kFm|g>X{{5H79u%~+w|+fLd!|zIC*yBRrQPJdR3Gn)Hv%*)az{t zEzW)O)-PTUZILGFB4-<~Mhm6K~M;-wf_ynDq{ zynSyj57RHoH9i8>M`B2n>G3mqePSz`+t&h@Z>f7#Cf@k!K(?@f!oHW zHjjTve>9Ok^D9p(1bYZtYV?y=wP!lc(xqaC@!NTC3IK#$|RVx$>K>g^JcZrM7naV)%`H$=k56^Kg6v8+71lOTt`+CRBEV=1_U|Hihrr|@+8 zr9er)Nr5M^>@i8JB?4kw=5F=Ow9mF-#@jY+>OET+u9(B6I0Cog6h(Lxg~Kb;lU){? zrRk@|ZEKI~j*wturUA&4XPi51iM=V~$Wx}|a2%*U;2IPh$>>ex7z#Ou%B4N)IoCgJ zbtM@3LBGLK&i;^K3#3Mzo#%M3X;++x!csM|Jc&;gcsLjTU0eRM4#Sp0yK#sf@J{`3 z#NO(f(^0czOzYTHRFSQ8jO44*cS3!n?EFvmdK|Q2F1gu8?211|+c&+Tzgbt}7Zlxd znemR#q2Nt3HrEi}PqfiEG;Gy@YWv+){daSpRR@OsNL-WN_BuB7NJkcOoNQ9pPj-BY zxj3d#2clQhs)N+FKcgmcvw&3xxm90wB^;;rZ1~f#IDL7sRxJa3xQJB;r1kaR(Ei`i zG)60@T%-ur0N+2V)*z&j8`6koQ63DfJZ>BRBF>%Sd+A~WLS@5P>BOghoU;K8a}V~< zR3zpn?yrG4L#D3cXU_1cwzqf!g`Gj44@*9p`=w1#+bC}Y0`ym0V|=+V(oWrs>Z&$} zT(8?O%vSeTu2BeY^UY9ZqWCk1kFRwfgoiIX0{qpVHMNYI(-&)#Tjk$vs@Fn zJH)C3*A`$!MG}Rr-*Mi4d)x9ivTAFqJlyRms61{xO<*0((45@J(1=)54Jr_xnVmh- zNv7VIwm2y4luDKjL3k?kS$*;hZSl@cIDMF<mo7LyFN&( zS_Z+}l#PkW>>BX^qLsXon;s7uiTgD;I_+f_1w*ymvVK(o4b~Z5DSV!R0h= z+VTkBrQADSv;x?@1 zgA2ZMuC#>0l;c?W7EAi>ra#l|xuDkfnq(%gG{O~#G6xS?SlO+!)Qfa;ELzy!YN~t0RN21L=PaUq%qoB(uuY;_9fHhMX*DGsB&$|t)J5?Aw)Cx^v zq1Pk)+Z%Om)`g`nGf!ilY^1xzZko#|THi9Rf3rqtXmHCV+qx)vt%5uWZ!*Q%V6R%h>xnw^ZpXo#Z zHiGA|PAEfkIfCAc#SuJnPdw{&6<>pwJ+Agn!sRL6dddr$90E+Wc&k`sSluS@b}ax@ z25KO>=h$Y+27zfjYh5(&m;*jZwSiG3x}L++%l+<2Hiq_M&~>9j`lIXPvv23$iJOlP{ZwJCyYO&eYiHS&jEI)<=`e5Sq@|T%m52XFb%J*;C865kc zF--ANu_`7`K;nYJfnR!7VUAE8y-v#4WcrjEb7CyfXM}8XE=(3 zl3V~%eY5s-_|E3ily>Fk;7;{DOpdRJo^XkW-3m*6fad#KU{GJm8rPuS>|v93nA3!D z7H;oGDm$+R*{JiD1l!tTVqvFGKvm-QTC$7QoBZ=8y_=aydY1JD6&I)8>C6NZ=UR)3 zvt!R(cCzTP2*IWaU$v@Naobx~qK%`eiQHlKPAa4Dna>!Lk#4}|wxDgKjms%vowBH6 zsDmBnn(DV-CJ|h6j`~SX{h$D6f^@uT<}9ZYG@g<*^=no?_29BVc7D%XquJHa+dhDY>X%Y^{f*J?v5F-^7w_bT02bMv8PYa^tL~#D9D@xlo+h zaoAwgjfr>b$bn4c1gXpw?E0(ZjO(_bERlJL6%yu+uk!hPg5WHC!g%ejkClLz7l7R z<4}otdP5U$!^(-E8$v(QaqV%T&%EqRPY}yoZBq$0N25@rsCklqSWyDliRTgn2pIZ^ zb9jAfV#7$9|{HfM`dy4})7jj^|pUr?i?@wv)>}hpNcY4Ss{fmW)V4@Uh2lCnVua!&&8A3F-!Kl-35Q zDv>eFRWFks>z;pRZ?GqBG@jW*xa==!Ptf`keeSTm^Y zq)<@W#>zlHw&v zx4RNh9z{wQcE(QZ|KdeB!#d~|Fa9V&dpf{#^EP}UiBMN9Znl!(r5pHsznHmA$Wi5F zf*@CdIufLg_993!&Hv}@`!p)GL~|@siN2t}2|Yy)+B47^2ye_%&1u3P`P+%r^z9OE zX+rF$Nj|y-qL%wbCf3*$Olk#M@Z634iEsCub8MV%$XP@`)80TTqNSTWEHdjSD`YemHdP+_f{g zQ!g-U-krmCw{2d~yvbx^@7f0I596g*>5{{{U%h8HiF9blw`wt(iAYQKbIWo%pOO2# z;z29Es}6Sz?54ifM3+rRBYUGTf7LaAO3qqu!@eagtqp*3N0Zm|6tehVyENCTkhlV~ ztBU4RS`S|3)T;bKeQP=TYhf55lWVuJU%~pW)Wkx?NG_p*&uUT}v0X3L?u=_646A<3 zDf_}V8&}gd{OeseB=)dVuNm5loAFtAL2A72Pxj0;g=7MGb@;f#XXOnrg#id%2fl4D z*S+PvEfb{X?1h>jT7x)m$Gun6FUM8;Or0npd554(jA|4kreU`o{-2G9Qp6gP0smV#m)4@N7HEo*SF-?|7bD8)r{a3gtIH^$391WY^M|Dwx`A{TyajkNChMt<8 zIqYrr*_{qKe3*YFGe_t7a6`r3QG` z(qA#Ja*7RJ9(j{v1<#MdfBQFOxcxz*bk>@;+DK>4K=iw|R<}&adz)eC{Ht?C-&;yRv=>Xp)qrg;>pc?M5keKo#{|aJc zZZRkIDS7&IEg73Uej-m<(Q!4(&LRTCOrS#zYHOtef7DX`xE$6nwZ&vT85b%@>+(Gl{u&avuMKpqjqPWO*e9O|fg1B`BFuAS) zA5Ashzius(J)+8miG#O%BCBF%?&=y&`xqKb_4o1fbGEI%e(-GUKUl6fq8BQpxyp1+ zo-DiT&^o5Q3pEq-Ga5g1I-WWXl%E|rg?fQ>=^OVs;n}zSxDbdhrk@Nihd~PEc?Ae* zxCAJCRfrG}a*x?JVt2QXc-Hv!3oqg}BQ7SLq<)&Eqg$AoBq=U@Jl_0CbO&0@m#Q^A z&8O~q-PiK?(8&)T=2{n11v&GoFK{odLRL7bvJF-(zOYS}_}ee{CCTvWWbP%H&!7*t zc7dw7VK3b~Lmi$T=g6M&NnfaxCc)eq+a1KvOz&R`7*aJPwl8m(AaaW9Zq$EuRURvbrtw)oXnEXKn!XOYJg)gA%riO`ESsSBY? z9F^p}Yylfc!0;6b+uq>1a~O{I%HP*dH>QHJ6Vx02L&kU~I?Z%XQ1fhw!~~RTDq$F8 zh@E-zVi$$%^yMgqD5LKSu5g6!Ij(*EH0tWd!;>7SY2O|pmf92Agc|yEHe2>rQ z0+%G}YLX(h(I8W*_GVQ>=1Bup0;fq~eIc6yC=28dJ&Cl|i8?4`yV8I~6NlVTu*GZ@z{vXd&hMv;z0*(B$> zqM9zAd{%C8i`;J^@_!<3J0sm|SzAC)=xT5cywCboCQ8Xtz_XNU>_V6-?vCDUab|S> zWYO!|L?(I3yig6-wx3+|1Lecq4BHgHG8CdR6c*Co%Fcvw7H*IZ%9JBahn+zT?=1kv z0p!CnD@_cggZ)Z2`?wN$$6Vq_)k#G$t}hT9tW#y3loBPxxDYvl z;{|8eQ1>bi-C3a%ob!Y%L}Nagu4TJ?%b>UG>}|_&hMjXd;?u-m$1-2##%Ues=*ian z>X9>AE2m~j&^Poi@+d@ffe|>i>Ay@Tw8vo$@ORRKgpK0B$qXxHgNw0)Obqs)lck`I z13A-96VXgpuq6PKOs&j14FlF%wz*jRyi@6P8U_eR`7fTBiPBEw`s2RItY> zxtP5(4LR>B_xBf+Hf>>@?tGVznjJ%~1zk%zNU+r(#=#K{n6=~`WP>6Y1e<*V`B#_s zt_;Hgl!sTtcS}-C2Ks3lE_G2~M)k;3IYw@B*{UhsLOS~EtyBNrigGH?tmk+!o9yb* zIISXTuAFn)W8Z*J#>n6O+uEtqPk~$8!uIC*nLM9t@Ut!z<{X486O@`dI}D>a`Lro( z%6WN4t*Fs}Ga(P6D--S^58^ATpU!w2oFV>rcd;o9OJ5N~BxOz5p@V0NgwD8=nyD}A zw1H=;`;y^BHRO$ydy2erz&iu)81UPKz&h)}l^a!`(wHD!6vd}uJy4hVqTSKMCGA>! zo-XSIt^Nt(wcjK}MCJs32CV0IOa2ape9T{`iy^O4G9BLbH}{@!KgO6cQQfl5ZbiKz z{vDTPM&3x!mJIPSdrUuA&a>aL$6oi|_g4QDMVU~wwMOjI^eL%}G;M4i)<%P9 zK#z&vKuTtD3bvDB#u&Nw$!MZc4LA@Z<(nZ_I9u#DaNDzL&*CN+H-o zH68j){#L|BdjAo+oUGrv?1;JQ1H~|h49f$dxj<2(LZy>^CB9?11-GjZC`I~DpE&}L zLm>dLee2sn6n$1gI+knnWWc^)2tdoB!Bp_?=hz9atU1fr>~|GwJ9g|RBQcudMpPoD zL1s%>T&q$)~w!VQG*gCs_*4~H}<-xG7{4!>tkTAonkS{ z0@*~xQY~-44@-ptCPmyBs6Hhb=!&vBe9n>LX4QBcr;|^ZZq}?yNsj5^W(s^P%u5TsrRu^_GsEp}FW4B3RRvS$FSeO4Aqbrg?zo8n`%vVC9u)}BQJRWRF#9rYGNbZv6`B8$<2df`_mAktSc1l3|Q2c|sDl-lYF zWBaHTNH@OwcGzS35_oSCYaltlO|H+5Y8X)k38~dWRU)i-$1Ckw28_~>y4-#HP|k1- zBVukGcQCqib_D`+gr0O@ZDEZ%Fp3t5H3pn;>>NOufm>~IV9zcW6z+QVbunHMl)xtN z{@+)N2+y=jucAN@f-XH&2$szbFi24!$o- z>H`V?YOkTE1cavEx&GuOMRCTaexoqg4FR?&ggMp(gG0s!sxToh#NawjNC#6ZTP|yW zJ!wJjf&H1+_=^9Qigr7@oJs8<(3*o+NWa%!Z_!Pwvz}jw-wX@4*KEH!b)73}DlAG( z$)B(Z>FtLB_)rKNfh8TUvgxbF1QYQ(dFwdy9=H0%Y8n5_@|cq324g}J#8NmJ80Ey2 zCM6h)*pfrrsJ#eq?7%tEy9XjFrT5Z;kzd-z6ML6Sw<0&i-BGNV=qOvD?Z1SFw*qye zq7W<|Ox1Zl=&=yTUN^%>f|w#O1ow9?6>?na-`p?pjzA$FBuo!^?|g9xG!Crhh@Uo4 zwha{L8a#$XV-bce;m<|zz_bA!xBvK~kZ7z3QBAv=tdYeMc6Rlw?hU>vB_b>BEg|2z zlT3HYBFBKb#CO&g$dYPm$5E(on7jz5V0nB9n*PuJAxzWwV9<1hZydF^mo=j$s&vv& zL3f6bXUsn?5r9p!w7`bFVeLC#j#v+FKEJDjEm>vxFcb$G`oMdXdJqt50r_v1;IyARMS>6_}B zI3bu)By;4-X2-!5ib#sRRPRaDm#>HFX z=;XC{C&WybV3g8@jN_3Ue-(dN8^>tiL3aJL<&g$fB+nZlqR_3z90siVhly&|_*jJD zLZ4ybG)Z_a?L=@gk&tm z^~9YWwul6uG;l5D0oqGSkf30|%pk=6A)~SeMA^8L-RC|!d!hA-DS>}0jmTIgXy%SY9`@cRJWu6dwTl8a9CeB7xMFuOoxcNO|ixn1@*D@6Xug4 zICf>FQQ?4;PLcDkOKDu>UxtzIbw0?X(-TPla_-2ID#66CLJkj)2bjv)*mEzF`L6#%bY;snuyHdg@Zj0$qA$PlT+`hE8Y7 zz|r%~%-ziWuFvUuUhCWaR%|Z*Ga5&xH;UspJ`E4J$(*-5 znGODxm=zlantpcdJ-r)MAQbQIS+y>94-B8okMwFrlYKnCn?j}dB|L;%zOGJtvC@b0 z=r`SRe1!g?)_jP2`wTs1O#R^Ap>$aG$>2exy=crCMo@j`!O2Bi>Ttj2bZZCC3(VeC z=LNA2s1vOe*jol^L&*t$C^H5V8&F9|wl4^Z5X>(&*S8QU)PgStEAci9f%JLEQ`G!rokU75-pf6$?UOK3@)8yK9rQ^>AUeMpR_%H>fIOHQa;RmD>) zF%)H}yl=`zFt|$$FbV^i(}y}U<$7x}X!acRnvyiD2C_k|*>J`k@9BDP{JBK3RB<2- zlVl=8%4+51`w8woWDhx0mu|^^&$q0VhP_E~LbL#_a1jr+6v)wkQPOCN9lA8z@Ndsa zJ|6p6|3hu|$fN)VLoghGF8jIgP`v0E#Qfc({(F=S*a+3T{0CV*ao8){gH4vzxcWv0 zD^zK#Pig36siot@TZw(o`wAn;51%!^if8xFL!!-+!i2$oy#+bJ&f(NmXYi7^NjF38 zJNjxB-OUuaD2~nJJTaQ{J#p%iE(nhO9>dlO>WeO>zbjm82Ci%uE#R7vqj;zbPS)UFV~6M2 zzIH%oLq`?}R^gI#G`uM1J+cLbZ{%ctv_e>y^=jIzD2W(R^_%M?Rx>!_FWW4$70# zlCZnyD<&z`G)k{U9gEL&<3h2cArn>{_AYvZV|OS&%chu>C>r=!jf1XC!S7{C4BO)i z*@)OdFjr@0QeLY@HH&X^2}Fvp*X?&_TCO23I3@JSbMQ*ETy#I6|KO@Rgx5(_OD(v? zN|bQ$YT%MU>i7RtQh z*ZcYYVBl%kP@yb5eE8y~E^mvty6%%l>pl9|#p3MJg{vAU4eiZ%g*WnUW#99H+$LRJ zP2LywXFGd$t;+BVDOgpmHue(St?9*ujlq_@#RY78-%Qh8waxsXC!l`i7-l|Rxr;{)@+4@sMwD?5GePZ;lU^w(<^ z7Y?O5Ie2+^{V!Twg2sE#Jst@UY$<#Pgp;0zn+uF{}N6Kh!Fu9u^EHGYU$O12OzrC0Z_4HKXjROmn z_3{iQTBc+wQoN=`b8?t7ys7xMq5AE?eZGsErz+pG`b8t1cacn&7Ko5DAQJ+1RiWeIbm-+_Q zecp;=M5466Y*`jwmfbpORV&M`Z)mw24`l=%ckl)XoRs6xG>uc`i~7Ie$#Rq^PQdSA+N@im;HUuh~2G|F2; z&{=P#qpM>G=16eQa|xRVvD5CI;{si6v{T4Bq9RO!l*{k8+mA8@Yd^%2#tR{``rtzj z>k}&GPIJhsE?~`i&CkPJB<4XZR(rn3fzjx^d9R;k;sWaPRkN$Mtky8KCIp4Nln%q4 z{^*hLd1;|kUKt_H zc>6v2R`Y_RT|;dKrsLVC4b~Q)XZH}Pyd>q%cQMkpLOiUez!#9bgWXskdQ;a(*1()_kv0IuA~fhXaGQ{4FEv%-wP&LnH$iV+ZY+U z(HhY@IgavJIxe%uu02ty-&K_<-{seBjqcPg6dO@ED4S~XMjnwkJG1l=GBAa(lgRi^ zMYvwARf3#>II#uCdkuc(GsmhF&6~8H5EGjmtw2?vOk_;@fZi0AD1ug!F=asPc(u206TLM6tSflY3U|=+@CTrtgFudO&#X zlk7teO7i#j_wC413ZdLcF%a9cYaK)3%ARPr0xk22A_aNetB@-F6NW(yp|92YB~ZJV z$KmtTh~BBBWBQKN6(^eXMlOe3s1Hmq`1wd^cYUZjY+a=mzG8zZmx5~(Oa^*VI`~p* z4|<{ruJxy7@8ooC-s$@rIGs(8>jo!l4U`7#m#x$_#zEWNOf2@g!(}*Whf-=)mxl?z zS0Sh(RDmo>)ex%ne1l^Wr@GRKWJI_ptL%0U3EvjWaG*ZNDAHzQ$(&T~WZh2_MucLI z$L~WK&nw{ZDh6+t7_owR+2Tb3vvYhUyG=nx)KVY`5FI)jc>~&j%71HO-(I?vz`tG) z0{2Ig<`lc>;+is*rAz;rR^D}A1pHa(t67;7?40?IAc(Q)p>M8%HA!W6t-gUMR}$D4g?g9hqX zqi+mH?Mlqb?@E;nTG&6#5XZpYSi|1+6kA7~@YYn`9i^B|+sv{0sU#_ZpR-vtIco!J zhzmG~JWQ=)1ld}gH2i&rL0u2N=ILw}$RQ+78cUss-5lTiNym-hms}Pb4ARjE$NdYt#wCq&xLy^t-oiCxt%4 zCX7Np%W&hA?I9fb9aLkChp9+=JXLbISnmGLAWwaYieE^64V>O?%mtguwxemr7*_(? zD!6eF3086!+_{tHJW_pT-=Z`t8@g?yQcsDVR1J-NT{DaftcQta$*yFNjM(zi1U-^j ztnj7!&ewjHmk|rc3gDNJgt=yM==^>>Zg4i&($j!RFP8+AlZjn;S1Zjy3rBpl+yYKK zi;&gh_7wy3h(Od5KL`PgR*wCa(q`uNukyC*zD=57(!r9n7S^+BT+MS+yc_yRH27PCDBuBX_i!+MV_OZ1Tz%Lm!T`m@u?IW}?=eKO|o_e(QTw4T&}P+IuPA ze4xu0VOtRLpn|$-{A|=msn-Tqd;HiJd^=dY&q==fLSL1Nyx;(zUV0ve1*>+(Uq~a7 z+=%v;*9f8Mnqgc>eD3VtyQ>wy%&OF9S%C8|Sl2cKgGKj!QN!umqJYbVA*1TdFH+ze*&r z1P~qR^|5J`MbwjuRFn}73$y6XSg^4j2~ELblhJRB|;?M6`>*yHI{fzsL-^eyQeBdpCg~JZpEZw|uc_1A_2kegxNK}9Gy@WX;|3{0wPquk7D&9%P*Uv8a`=~ zclLa#djxiI()q&eE~v-4wj*L$`m#gnCm%)pNLEIaEmKuZ2t=A@9of2(4U8?*$~PUg zCQ<-v&uIb!i-f!636a{);GmH9-<|93MWi0f35FljfG3xBqBFK9gJi|AGBgC5TQH&8 ze}_CF$#5mIlFx^`zccrj%>_%UJvPOy${M=egkG-Cm^)n-5S@eBT|#Mquzt>&y;BBg z6_V!}IS~b2YOPBFe5aYg;mXexRa!SPOwHKWfOfG^oVwM4aJ#Ikcn&-$2TPEMxcF{z zuM!>?^F?UA-jv>`TQYw8mtRy--Q1(JhuIrI;QaDJG1o8%2kKkZz=UWCn*FgXXqGy+ z%f8^*IN2ZQCy2iFh&<9O>lo{5*jTUJ5w)1n1LG#+9_~sZ4Wd=^p}00N!x3wkpvM-t z!xDry&%ls;qTCEKo{*Of&}SZ2^R__{S)d*gnx79b?_3}g%!6XK|1mzTP3WCn?X$rU zoT$5ysAwbNLMz#3lD6TEreUr6Xq=ys)vf?HC-}rT#p|n+V^sAK@;O08c+S9_`o;2a z_ClXse7%)DqJr87o3Z(g=~r8|b`0Asb8#E-Ta_ve{`5m}aF!Mufl__mh%zHw!H5q2 z0b0I74(&XW5^Q?Q@Pd)v#-SPofvM3mXLIWk0wovpX-eCHo)Bec=%Cac`>yE~Q&YTgy@w-$O7?>)REtB= zLe=~tkr5ufn%t(MSA_W%JtIn#VdZV&q-ijFQomr6=WQRmduPUg^%joAiA5PP4QJQx`N<_;q1Zh{t!I;yDM3KC_Kc#TEKY7(zgSZ5lZ~RThv3i7kWzK`$PN^vyMj2#C1L#8g&V zJZRjIzvznKJKO1T9jcMD)hyP*a<6So$QfUi*z;r;hi9``%!8vR#Z3!?zcx%2Ko4OC z>r2?feri7Lu~?dASYj(qxX6R>jeB192kqsc&{03keiz0h zrVrnmSR56uq^FO+fZvuA!vVB~!9Gfzkk7F9I|rd~e(?nE?8De$IBMY$4ckKb9=`n! zi6Su+EIEgW8WBCTO)YBZZmw-&5T5vrI@3=8q5LHD3_8ArDhi3}XJE^L&DH4}WRqZV zX5O*#?Dn~)ek104_TSvSflA%bhIt!b$gaC%6Ph8 zkZnd5KJYWYLndrzQO-F=Z3tm%5)5c#e#DHo7ZU666w$YC$|lI8K_Ul((JX>P!|*DX zvBrWH6Jll=(-A_)ym~P!9kk0w#mK8Lvc0djHJ2B7<2+hPq&C{k%Myx0Ha3ys zJ-Nw|rlm%cnJcyxo_m48OkfpAbQ|0$+E}Vvn zO>ar@r0O@r5MSe~dk58Hjc^DVy&o3VQ)+^F+=e`&T+g)LA~@}l1b>R=;c{YKS-ClN z4%#hsOogeDu=t<`ogkiXnX&dgdS6U95u)1W>H8-EvQ5rWv0h4CyB$J;Uxf zmVy2E2!1qh8p_OS6s-6&bJmNe|mq&~^x zn}Zr!My41tl7i0%JciUZYSm53cnIO+RvP$!o|=ihx60>_^mfI_SkfcLeDLX7 z9gB<@2J_vA(v_~tCaO8Mj&O6>RLEei7fr6Eqict*MySY#?>AOr}1Opgr4LR|cyj zo}PUoH>4`&KEyBL3xzMGgy0gIuX15*Uy&QLWiM93!*l)gJS9JQDGWN1uF}#;X?`z) zNb7iAomj0KSu~OqQXx`(CzoQ3n4)i>f><2Xh`Q}czoXsx926i=sAeEZI+o%uVHFZ? zIq1VIl6$}+u6z+juQix4_Vxr^agr?S11TCaV~ju?Ca5ljy)!8Y^m1KO&a5Bpv$rOm z7=;4U4yoPpG-&u2z;GF`UCeX}5`xiqzVAVi^t{Lp>96xb$!z6x#x{qRDbhbIqZ6Bu zJ+?m*e~vIqCaNfQKw?*nU^4EZ-l}Cz%GBSN6`B}=40RG+m*Ea)<^Oz{$_?TVEy43% zaz!&@>;0IkbuuO;V3BKHfJy;<7rD30T^obnw%m0Yh|H}E&bDFj4P<_c!?Jq8QCJ#Y zPYAgh-N~J|OIWXDYJpT=LX#HFU3VseufRSn45Yy^Ju29ppDLLnnX?9X$xci=sswqD zF){)vFZ_cIg4-+}-q{8|6nX+vS#=YmhrS&F&O%ZrWV{TbXxWvUYeBz%V{Ewb=|WVeJrfe0GwlVH65&Z z>mk%QA4V}#3_Y{!IS z?fj#L?yhC7Ed&_}M8jM!U+AoLDM;mI`*&@#PfuMbLUb?^@v7!qi#l=%sJADKjMZ1* z&s+5O>+!OeU*>aD5x$OpY6ScA!+?Gzt%4~KB zmIvQNtB(Fo^aE@(enW16qV{HZPeQh{;OL>|a~Dqid)3Wc)e$iBG8Z~CI7Rq~RtPv) zIcCTUR4VvZ+E5t9{`sTvY{5Q>(<<@C*l5a@DwAw^qs&GURpyeTgZ&<(Br&*?dLQc-dJ2swboInbN!S>kNu= zT(`O^NX>~txkF`irTWqIO#;zJs59M!byVS`LZ}SNbg0TJvpT*V1jQC57&tbAbpYEqON`UWYOZToo!?*JMF!(XzVU zX=WFx)$D^qrU?h_q7L=?uuRr1l)~0qIo}CCEn88?Z<>yVtHEuO%cB53O?V-Chd-Zfus$> z$ndn`Jxxu|bH6w4)6-i+2_I_&Z?KrE(;Md(Ag!6r!&isT?~`lQmr^uK6L1UC1d6jsgE(yx*zAyUq~E_&f}msWz?9ip3eOx`)?myztJ8 zFY>zb2x?Da*yHJD<4lYex~q~JM%78vw9o}^1V=PHl3=B@Q39hOgM${di@U#GmQU7D zV=k$M$k_TYygiy(;$o-FKD`CONJgX;o4%^Nh@QMWYUa?0WP%;vh)N! ze2mWICw-*UH`DTv1N4VewOPMohHhJ?d}1ro=nBiT!(g^ENk@X&82)n zOD2YA5tIXCSgFNWEzcu~nvNfh6xP0F)|T@5E|oD&!I$T;Ydl<{uL$QpfU!S2i9b$; zyU3}Ds=?zmNo#Rq^kC|*_9QZ>3fbzBA^XB_ncGI3*>5%!-YYLQJf*N;bNLv_j6)^Y z7S8$TjY(nDorViLqS=B-I<~ZC@#2m123Y@Mf8M z43zO;5=z`=80}A5cs&Y76#)TX^NP9Q$>B4o$SAz!46JKDN{al4U32Y;1E}>P* zaHY3T94iEGB4GD!p%!4=%Jk65cCWFhSQ(llRnA*)!gmw4D(KZL<&g=f;WKOOek69g zFlDfKq{cITpbmN$E(09->Y$A@+6&(HY-Pt*E`f>A7K5BPILT&05LPh*~)+dWe>D$VL_Vqq*(eo_&=zjp1^>ViLf*z!y# zF9ib12Zs7OObY<;SA2u~$DjZGg8R$PvA`cYf2)1}|2q`_Z--L-eCU6c&Hoby3V{5F z9kiC`(4nsy6e4c`0J6Wp@_}am9VRUyBqFOM@+b3;!+*Xu;=eGD1z5m-y0-r`@Q-2Y zKY@Q5nSkMHtoACB5sLRup^QJ7`9PQ71L`{)ncKb!XZ#Gl#V-nEgarV?x&AqX{%ZhM^MNU0zlAlj zHMBH#_yt+$;iHJhs~qmZzZt9?KXJ&5rs}|COdhV6} zn!KiYehy2mtKVY(b2{oj+sHs+Qn4=t0PqRtXQKtcKz=87%xzwy(&m@$PU&metbA=K z-ugc`6gcSLVp|(q+x{}*+2N7W8DB#^83yDZ^KpNAJ0A#v_gmywgI#SMEPrtq1Gb&z zjbD==Ve`*M`^)?m+Sc(8?UY}T*ozlpXrGHTZU z(**$myrz+VZTZ0KuHOSYnOptBU?37o$<*sp!8Y>GdCBDDx416m4o=ScRtC0izo18h zuHTNlc7z|?06$qBbn#nsS96nJbuT|_YW?Ysd|)aJ=zmKce^uD}x!?L(p6K7;V)*|G s{+C$M&(xpi@c&I+Q2Vdczt8B)OM$<}F#v$~`Z0h80OGA*AL{`B0~z7w*#H0l diff --git a/.yarn/cache/systeminformation-npm-5.31.1-810ce63c49-1fff0b2827.zip b/.yarn/cache/systeminformation-npm-5.31.1-810ce63c49-1fff0b2827.zip new file mode 100644 index 0000000000000000000000000000000000000000..f2ffbb3016d0fdd42fc1ebc3e505889ab23b6187 GIT binary patch literal 164057 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