diff --git a/Cargo.lock b/Cargo.lock index d448b3594d9..f2c92755680 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2274,6 +2274,7 @@ dependencies = [ "platform-serialization", "platform-serialization-derive", "serde", + "serde_json", "tenderdash-abci", "thiserror 2.0.18", "tracing", diff --git a/packages/rs-drive-proof-verifier/Cargo.toml b/packages/rs-drive-proof-verifier/Cargo.toml index 5ef2372aee3..d0246c9a8eb 100644 --- a/packages/rs-drive-proof-verifier/Cargo.toml +++ b/packages/rs-drive-proof-verifier/Cargo.toml @@ -47,3 +47,14 @@ derive_more = { version = "1.0", features = ["from"] } dpp = { path = "../rs-dpp", features = [ "fixtures-and-mocks", ], default-features = false } +dapi-grpc = { path = "../dapi-grpc", default-features = false, features = [ + "platform", + "client", +] } +drive = { path = "../rs-drive", default-features = false, features = [ + "verify", +] } +hex = { version = "0.4.3" } +indexmap = { version = "2.6.0" } +serde = { version = "1.0.219", features = ["derive"] } +serde_json = { version = "1.0" } diff --git a/packages/rs-drive-proof-verifier/tests/common/mod.rs b/packages/rs-drive-proof-verifier/tests/common/mod.rs new file mode 100644 index 00000000000..ba341f6c3b5 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/common/mod.rs @@ -0,0 +1,282 @@ +//! Loader for the proof-vector regression corpus in `tests/vectors/`. +//! +//! Each case directory carries a `manifest.json` (request parameters, block +//! metadata, expected outcome) plus the raw blobs (`proof.hex`, +//! `signature.hex`, `quorum_pubkey.hex`). The corpus was generated from the +//! Dash Core fixture set (`drive_query_vectors.json` / +//! `quorum_sig_vectors.json`, platform v4.0.0 state, protocol version 12); +//! every grovedb proof commits to the same root hash, which the fixture +//! quorum signed, so positive cases run the full grovedb + tenderdash +//! verification pipeline with real key material. + +// Each integration-test binary compiles its own copy of this module and uses +// a different subset of it. +#![allow(dead_code)] + +use std::path::PathBuf; +use std::sync::Arc; + +use dapi_grpc::platform::v0::{Proof, ResponseMetadata}; +use dpp::dashcore::Network; +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::data_contract::TokenConfiguration; +use dpp::prelude::{CoreBlockHeight, DataContract, Identifier}; +use dpp::system_data_contracts::{load_system_data_contract, SystemDataContract}; +use dpp::version::PlatformVersion; +use drive_proof_verifier::{ContextProvider, ContextProviderError}; +use serde::Deserialize; + +/// The network the fixture chain id (`dash-testnet-51`) belongs to. +pub const NETWORK: Network = Network::Testnet; + +#[derive(Deserialize)] +pub struct Manifest { + pub description: String, + pub request: RequestSpec, + pub block: BlockMeta, + pub proof_meta: ProofMeta, + pub expected: Expected, + #[serde(default)] + pub expected_root_hash_hex: Option, +} + +#[derive(Deserialize)] +#[serde(tag = "type", rename_all = "snake_case")] +pub enum RequestSpec { + IdentityBalance { + identity_id: String, + }, + IdentityNonce { + identity_id: String, + }, + IdentityContractNonce { + identity_id: String, + contract_id: String, + }, + IdentityKeys { + identity_id: String, + }, + DocumentsDpnsExact { + normalized_label: String, + limit: u16, + }, + DocumentsDpnsPrefix { + normalized_prefix: String, + limit: u16, + }, + DocumentsDashpayProfile { + owner_id: String, + }, + DocumentsDashpayContacts { + identity_id: String, + to_identity: bool, + limit: u16, + }, + ContestedVoteState { + contract_id: String, + document_type_name: String, + index_name: String, + index_values: Vec, + count: u16, + }, +} + +#[derive(Deserialize)] +pub struct BlockMeta { + pub height: u64, + pub core_chain_locked_height: u32, + pub epoch: u32, + pub time_ms: u64, + pub protocol_version: u32, + pub chain_id: String, +} + +#[derive(Deserialize)] +pub struct ProofMeta { + pub round: u32, + pub quorum_type: u32, + pub quorum_hash_hex: String, + pub block_id_hash_hex: String, +} + +#[derive(Deserialize)] +#[serde(tag = "kind", rename_all = "snake_case")] +pub enum Expected { + IdentityBalance { + balance: u64, + }, + IdentityNonce { + nonce: u64, + }, + IdentityContractNonce { + nonce: u64, + }, + IdentityKeys { + serialized_keys: Vec, + }, + /// The fixture grovedb state stores placeholder payloads at document + /// positions; the grovedb layer must verify and yield exactly these + /// bytes, and decoding them as DPP documents must fail cleanly. + DocumentsPlaceholder { + serialized_documents: Vec, + }, + Contested { + contenders: Vec, + abstain_votes: Option, + lock_votes: Option, + finished: bool, + winner_identity_id: Option, + }, + ContestedAbsent, + Error { + class: ErrorClass, + }, +} + +#[derive(Deserialize)] +pub struct ExpectedContender { + pub identity_id: String, + pub votes: Option, +} + +#[derive(Deserialize, Clone, Copy, PartialEq, Eq, Debug)] +#[serde(rename_all = "snake_case")] +pub enum ErrorClass { + InvalidSignature, + ProofInvalid, +} + +pub struct Case { + pub name: String, + pub manifest: Manifest, + pub grovedb_proof: Vec, + pub signature: Vec, + pub quorum_pubkey: [u8; 48], +} + +pub fn hex_vec(s: &str) -> Vec { + hex::decode(s.trim()).expect("corpus hex blob must decode") +} + +pub fn hex32(s: &str) -> [u8; 32] { + hex_vec(s).try_into().expect("expected 32 bytes of hex") +} + +pub fn identifier(s: &str) -> Identifier { + Identifier::from_bytes(&hex_vec(s)).expect("corpus identifier must be 32 bytes") +} + +pub fn load_case(name: &str) -> Case { + let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("tests/vectors") + .join(name); + let read = |file: &str| { + std::fs::read_to_string(dir.join(file)) + .unwrap_or_else(|e| panic!("read corpus file {name}/{file}: {e}")) + }; + let manifest: Manifest = + serde_json::from_str(&read("manifest.json")).expect("parse corpus manifest"); + Case { + name: name.to_string(), + grovedb_proof: hex_vec(&read("proof.hex")), + signature: hex_vec(&read("signature.hex")), + quorum_pubkey: hex_vec(&read("quorum_pubkey.hex")) + .try_into() + .expect("quorum public key must be 48 bytes"), + manifest, + } +} + +impl Case { + /// The tenderdash proof envelope for the DAPI response. + pub fn grpc_proof(&self) -> Proof { + Proof { + grovedb_proof: self.grovedb_proof.clone(), + quorum_hash: hex_vec(&self.manifest.proof_meta.quorum_hash_hex), + signature: self.signature.clone(), + round: self.manifest.proof_meta.round, + block_id_hash: hex_vec(&self.manifest.proof_meta.block_id_hash_hex), + quorum_type: self.manifest.proof_meta.quorum_type, + } + } + + /// The response metadata (block context the quorum signed over). + pub fn metadata(&self) -> ResponseMetadata { + ResponseMetadata { + height: self.manifest.block.height, + core_chain_locked_height: self.manifest.block.core_chain_locked_height, + epoch: self.manifest.block.epoch, + time_ms: self.manifest.block.time_ms, + protocol_version: self.manifest.block.protocol_version, + chain_id: self.manifest.block.chain_id.clone(), + } + } + + /// The platform version the vectors were generated with. The proofs are + /// self-contained, so they must keep verifying under this version even + /// as the crate's latest version moves on. + pub fn platform_version(&self) -> &'static PlatformVersion { + PlatformVersion::get(self.manifest.block.protocol_version) + .expect("corpus protocol version must be known") + } + + /// A [ContextProvider] serving this case's quorum public key and the + /// system data contracts referenced by the fixture proofs. + pub fn provider(&self) -> VectorContextProvider { + VectorContextProvider { + quorum_type: self.manifest.proof_meta.quorum_type, + quorum_hash: hex32(&self.manifest.proof_meta.quorum_hash_hex), + quorum_pubkey: self.quorum_pubkey, + } + } +} + +/// [ContextProvider] backed by the per-case corpus quorum key material. +pub struct VectorContextProvider { + quorum_type: u32, + quorum_hash: [u8; 32], + quorum_pubkey: [u8; 48], +} + +impl ContextProvider for VectorContextProvider { + fn get_data_contract( + &self, + id: &Identifier, + platform_version: &PlatformVersion, + ) -> Result>, ContextProviderError> { + for system_contract in [SystemDataContract::DPNS, SystemDataContract::Dashpay] { + let contract = load_system_data_contract(system_contract, platform_version) + .map_err(|e| ContextProviderError::DataContractFailure(e.to_string()))?; + if contract.id() == *id { + return Ok(Some(Arc::new(contract))); + } + } + Ok(None) + } + + fn get_token_configuration( + &self, + _token_id: &Identifier, + ) -> Result, ContextProviderError> { + Ok(None) + } + + fn get_quorum_public_key( + &self, + quorum_type: u32, + quorum_hash: [u8; 32], + _core_chain_locked_height: u32, + ) -> Result<[u8; 48], ContextProviderError> { + if quorum_type != self.quorum_type || quorum_hash != self.quorum_hash { + return Err(ContextProviderError::InvalidQuorum(format!( + "unexpected quorum requested: type {quorum_type}, hash {}", + hex::encode(quorum_hash) + ))); + } + Ok(self.quorum_pubkey) + } + + fn get_platform_activation_height(&self) -> Result { + Ok(1) + } +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors/README.md b/packages/rs-drive-proof-verifier/tests/vectors/README.md new file mode 100644 index 00000000000..e47fc391923 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/README.md @@ -0,0 +1,35 @@ +# Proof-vector regression corpus + +Fixture cases generated from a real Drive state (platform v4.0.0 fixtures, +protocol version 12, grovedb 5.0.0), replayed through the crate's public +`FromProof` entry points. The same fixtures are replayed byte-exact by Dash +Core's platform GUI implementation, so drift between what Drive proves and +what any client verifies fails loudly here. + +Each case directory contains `manifest.json` (request parameters, block +metadata, expected outcome, pinned root hash) plus `proof.hex`, +`signature.hex`, and `quorum_pubkey.hex`. Loaders live in +`../common/mod.rs`; the suite is gated behind the `mocks` feature. + +## Coverage matrix — what each family actually exercises + +| family | grovedb proof replay | tenderdash BLS check | notes | +|---|---|---|---| +| identity (4 cases) | ✅ | ✅ | full pipeline through `FromProof` | +| contested vote state (3) | ✅ | ✅ | incl. `Ok(None)` proof-of-absence | +| quorum-sig (4 fixtures / 7 cases) | ✅ | ✅ | 1 positive + 3 negatives on-disk (tampered sig, wrong key, wrong block-id hash) + 3 in-test negatives that tamper the `quorum-sig-valid` response's `ResponseMetadata` (height, time_ms, core_chain_locked_height) to prove those fields are inside the signed `StateId` too | +| documents / DPNS / DashPay (4) | ✅ | ❌ (not reached) | fixture state stores placeholder payloads at document positions, so `FromProof` fails at document decode *before* the signature check; these cases pin the `DriveDocumentQuery` shape (root hash + serialized payloads byte-for-byte via `verify_proof_keep_serialized`) and the clean-`Err` decode failure | +| identity-balance corrupted proof (1) | ✅ (rejects) | ❌ (not reached) | negative: bit-flipped proof fails as a GroveDB error | + +The `quorum-sig-valid` case shares its proof bytes with `identity-balance` +(the corpus has 15 distinct fixtures across 16 on-disk cases): all drive +fixtures commit to the same root hash, which is exactly the app hash the +quorum signature signs — that is what lets the positive cases run a genuine +BLS verification with real fixture key material. The 3 metadata-tamper +negatives in `vectors_quorum_sig.rs` reuse `quorum-sig-valid`'s on-disk bytes +and mutate the `ResponseMetadata` in-test rather than adding new fixture +directories, bringing the total to 19 `#[test]` functions over 16 fixture +directories. + +Regenerate only deliberately (fixture-generation lives with the Dash Core +platform GUI's vector tooling); a regeneration should be its own commit. diff --git a/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-absent/manifest.json b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-absent/manifest.json new file mode 100644 index 00000000000..b34245cddd1 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-absent/manifest.json @@ -0,0 +1,37 @@ +{ + "description": "Absent DPNS name contest ('carol'): proof of non-existence, FromProof returns Ok(None).", + "source": { + "platform_repo_tag": "v4.0.0", + "grovedb_repo_tag": "v5.0.0", + "generated_protocol_version": 12 + }, + "request": { + "type": "contested_vote_state", + "contract_id": "e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c53155", + "document_type_name": "domain", + "index_name": "parentNameAndLabel", + "index_values": [ + "dash", + "carol" + ], + "count": 100 + }, + "block": { + "height": 123456, + "core_chain_locked_height": 2000000, + "epoch": 0, + "time_ms": 1700000000000, + "protocol_version": 12, + "chain_id": "dash-testnet-51" + }, + "proof_meta": { + "round": 0, + "quorum_type": 106, + "quorum_hash_hex": "01080f161d242b323940474e555c636a71787f868d949ba2a9b0b7bec5ccd3da", + "block_id_hash_hex": "090c0f1215181b1e2124272a2d303336393c3f4245484b4e5154575a5d606366" + }, + "expected": { + "kind": "contested_absent" + }, + "expected_root_hash_hex": "dad905d8fddd7a31089ed57521ff006ec5946b5648d48056bce493357675ab72" +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-absent/proof.hex b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-absent/proof.hex new file mode 100644 index 00000000000..48db66e0a38 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-absent/proof.hex @@ -0,0 +1 @@ +0100b201039118e921c386a7a9c166dbad8a7df9b87fa7f3dc8e3bd4fb42e124cffaa65a02cc9a023abb3efe685ac357116032ee5eb34884d6c3e5861ea7ac662ab511f2371001282192d9f288b3dd8ceeba34fda695ec21d080458ed5d9503eb5916a63494a7a02dae5ae1465037089786f368eee27aa0437d77fbaf34d14dd299aae3d6a54168b1004017000050201016300ade908a28152707d22ed66d575d6f3ce38c27447c295a245272dc100dd0c4a621111010170002a040163000502010170001e5c60ed1b4311b6baf76a42f41550bcbba0f9f87d71b48e76d800c95f22cccc01016300490401700024020120e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c53155005401be78056200f8a616eddb15fbd41fbc4204330111709350c20535528492b5010170004e0420e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c53155000a020106646f6d61696e004412968f90b3c569b0e5b9760130f021137946563c0d05c6cb64233e4a35a57f0120e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c53155002f0406646f6d61696e00050201010100bba90275bf4b39ce726f641378ede6c4fcd17162611f992a34fea2ad303f4eeb0106646f6d61696e002d0401010008020104646173680060b4e46b6e0fca7c9c1634f80d1d3a18a9188165d64e81782800392ba3f08c5901010100310404646173680009020105616c6963650078f7ad26be337eb5f110a07a8d21736265aef4cb370c25b3aaa3f8d354ee191101046461736800470246f1e3eb733288ba8ee508b3b972872149b7ee87c6b0c05bbd4bb5982d93e7140503626f62818e82b602d0fff0c045f136090f3816039b90af1ac6f33f3ec84deba88908d61100 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-absent/quorum_pubkey.hex b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-absent/quorum_pubkey.hex new file mode 100644 index 00000000000..a1912bdde28 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-absent/quorum_pubkey.hex @@ -0,0 +1 @@ +b6087e2054b847ec64a1e18af3930d39fb040b73eb8a10620f9adcb1be85bf7d5ea961dc2458d601ba9003b1e39ead15 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-absent/signature.hex b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-absent/signature.hex new file mode 100644 index 00000000000..0ca209f79f3 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-absent/signature.hex @@ -0,0 +1 @@ +a4fca3d223938deeb9da82d0021a2cfb8cd7463412f7613c8943cd86a4f26b9aa81daf9d218c310ed3bb9e9c6a80b38118d16d27ff981dcc7ca46a65c95be36036eb0e1c4bc31801d2aa5699fc3d9932295f375bec3073e03c4279668429d319 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-active/manifest.json b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-active/manifest.json new file mode 100644 index 00000000000..01ea67f5d3b --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-active/manifest.json @@ -0,0 +1,51 @@ +{ + "description": "Active DPNS name contest ('alice'): two contenders plus abstain/lock tallies, no winner yet.", + "source": { + "platform_repo_tag": "v4.0.0", + "grovedb_repo_tag": "v5.0.0", + "generated_protocol_version": 12 + }, + "request": { + "type": "contested_vote_state", + "contract_id": "e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c53155", + "document_type_name": "domain", + "index_name": "parentNameAndLabel", + "index_values": [ + "dash", + "alice" + ], + "count": 100 + }, + "block": { + "height": 123456, + "core_chain_locked_height": 2000000, + "epoch": 0, + "time_ms": 1700000000000, + "protocol_version": 12, + "chain_id": "dash-testnet-51" + }, + "proof_meta": { + "round": 0, + "quorum_type": 106, + "quorum_hash_hex": "01080f161d242b323940474e555c636a71787f868d949ba2a9b0b7bec5ccd3da", + "block_id_hash_hex": "090c0f1215181b1e2124272a2d303336393c3f4245484b4e5154575a5d606366" + }, + "expected": { + "kind": "contested", + "contenders": [ + { + "identity_id": "7777777777777777777777777777777777777777777777777777777777777777", + "votes": 5 + }, + { + "identity_id": "8888888888888888888888888888888888888888888888888888888888888888", + "votes": 2 + } + ], + "abstain_votes": 2, + "lock_votes": 3, + "finished": false, + "winner_identity_id": null + }, + "expected_root_hash_hex": "dad905d8fddd7a31089ed57521ff006ec5946b5648d48056bce493357675ab72" +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-active/proof.hex b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-active/proof.hex new file mode 100644 index 00000000000..e88ff11ea0a --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-active/proof.hex @@ -0,0 +1 @@ +0100b201039118e921c386a7a9c166dbad8a7df9b87fa7f3dc8e3bd4fb42e124cffaa65a02cc9a023abb3efe685ac357116032ee5eb34884d6c3e5861ea7ac662ab511f2371001282192d9f288b3dd8ceeba34fda695ec21d080458ed5d9503eb5916a63494a7a02dae5ae1465037089786f368eee27aa0437d77fbaf34d14dd299aae3d6a54168b1004017000050201016300ade908a28152707d22ed66d575d6f3ce38c27447c295a245272dc100dd0c4a621111010170002a040163000502010170001e5c60ed1b4311b6baf76a42f41550bcbba0f9f87d71b48e76d800c95f22cccc01016300490401700024020120e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c53155005401be78056200f8a616eddb15fbd41fbc4204330111709350c20535528492b5010170004e0420e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c53155000a020106646f6d61696e004412968f90b3c569b0e5b9760130f021137946563c0d05c6cb64233e4a35a57f0120e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c53155002f0406646f6d61696e00050201010100bba90275bf4b39ce726f641378ede6c4fcd17162611f992a34fea2ad303f4eeb0106646f6d61696e002d0401010008020104646173680060b4e46b6e0fca7c9c1634f80d1d3a18a9188165d64e81782800392ba3f08c5901010100310404646173680009020105616c6963650078f7ad26be337eb5f110a07a8d21736265aef4cb370c25b3aaa3f8d354ee1911010464617368006f0405616c6963650024020120777777777777777777777777777777777777777777777777777777777777777700ba2fead8aaa37d1be007db47f2e9779b773387336b1fcb738551a2a8ca295ef201a5ddbf84df65edf5876f0141adfa01d1988f011c18020496c3e93599f57dd5d5110105616c69636500fb016703200000000000000000000000000000000000000000000000000000000000000000001b0018000003fd0000018bcfe56800fc0001e078fc001e84760400000420000000000000000000000000000000000000000000000000000000000000000100050201010100ac8e80c26488285c9ef7ce4167825d9e9bef26e737bb7f7f1340d69af3a8eb5910042000000000000000000000000000000000000000000000000000000000000000020005020101010012ec6171d927bc5d9f132f407acd3ab0e75049f021389f6430dd8d4ba87ce26d1104207777777777777777777777777777777777777777777777777777777777777777000502010100008bbee91750be1729b067ae752c218d46345cee65af3996e02cc4aa079d9b26fd10042088888888888888888888888888888888888888888888888888888888888888880005020101000092fab297d83548fabdbefbad2d5e3c26a4005332274f31ff9cd51c9436d401971104200000000000000000000000000000000000000000000000000000000000000001006b1c01010025040120c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c10400c1d2a7d2d0355e6a6e662719e9e8475444c47022e4f1eddddfb5b45a8686acea006a29c24ef5eb604e398952790112a98973d5485490ab94ec88844dd50ac7525100200000000000000000000000000000000000000000000000000000000000000002006b1c01010025040120c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2060035878fa5d0c12a20364a12f71fc2124b8ddc22d9d81368bd79b20400da6eee8800efe92f879d4c44f631bb52241d7606b85bbbab020cb55fd4395a887bd97101db00207777777777777777777777777777777777777777777777777777777777777777008d025ef5cd4abe01c5cc27c851dca48ca596628dfc45b454ee847bcfc824f17312b61c01010025040120a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a10a00f5b15a04f171a7a3fe3cf9dc367b0bfe597fea84cd7239384715570ce4551fe800a706a5fc391f817996f9e274f0b37ff0b8a61b579bf079a8da92846c9252d5511100208888888888888888888888888888888888888888888888888888888888888888008d02e6ee602462484dae8b0c314ddc157efc77b293ea2350cb615962612be3d768bf1c01010025040120b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b104002bb7188bd669db6e98f44ee502c9742d85da29c4e7824b4fbd27f9587ad2758a009b9c598e017cb597ea60903480c868289dd951ce282f67f97459c79366a9d0d31100 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-active/quorum_pubkey.hex b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-active/quorum_pubkey.hex new file mode 100644 index 00000000000..a1912bdde28 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-active/quorum_pubkey.hex @@ -0,0 +1 @@ +b6087e2054b847ec64a1e18af3930d39fb040b73eb8a10620f9adcb1be85bf7d5ea961dc2458d601ba9003b1e39ead15 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-active/signature.hex b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-active/signature.hex new file mode 100644 index 00000000000..0ca209f79f3 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-active/signature.hex @@ -0,0 +1 @@ +a4fca3d223938deeb9da82d0021a2cfb8cd7463412f7613c8943cd86a4f26b9aa81daf9d218c310ed3bb9e9c6a80b38118d16d27ff981dcc7ca46a65c95be36036eb0e1c4bc31801d2aa5699fc3d9932295f375bec3073e03c4279668429d319 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-finished/manifest.json b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-finished/manifest.json new file mode 100644 index 00000000000..5cff9b4d2e4 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-finished/manifest.json @@ -0,0 +1,51 @@ +{ + "description": "Finished DPNS name contest ('bob'): winner recorded with finalization block info.", + "source": { + "platform_repo_tag": "v4.0.0", + "grovedb_repo_tag": "v5.0.0", + "generated_protocol_version": 12 + }, + "request": { + "type": "contested_vote_state", + "contract_id": "e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c53155", + "document_type_name": "domain", + "index_name": "parentNameAndLabel", + "index_values": [ + "dash", + "bob" + ], + "count": 100 + }, + "block": { + "height": 123456, + "core_chain_locked_height": 2000000, + "epoch": 0, + "time_ms": 1700000000000, + "protocol_version": 12, + "chain_id": "dash-testnet-51" + }, + "proof_meta": { + "round": 0, + "quorum_type": 106, + "quorum_hash_hex": "01080f161d242b323940474e555c636a71787f868d949ba2a9b0b7bec5ccd3da", + "block_id_hash_hex": "090c0f1215181b1e2124272a2d303336393c3f4245484b4e5154575a5d606366" + }, + "expected": { + "kind": "contested", + "contenders": [ + { + "identity_id": "7777777777777777777777777777777777777777777777777777777777777777", + "votes": 5 + }, + { + "identity_id": "8888888888888888888888888888888888888888888888888888888888888888", + "votes": 2 + } + ], + "abstain_votes": 2, + "lock_votes": 1, + "finished": true, + "winner_identity_id": "7777777777777777777777777777777777777777777777777777777777777777" + }, + "expected_root_hash_hex": "dad905d8fddd7a31089ed57521ff006ec5946b5648d48056bce493357675ab72" +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-finished/proof.hex b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-finished/proof.hex new file mode 100644 index 00000000000..300633f010e --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-finished/proof.hex @@ -0,0 +1 @@ +0100b201039118e921c386a7a9c166dbad8a7df9b87fa7f3dc8e3bd4fb42e124cffaa65a02cc9a023abb3efe685ac357116032ee5eb34884d6c3e5861ea7ac662ab511f2371001282192d9f288b3dd8ceeba34fda695ec21d080458ed5d9503eb5916a63494a7a02dae5ae1465037089786f368eee27aa0437d77fbaf34d14dd299aae3d6a54168b1004017000050201016300ade908a28152707d22ed66d575d6f3ce38c27447c295a245272dc100dd0c4a621111010170002a040163000502010170001e5c60ed1b4311b6baf76a42f41550bcbba0f9f87d71b48e76d800c95f22cccc01016300490401700024020120e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c53155005401be78056200f8a616eddb15fbd41fbc4204330111709350c20535528492b5010170004e0420e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c53155000a020106646f6d61696e004412968f90b3c569b0e5b9760130f021137946563c0d05c6cb64233e4a35a57f0120e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c53155002f0406646f6d61696e00050201010100bba90275bf4b39ce726f641378ede6c4fcd17162611f992a34fea2ad303f4eeb0106646f6d61696e002d0401010008020104646173680060b4e46b6e0fca7c9c1634f80d1d3a18a9188165d64e81782800392ba3f08c5901010100310404646173680009020105616c6963650078f7ad26be337eb5f110a07a8d21736265aef4cb370c25b3aaa3f8d354ee1911010464617368006d0246f1e3eb733288ba8ee508b3b972872149b7ee87c6b0c05bbd4bb5982d93e7140403626f620024020120000000000000000000000000000000000000000000000000000000000000000000818e82b602d0fff0c045f136090f3816039b90af1ac6f33f3ec84deba88908d6110103626f6200fb018403200000000000000000000000000000000000000000000000000000000000000000016000fb015b00010400777777777777777777777777777777777777777777777777777777777777777702a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a104a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a20100888888888888888888888888888888888888888888888888888888888888888801b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1020101c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1020201c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c2c201fd0000018bcfe56800fc0001e078fc001e847604fd0000018bcfed0920fc0001e208fc001e847f04017777777777777777777777777777777777777777777777777777777777777777017777777777777777777777777777777777777777777777777777777777777777000000 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-finished/quorum_pubkey.hex b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-finished/quorum_pubkey.hex new file mode 100644 index 00000000000..a1912bdde28 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-finished/quorum_pubkey.hex @@ -0,0 +1 @@ +b6087e2054b847ec64a1e18af3930d39fb040b73eb8a10620f9adcb1be85bf7d5ea961dc2458d601ba9003b1e39ead15 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-finished/signature.hex b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-finished/signature.hex new file mode 100644 index 00000000000..0ca209f79f3 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/contested-vote-state-finished/signature.hex @@ -0,0 +1 @@ +a4fca3d223938deeb9da82d0021a2cfb8cd7463412f7613c8943cd86a4f26b9aa81daf9d218c310ed3bb9e9c6a80b38118d16d27ff981dcc7ca46a65c95be36036eb0e1c4bc31801d2aa5699fc3d9932295f375bec3073e03c4279668429d319 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/dashpay-contacts-incoming/manifest.json b/packages/rs-drive-proof-verifier/tests/vectors/dashpay-contacts-incoming/manifest.json new file mode 100644 index 00000000000..024981b8176 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/dashpay-contacts-incoming/manifest.json @@ -0,0 +1,35 @@ +{ + "description": "Dashpay incoming contact requests query proof (toUserId); grovedb layer verifies, placeholder document payload must fail decoding cleanly.", + "source": { + "platform_repo_tag": "v4.0.0", + "grovedb_repo_tag": "v5.0.0", + "generated_protocol_version": 12 + }, + "request": { + "type": "documents_dashpay_contacts", + "identity_id": "7777777777777777777777777777777777777777777777777777777777777777", + "to_identity": true, + "limit": 100 + }, + "block": { + "height": 123456, + "core_chain_locked_height": 2000000, + "epoch": 0, + "time_ms": 1700000000000, + "protocol_version": 12, + "chain_id": "dash-testnet-51" + }, + "proof_meta": { + "round": 0, + "quorum_type": 106, + "quorum_hash_hex": "01080f161d242b323940474e555c636a71787f868d949ba2a9b0b7bec5ccd3da", + "block_id_hash_hex": "090c0f1215181b1e2124272a2d303336393c3f4245484b4e5154575a5d606366" + }, + "expected": { + "kind": "documents_placeholder", + "serialized_documents": [ + "70726f7665642d636f6e746163742d646f63756d656e74" + ] + }, + "expected_root_hash_hex": "dad905d8fddd7a31089ed57521ff006ec5946b5648d48056bce493357675ab72" +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors/dashpay-contacts-incoming/proof.hex b/packages/rs-drive-proof-verifier/tests/vectors/dashpay-contacts-incoming/proof.hex new file mode 100644 index 00000000000..e24661821a4 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/dashpay-contacts-incoming/proof.hex @@ -0,0 +1 @@ +0100d101039118e921c386a7a9c166dbad8a7df9b87fa7f3dc8e3bd4fb42e124cffaa65a02cc9a023abb3efe685ac357116032ee5eb34884d6c3e5861ea7ac662ab511f237100401400024020120e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c5315500fbda163cb3ac4d5ca76ccab587620f53bdcbe46a96dbcb1e0ed411ace9395b2202dae5ae1465037089786f368eee27aa0437d77fbaf34d14dd299aae3d6a54168b1001f61ef78f4632c6b8cb48fd3087644cf1775a597afa62b67660943fccfabd887b1111010140006b0420a2a1b4ac6fef22ea2a1a68e8123644b357875f6b412c18109281c146e7b271bc000502010101005b6467dac53627bd556c06b7de5e97bd2d50688788cc29c251144d866715c4bf02b8d9d2e8f03bb4b317f5fc24e2741a89ea9f5bb6cb43a44ebbf99bf056fc6105100120a2a1b4ac6fef22ea2a1a68e8123644b357875f6b412c18109281c146e7b271bc0030040101000b02010770726f66696c650084e1535a92501db14221531aacd7009467348130c1807153e9b3af041b75f6140101010060040e636f6e7461637452657175657374000c020108246f776e6572496400c59531534d16dc4ec238c5c8a30fb6414b28cdbb977c82c77bfacf55ab8d3dcd028434a8d562d84df39d1971af05bd8fdd748581b35202e723eda1d4f737d7e93710010e636f6e74616374526571756573740094014b4c08659a34e5bccbbc817edffcec379dc3300ad974a50d539307d25bd505c202241ddcbc852479eec397f2fd32bcaf69ebadd79675ddbf92504d7e42436c1774100408746f5573657249640024020120777777777777777777777777777777777777777777777777777777777777777700902c3fed2d96edf795511e59795d4fa6fd6d36220a32a9aa13450e9562c5018c110108746f557365724964005204207777777777777777777777777777777777777777777777777777777777777777000e02010a2463726561746564417400c75709cd8917bb5116f06f15c1b88c22917b42e472c4f4ea2fecfe993291976b01207777777777777777777777777777777777777777777777777777777777777777003a040a24637265617465644174000c0201080000018bcfe56800005d8532c133405f01f9a65173c587d6a363a865b0c1e6fdc6a6b8b52d13f68575010a24637265617465644174003104080000018bcfe56800000502010100000dedbe3b16265a48243462cef6c2fbcdfcad43aed206f5310dbc84ad1a39d98901080000018bcfe5680000490401000024020120d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d300a2ab6c494b389894e8a4efe5a4e0673566880fd6a1d376962621108ced3d6120010100005e0620d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3001a001770726f7665642d636f6e746163742d646f63756d656e740007547e597229008c8eed5a86719458be289d9d088f8943866923c9c3cd230da400 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/dashpay-contacts-incoming/quorum_pubkey.hex b/packages/rs-drive-proof-verifier/tests/vectors/dashpay-contacts-incoming/quorum_pubkey.hex new file mode 100644 index 00000000000..a1912bdde28 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/dashpay-contacts-incoming/quorum_pubkey.hex @@ -0,0 +1 @@ +b6087e2054b847ec64a1e18af3930d39fb040b73eb8a10620f9adcb1be85bf7d5ea961dc2458d601ba9003b1e39ead15 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/dashpay-contacts-incoming/signature.hex b/packages/rs-drive-proof-verifier/tests/vectors/dashpay-contacts-incoming/signature.hex new file mode 100644 index 00000000000..0ca209f79f3 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/dashpay-contacts-incoming/signature.hex @@ -0,0 +1 @@ +a4fca3d223938deeb9da82d0021a2cfb8cd7463412f7613c8943cd86a4f26b9aa81daf9d218c310ed3bb9e9c6a80b38118d16d27ff981dcc7ca46a65c95be36036eb0e1c4bc31801d2aa5699fc3d9932295f375bec3073e03c4279668429d319 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/dashpay-profile/manifest.json b/packages/rs-drive-proof-verifier/tests/vectors/dashpay-profile/manifest.json new file mode 100644 index 00000000000..45fbfbbb511 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/dashpay-profile/manifest.json @@ -0,0 +1,33 @@ +{ + "description": "Dashpay profile-by-owner query proof; grovedb layer verifies, placeholder document payload must fail decoding cleanly.", + "source": { + "platform_repo_tag": "v4.0.0", + "grovedb_repo_tag": "v5.0.0", + "generated_protocol_version": 12 + }, + "request": { + "type": "documents_dashpay_profile", + "owner_id": "7777777777777777777777777777777777777777777777777777777777777777" + }, + "block": { + "height": 123456, + "core_chain_locked_height": 2000000, + "epoch": 0, + "time_ms": 1700000000000, + "protocol_version": 12, + "chain_id": "dash-testnet-51" + }, + "proof_meta": { + "round": 0, + "quorum_type": 106, + "quorum_hash_hex": "01080f161d242b323940474e555c636a71787f868d949ba2a9b0b7bec5ccd3da", + "block_id_hash_hex": "090c0f1215181b1e2124272a2d303336393c3f4245484b4e5154575a5d606366" + }, + "expected": { + "kind": "documents_placeholder", + "serialized_documents": [ + "70726f7665642d70726f66696c652d646f63756d656e74" + ] + }, + "expected_root_hash_hex": "dad905d8fddd7a31089ed57521ff006ec5946b5648d48056bce493357675ab72" +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors/dashpay-profile/proof.hex b/packages/rs-drive-proof-verifier/tests/vectors/dashpay-profile/proof.hex new file mode 100644 index 00000000000..5a262525560 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/dashpay-profile/proof.hex @@ -0,0 +1 @@ +0100d101039118e921c386a7a9c166dbad8a7df9b87fa7f3dc8e3bd4fb42e124cffaa65a02cc9a023abb3efe685ac357116032ee5eb34884d6c3e5861ea7ac662ab511f237100401400024020120e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c5315500fbda163cb3ac4d5ca76ccab587620f53bdcbe46a96dbcb1e0ed411ace9395b2202dae5ae1465037089786f368eee27aa0437d77fbaf34d14dd299aae3d6a54168b1001f61ef78f4632c6b8cb48fd3087644cf1775a597afa62b67660943fccfabd887b1111010140006b0420a2a1b4ac6fef22ea2a1a68e8123644b357875f6b412c18109281c146e7b271bc000502010101005b6467dac53627bd556c06b7de5e97bd2d50688788cc29c251144d866715c4bf02b8d9d2e8f03bb4b317f5fc24e2741a89ea9f5bb6cb43a44ebbf99bf056fc6105100120a2a1b4ac6fef22ea2a1a68e8123644b357875f6b412c18109281c146e7b271bc0030040101000b02010770726f66696c650084e1535a92501db14221531aacd7009467348130c1807153e9b3af041b75f61401010100520181acb67debb4c2c3aeaf6481bba22c23e59118b587c1adffcbe3c42e4754a6d5040770726f66696c650005020101000064064ce41f142aa0218b83251b9511d2d4affbb8012187cb1348f2062e61008710010770726f66696c65007202b077d63006fc15cfb2db05ddbee6d6dd7cf56291575215cee5216f7f1552a1250408246f776e657249640024020120777777777777777777777777777777777777777777777777777777777777777700282c1c78c773ac1bbcd84b55ad6bc8aa39653642a01744998b92045ce37949c7110108246f776e657249640049042077777777777777777777777777777777777777777777777777777777777777770005020101000071ea7f7cb98ab3eb3eae2895ce3a94c2714e806bb98c0e8c1177dde712022e8a01207777777777777777777777777777777777777777777777777777777777777777003f060100001a001770726f7665642d70726f66696c652d646f63756d656e7400da1581c51512f64b6e931eff13bd4fb05003f6befbbbc3b2962d208a582958df00 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/dashpay-profile/quorum_pubkey.hex b/packages/rs-drive-proof-verifier/tests/vectors/dashpay-profile/quorum_pubkey.hex new file mode 100644 index 00000000000..a1912bdde28 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/dashpay-profile/quorum_pubkey.hex @@ -0,0 +1 @@ +b6087e2054b847ec64a1e18af3930d39fb040b73eb8a10620f9adcb1be85bf7d5ea961dc2458d601ba9003b1e39ead15 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/dashpay-profile/signature.hex b/packages/rs-drive-proof-verifier/tests/vectors/dashpay-profile/signature.hex new file mode 100644 index 00000000000..0ca209f79f3 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/dashpay-profile/signature.hex @@ -0,0 +1 @@ +a4fca3d223938deeb9da82d0021a2cfb8cd7463412f7613c8943cd86a4f26b9aa81daf9d218c310ed3bb9e9c6a80b38118d16d27ff981dcc7ca46a65c95be36036eb0e1c4bc31801d2aa5699fc3d9932295f375bec3073e03c4279668429d319 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-exact/manifest.json b/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-exact/manifest.json new file mode 100644 index 00000000000..6dcd1bb8c90 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-exact/manifest.json @@ -0,0 +1,34 @@ +{ + "description": "DPNS domain-by-exact-label query proof (label 'alice'); grovedb layer verifies, placeholder document payload must fail decoding cleanly.", + "source": { + "platform_repo_tag": "v4.0.0", + "grovedb_repo_tag": "v5.0.0", + "generated_protocol_version": 12 + }, + "request": { + "type": "documents_dpns_exact", + "normalized_label": "alice", + "limit": 1 + }, + "block": { + "height": 123456, + "core_chain_locked_height": 2000000, + "epoch": 0, + "time_ms": 1700000000000, + "protocol_version": 12, + "chain_id": "dash-testnet-51" + }, + "proof_meta": { + "round": 0, + "quorum_type": 106, + "quorum_hash_hex": "01080f161d242b323940474e555c636a71787f868d949ba2a9b0b7bec5ccd3da", + "block_id_hash_hex": "090c0f1215181b1e2124272a2d303336393c3f4245484b4e5154575a5d606366" + }, + "expected": { + "kind": "documents_placeholder", + "serialized_documents": [ + "70726f7665642d64706e732d646f63756d656e74" + ] + }, + "expected_root_hash_hex": "dad905d8fddd7a31089ed57521ff006ec5946b5648d48056bce493357675ab72" +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-exact/proof.hex b/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-exact/proof.hex new file mode 100644 index 00000000000..c857a730a41 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-exact/proof.hex @@ -0,0 +1 @@ +0100d101039118e921c386a7a9c166dbad8a7df9b87fa7f3dc8e3bd4fb42e124cffaa65a02cc9a023abb3efe685ac357116032ee5eb34884d6c3e5861ea7ac662ab511f237100401400024020120e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c5315500fbda163cb3ac4d5ca76ccab587620f53bdcbe46a96dbcb1e0ed411ace9395b2202dae5ae1465037089786f368eee27aa0437d77fbaf34d14dd299aae3d6a54168b1001f61ef78f4632c6b8cb48fd3087644cf1775a597afa62b67660943fccfabd887b1111010140006b013af9b5c483d29ba0cb144b3c8d0b00acb6894c2ba54526ee525ecba262f25bbe0420e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c53155000502010101005dfffca61718377c8e28755c8c4c41cd3281e43700cc17ef2fb2ce858f8d9e08100120e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c53155002f040101000a020106646f6d61696e00aef97d6723e7dfdd1a37d4051a65d1851a7183ee391f51b154add1042479806001010100480406646f6d61696e001e02011a6e6f726d616c697a6564506172656e74446f6d61696e4e616d6500c0db47fafbb7b914aca5112d697ebb013ac3f9de326d8135d68029a191e89cb20106646f6d61696e008a01bb6f7c477bd80200888c4db39eee8829d38f1ab953cc25c13f82c05fc5b25f32041a6e6f726d616c697a6564506172656e74446f6d61696e4e616d6500080201046461736800aeb4ddee9352a25186598ca471577e45325bd9cf1b02c80bb31d03ab58ba336810014fd3d5c7b045c62f2ac81c9f51f067a4450901d41999b0f82a3f15b103df4a6a11011a6e6f726d616c697a6564506172656e74446f6d61696e4e616d65003b040464617368001302010f6e6f726d616c697a65644c6162656c000127fd05259b354ce1f58158158364d18a5a6c9f07227e9170a8ebda0e5e7fa3010464617368003c040f6e6f726d616c697a65644c6162656c0009020105616c696365001e7beb5cde43e295777634dc595f1536f62e2885343dca251fd9c3551285b8f6010f6e6f726d616c697a65644c6162656c002e0405616c69636500050201010000ecb69a79bd697e495ef181171cb50b0443bdc72b78e3c0446e75ae9f68ffeb2c0105616c696365003c0601000017001470726f7665642d64706e732d646f63756d656e7400a711904e44b1b6aec95a008065047732ea534162d3e3e0934617a6faa218739500 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-exact/quorum_pubkey.hex b/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-exact/quorum_pubkey.hex new file mode 100644 index 00000000000..a1912bdde28 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-exact/quorum_pubkey.hex @@ -0,0 +1 @@ +b6087e2054b847ec64a1e18af3930d39fb040b73eb8a10620f9adcb1be85bf7d5ea961dc2458d601ba9003b1e39ead15 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-exact/signature.hex b/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-exact/signature.hex new file mode 100644 index 00000000000..0ca209f79f3 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-exact/signature.hex @@ -0,0 +1 @@ +a4fca3d223938deeb9da82d0021a2cfb8cd7463412f7613c8943cd86a4f26b9aa81daf9d218c310ed3bb9e9c6a80b38118d16d27ff981dcc7ca46a65c95be36036eb0e1c4bc31801d2aa5699fc3d9932295f375bec3073e03c4279668429d319 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-prefix/manifest.json b/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-prefix/manifest.json new file mode 100644 index 00000000000..f84480e2ed7 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-prefix/manifest.json @@ -0,0 +1,34 @@ +{ + "description": "DPNS domain-by-prefix query proof (prefix 'ali', limit 25); grovedb layer verifies, placeholder document payload must fail decoding cleanly.", + "source": { + "platform_repo_tag": "v4.0.0", + "grovedb_repo_tag": "v5.0.0", + "generated_protocol_version": 12 + }, + "request": { + "type": "documents_dpns_prefix", + "normalized_prefix": "ali", + "limit": 25 + }, + "block": { + "height": 123456, + "core_chain_locked_height": 2000000, + "epoch": 0, + "time_ms": 1700000000000, + "protocol_version": 12, + "chain_id": "dash-testnet-51" + }, + "proof_meta": { + "round": 0, + "quorum_type": 106, + "quorum_hash_hex": "01080f161d242b323940474e555c636a71787f868d949ba2a9b0b7bec5ccd3da", + "block_id_hash_hex": "090c0f1215181b1e2124272a2d303336393c3f4245484b4e5154575a5d606366" + }, + "expected": { + "kind": "documents_placeholder", + "serialized_documents": [ + "70726f7665642d64706e732d646f63756d656e74" + ] + }, + "expected_root_hash_hex": "dad905d8fddd7a31089ed57521ff006ec5946b5648d48056bce493357675ab72" +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-prefix/proof.hex b/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-prefix/proof.hex new file mode 100644 index 00000000000..c857a730a41 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-prefix/proof.hex @@ -0,0 +1 @@ +0100d101039118e921c386a7a9c166dbad8a7df9b87fa7f3dc8e3bd4fb42e124cffaa65a02cc9a023abb3efe685ac357116032ee5eb34884d6c3e5861ea7ac662ab511f237100401400024020120e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c5315500fbda163cb3ac4d5ca76ccab587620f53bdcbe46a96dbcb1e0ed411ace9395b2202dae5ae1465037089786f368eee27aa0437d77fbaf34d14dd299aae3d6a54168b1001f61ef78f4632c6b8cb48fd3087644cf1775a597afa62b67660943fccfabd887b1111010140006b013af9b5c483d29ba0cb144b3c8d0b00acb6894c2ba54526ee525ecba262f25bbe0420e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c53155000502010101005dfffca61718377c8e28755c8c4c41cd3281e43700cc17ef2fb2ce858f8d9e08100120e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c53155002f040101000a020106646f6d61696e00aef97d6723e7dfdd1a37d4051a65d1851a7183ee391f51b154add1042479806001010100480406646f6d61696e001e02011a6e6f726d616c697a6564506172656e74446f6d61696e4e616d6500c0db47fafbb7b914aca5112d697ebb013ac3f9de326d8135d68029a191e89cb20106646f6d61696e008a01bb6f7c477bd80200888c4db39eee8829d38f1ab953cc25c13f82c05fc5b25f32041a6e6f726d616c697a6564506172656e74446f6d61696e4e616d6500080201046461736800aeb4ddee9352a25186598ca471577e45325bd9cf1b02c80bb31d03ab58ba336810014fd3d5c7b045c62f2ac81c9f51f067a4450901d41999b0f82a3f15b103df4a6a11011a6e6f726d616c697a6564506172656e74446f6d61696e4e616d65003b040464617368001302010f6e6f726d616c697a65644c6162656c000127fd05259b354ce1f58158158364d18a5a6c9f07227e9170a8ebda0e5e7fa3010464617368003c040f6e6f726d616c697a65644c6162656c0009020105616c696365001e7beb5cde43e295777634dc595f1536f62e2885343dca251fd9c3551285b8f6010f6e6f726d616c697a65644c6162656c002e0405616c69636500050201010000ecb69a79bd697e495ef181171cb50b0443bdc72b78e3c0446e75ae9f68ffeb2c0105616c696365003c0601000017001470726f7665642d64706e732d646f63756d656e7400a711904e44b1b6aec95a008065047732ea534162d3e3e0934617a6faa218739500 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-prefix/quorum_pubkey.hex b/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-prefix/quorum_pubkey.hex new file mode 100644 index 00000000000..a1912bdde28 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-prefix/quorum_pubkey.hex @@ -0,0 +1 @@ +b6087e2054b847ec64a1e18af3930d39fb040b73eb8a10620f9adcb1be85bf7d5ea961dc2458d601ba9003b1e39ead15 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-prefix/signature.hex b/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-prefix/signature.hex new file mode 100644 index 00000000000..0ca209f79f3 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/dpns-domain-prefix/signature.hex @@ -0,0 +1 @@ +a4fca3d223938deeb9da82d0021a2cfb8cd7463412f7613c8943cd86a4f26b9aa81daf9d218c310ed3bb9e9c6a80b38118d16d27ff981dcc7ca46a65c95be36036eb0e1c4bc31801d2aa5699fc3d9932295f375bec3073e03c4279668429d319 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-balance-corrupted-proof/manifest.json b/packages/rs-drive-proof-verifier/tests/vectors/identity-balance-corrupted-proof/manifest.json new file mode 100644 index 00000000000..0cbd1fb8d0f --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-balance-corrupted-proof/manifest.json @@ -0,0 +1,30 @@ +{ + "description": "Identity balance proof with one bit flipped mid-stream; grovedb verification must fail with a clean error (no panic), and any surviving root hash cannot match the signed app hash.", + "source": { + "platform_repo_tag": "v4.0.0", + "grovedb_repo_tag": "v5.0.0", + "generated_protocol_version": 12 + }, + "request": { + "type": "identity_balance", + "identity_id": "7777777777777777777777777777777777777777777777777777777777777777" + }, + "block": { + "height": 123456, + "core_chain_locked_height": 2000000, + "epoch": 0, + "time_ms": 1700000000000, + "protocol_version": 12, + "chain_id": "dash-testnet-51" + }, + "proof_meta": { + "round": 0, + "quorum_type": 106, + "quorum_hash_hex": "01080f161d242b323940474e555c636a71787f868d949ba2a9b0b7bec5ccd3da", + "block_id_hash_hex": "090c0f1215181b1e2124272a2d303336393c3f4245484b4e5154575a5d606366" + }, + "expected": { + "kind": "error", + "class": "proof_invalid" + } +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-balance-corrupted-proof/proof.hex b/packages/rs-drive-proof-verifier/tests/vectors/identity-balance-corrupted-proof/proof.hex new file mode 100644 index 00000000000..34afee48bc6 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-balance-corrupted-proof/proof.hex @@ -0,0 +1 @@ +0100da01039118e921c386a7a9c166dbad8a7df9b87fa7f3dc8e3bd4fb42e124cffaa65a02cc9a023abb3efe685ac357116032ee5eb34884d6c3e5861ea7ac662ab511f2371001282192d9f288b3dd8ceeba34fda695ec21d080458ed5d9503eb5916a63494a7a040160002d0401207777777777777777777777777777777777777777777777777777767777777777fd00000002540be400006ab14e39df7d262e55bae17e60bab5d996cb66d6ded567f4d445ba536eef3b931001f61ef78f4632c6b8cb48fd3087644cf1775a597afa62b67660943fccfabd887b1111010160002f03207777777777777777777777777777777777777777777777777777777777777777000b03fd00000002540be4000000 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-balance-corrupted-proof/quorum_pubkey.hex b/packages/rs-drive-proof-verifier/tests/vectors/identity-balance-corrupted-proof/quorum_pubkey.hex new file mode 100644 index 00000000000..a1912bdde28 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-balance-corrupted-proof/quorum_pubkey.hex @@ -0,0 +1 @@ +b6087e2054b847ec64a1e18af3930d39fb040b73eb8a10620f9adcb1be85bf7d5ea961dc2458d601ba9003b1e39ead15 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-balance-corrupted-proof/signature.hex b/packages/rs-drive-proof-verifier/tests/vectors/identity-balance-corrupted-proof/signature.hex new file mode 100644 index 00000000000..0ca209f79f3 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-balance-corrupted-proof/signature.hex @@ -0,0 +1 @@ +a4fca3d223938deeb9da82d0021a2cfb8cd7463412f7613c8943cd86a4f26b9aa81daf9d218c310ed3bb9e9c6a80b38118d16d27ff981dcc7ca46a65c95be36036eb0e1c4bc31801d2aa5699fc3d9932295f375bec3073e03c4279668429d319 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-balance/manifest.json b/packages/rs-drive-proof-verifier/tests/vectors/identity-balance/manifest.json new file mode 100644 index 00000000000..3daf42e7b0e --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-balance/manifest.json @@ -0,0 +1,31 @@ +{ + "description": "Balance proof for the fixture identity; positive end-to-end verification.", + "source": { + "platform_repo_tag": "v4.0.0", + "grovedb_repo_tag": "v5.0.0", + "generated_protocol_version": 12 + }, + "request": { + "type": "identity_balance", + "identity_id": "7777777777777777777777777777777777777777777777777777777777777777" + }, + "block": { + "height": 123456, + "core_chain_locked_height": 2000000, + "epoch": 0, + "time_ms": 1700000000000, + "protocol_version": 12, + "chain_id": "dash-testnet-51" + }, + "proof_meta": { + "round": 0, + "quorum_type": 106, + "quorum_hash_hex": "01080f161d242b323940474e555c636a71787f868d949ba2a9b0b7bec5ccd3da", + "block_id_hash_hex": "090c0f1215181b1e2124272a2d303336393c3f4245484b4e5154575a5d606366" + }, + "expected": { + "kind": "identity_balance", + "balance": 5000000000 + }, + "expected_root_hash_hex": "dad905d8fddd7a31089ed57521ff006ec5946b5648d48056bce493357675ab72" +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-balance/proof.hex b/packages/rs-drive-proof-verifier/tests/vectors/identity-balance/proof.hex new file mode 100644 index 00000000000..255f940a0c5 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-balance/proof.hex @@ -0,0 +1 @@ +0100da01039118e921c386a7a9c166dbad8a7df9b87fa7f3dc8e3bd4fb42e124cffaa65a02cc9a023abb3efe685ac357116032ee5eb34884d6c3e5861ea7ac662ab511f2371001282192d9f288b3dd8ceeba34fda695ec21d080458ed5d9503eb5916a63494a7a040160002d0401207777777777777777777777777777777777777777777777777777777777777777fd00000002540be400006ab14e39df7d262e55bae17e60bab5d996cb66d6ded567f4d445ba536eef3b931001f61ef78f4632c6b8cb48fd3087644cf1775a597afa62b67660943fccfabd887b1111010160002f03207777777777777777777777777777777777777777777777777777777777777777000b03fd00000002540be4000000 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-balance/quorum_pubkey.hex b/packages/rs-drive-proof-verifier/tests/vectors/identity-balance/quorum_pubkey.hex new file mode 100644 index 00000000000..a1912bdde28 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-balance/quorum_pubkey.hex @@ -0,0 +1 @@ +b6087e2054b847ec64a1e18af3930d39fb040b73eb8a10620f9adcb1be85bf7d5ea961dc2458d601ba9003b1e39ead15 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-balance/signature.hex b/packages/rs-drive-proof-verifier/tests/vectors/identity-balance/signature.hex new file mode 100644 index 00000000000..0ca209f79f3 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-balance/signature.hex @@ -0,0 +1 @@ +a4fca3d223938deeb9da82d0021a2cfb8cd7463412f7613c8943cd86a4f26b9aa81daf9d218c310ed3bb9e9c6a80b38118d16d27ff981dcc7ca46a65c95be36036eb0e1c4bc31801d2aa5699fc3d9932295f375bec3073e03c4279668429d319 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-contract-nonce/manifest.json b/packages/rs-drive-proof-verifier/tests/vectors/identity-contract-nonce/manifest.json new file mode 100644 index 00000000000..ee623fa84ed --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-contract-nonce/manifest.json @@ -0,0 +1,32 @@ +{ + "description": "Identity contract nonce proof against the DPNS contract; positive.", + "source": { + "platform_repo_tag": "v4.0.0", + "grovedb_repo_tag": "v5.0.0", + "generated_protocol_version": 12 + }, + "request": { + "type": "identity_contract_nonce", + "identity_id": "7777777777777777777777777777777777777777777777777777777777777777", + "contract_id": "e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c53155" + }, + "block": { + "height": 123456, + "core_chain_locked_height": 2000000, + "epoch": 0, + "time_ms": 1700000000000, + "protocol_version": 12, + "chain_id": "dash-testnet-51" + }, + "proof_meta": { + "round": 0, + "quorum_type": 106, + "quorum_hash_hex": "01080f161d242b323940474e555c636a71787f868d949ba2a9b0b7bec5ccd3da", + "block_id_hash_hex": "090c0f1215181b1e2124272a2d303336393c3f4245484b4e5154575a5d606366" + }, + "expected": { + "kind": "identity_contract_nonce", + "nonce": 11 + }, + "expected_root_hash_hex": "dad905d8fddd7a31089ed57521ff006ec5946b5648d48056bce493357675ab72" +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-contract-nonce/proof.hex b/packages/rs-drive-proof-verifier/tests/vectors/identity-contract-nonce/proof.hex new file mode 100644 index 00000000000..8a8943d0c2e --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-contract-nonce/proof.hex @@ -0,0 +1 @@ +01008d01039118e921c386a7a9c166dbad8a7df9b87fa7f3dc8e3bd4fb42e124cffaa65a0401200024020120777777777777777777777777777777777777777777777777777777777777777700a2f8eb7d55888b059806841f7a2e92d211d65049ed09fe2bab4d1cd1f72aa0e41001eb804ecd6886810d1d7c79a0f1b6b35791037224de02c64c11ce42338455528d1101012000490420777777777777777777777777777777777777777777777777777777777777777700050201018000aee59dc5acac5fe8d4b452c1fd0f22601b6c1d876e28d0e3512a2ff39d18bcee0120777777777777777777777777777777777777777777777777777777777777777700af0401200024020120e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c53155008b708962e5e42245c8220f3a06dbcc9ba3a7e655df4fed3dba6e8cff9426f43d024e6a60642818a48d5f2e7c3647a08b69f48d05941c95aaa24536b810b3c49b681002cbeddd5e01bcb90c5002f6a710bc7957af406d2a6a9df600dbfa36951abf3534100185d286a688ac17d96cdb2880a8f7174e151dfb90742370effeeaae391ee359df1101012000490420e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c5315500050201010000411ce8bb44ce6a4f4169880f3111dbad167ccd51ab08199b006247e83b1fd1510120e668c659af66aee1e72c186dde7b5b7e0a1d712a09c40d5721f622bf53c531550010030100000b0008000000000000000b0000 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-contract-nonce/quorum_pubkey.hex b/packages/rs-drive-proof-verifier/tests/vectors/identity-contract-nonce/quorum_pubkey.hex new file mode 100644 index 00000000000..a1912bdde28 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-contract-nonce/quorum_pubkey.hex @@ -0,0 +1 @@ +b6087e2054b847ec64a1e18af3930d39fb040b73eb8a10620f9adcb1be85bf7d5ea961dc2458d601ba9003b1e39ead15 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-contract-nonce/signature.hex b/packages/rs-drive-proof-verifier/tests/vectors/identity-contract-nonce/signature.hex new file mode 100644 index 00000000000..0ca209f79f3 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-contract-nonce/signature.hex @@ -0,0 +1 @@ +a4fca3d223938deeb9da82d0021a2cfb8cd7463412f7613c8943cd86a4f26b9aa81daf9d218c310ed3bb9e9c6a80b38118d16d27ff981dcc7ca46a65c95be36036eb0e1c4bc31801d2aa5699fc3d9932295f375bec3073e03c4279668429d319 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-keys/manifest.json b/packages/rs-drive-proof-verifier/tests/vectors/identity-keys/manifest.json new file mode 100644 index 00000000000..f3d066a6de2 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-keys/manifest.json @@ -0,0 +1,35 @@ +{ + "description": "All-keys proof for the fixture identity; keys compared byte-for-byte.", + "source": { + "platform_repo_tag": "v4.0.0", + "grovedb_repo_tag": "v5.0.0", + "generated_protocol_version": 12 + }, + "request": { + "type": "identity_keys", + "identity_id": "7777777777777777777777777777777777777777777777777777777777777777" + }, + "block": { + "height": 123456, + "core_chain_locked_height": 2000000, + "epoch": 0, + "time_ms": 1700000000000, + "protocol_version": 12, + "chain_id": "dash-testnet-51" + }, + "proof_meta": { + "round": 0, + "quorum_type": 106, + "quorum_hash_hex": "01080f161d242b323940474e555c636a71787f868d949ba2a9b0b7bec5ccd3da", + "block_id_hash_hex": "090c0f1215181b1e2124272a2d303336393c3f4245484b4e5154575a5d606366" + }, + "expected": { + "kind": "identity_keys", + "serialized_keys": [ + "0000000000000021034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa00", + "000100020000002102466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f2700", + "0002010300000021035ab4689e400a4a160cf01cd44730845a54768df8547dcdf073d964f109f18c3001fd0000018bcfe5687b" + ] + }, + "expected_root_hash_hex": "dad905d8fddd7a31089ed57521ff006ec5946b5648d48056bce493357675ab72" +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-keys/proof.hex b/packages/rs-drive-proof-verifier/tests/vectors/identity-keys/proof.hex new file mode 100644 index 00000000000..8a623ed819b --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-keys/proof.hex @@ -0,0 +1 @@ +01008d01039118e921c386a7a9c166dbad8a7df9b87fa7f3dc8e3bd4fb42e124cffaa65a0401200024020120777777777777777777777777777777777777777777777777777777777777777700a2f8eb7d55888b059806841f7a2e92d211d65049ed09fe2bab4d1cd1f72aa0e41001eb804ecd6886810d1d7c79a0f1b6b35791037224de02c64c11ce42338455528d1101012000490420777777777777777777777777777777777777777777777777777777777777777700050201018000aee59dc5acac5fe8d4b452c1fd0f22601b6c1d876e28d0e3512a2ff39d18bcee01207777777777777777777777777777777777777777777777777777777777777777006e017b204423f6e41b597890ac921d8f72453128cad7e268750f6fc87d648bcc72aa04018000050201010100d8e4a96433656c05d1cfef00c047f123db4140e64fd3e509993825149a64a5d0100185d286a688ac17d96cdb2880a8f7174e151dfb90742370effeeaae391ee359df1101018000a1030100002d002a0000000000000021034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa0000030101002d002a000100020000002102466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f27000010030102003600330002010300000021035ab4689e400a4a160cf01cd44730845a54768df8547dcdf073d964f109f18c3001fd0000018bcfe5687b001100 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-keys/quorum_pubkey.hex b/packages/rs-drive-proof-verifier/tests/vectors/identity-keys/quorum_pubkey.hex new file mode 100644 index 00000000000..a1912bdde28 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-keys/quorum_pubkey.hex @@ -0,0 +1 @@ +b6087e2054b847ec64a1e18af3930d39fb040b73eb8a10620f9adcb1be85bf7d5ea961dc2458d601ba9003b1e39ead15 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-keys/signature.hex b/packages/rs-drive-proof-verifier/tests/vectors/identity-keys/signature.hex new file mode 100644 index 00000000000..0ca209f79f3 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-keys/signature.hex @@ -0,0 +1 @@ +a4fca3d223938deeb9da82d0021a2cfb8cd7463412f7613c8943cd86a4f26b9aa81daf9d218c310ed3bb9e9c6a80b38118d16d27ff981dcc7ca46a65c95be36036eb0e1c4bc31801d2aa5699fc3d9932295f375bec3073e03c4279668429d319 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-nonce/manifest.json b/packages/rs-drive-proof-verifier/tests/vectors/identity-nonce/manifest.json new file mode 100644 index 00000000000..4930c4ee341 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-nonce/manifest.json @@ -0,0 +1,31 @@ +{ + "description": "Identity nonce proof; positive end-to-end verification.", + "source": { + "platform_repo_tag": "v4.0.0", + "grovedb_repo_tag": "v5.0.0", + "generated_protocol_version": 12 + }, + "request": { + "type": "identity_nonce", + "identity_id": "7777777777777777777777777777777777777777777777777777777777777777" + }, + "block": { + "height": 123456, + "core_chain_locked_height": 2000000, + "epoch": 0, + "time_ms": 1700000000000, + "protocol_version": 12, + "chain_id": "dash-testnet-51" + }, + "proof_meta": { + "round": 0, + "quorum_type": 106, + "quorum_hash_hex": "01080f161d242b323940474e555c636a71787f868d949ba2a9b0b7bec5ccd3da", + "block_id_hash_hex": "090c0f1215181b1e2124272a2d303336393c3f4245484b4e5154575a5d606366" + }, + "expected": { + "kind": "identity_nonce", + "nonce": 7 + }, + "expected_root_hash_hex": "dad905d8fddd7a31089ed57521ff006ec5946b5648d48056bce493357675ab72" +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-nonce/proof.hex b/packages/rs-drive-proof-verifier/tests/vectors/identity-nonce/proof.hex new file mode 100644 index 00000000000..78436a05fef --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-nonce/proof.hex @@ -0,0 +1 @@ +01008d01039118e921c386a7a9c166dbad8a7df9b87fa7f3dc8e3bd4fb42e124cffaa65a0401200024020120777777777777777777777777777777777777777777777777777777777777777700a2f8eb7d55888b059806841f7a2e92d211d65049ed09fe2bab4d1cd1f72aa0e41001eb804ecd6886810d1d7c79a0f1b6b35791037224de02c64c11ce42338455528d1101012000490420777777777777777777777777777777777777777777777777777777777777777700050201018000aee59dc5acac5fe8d4b452c1fd0f22601b6c1d876e28d0e3512a2ff39d18bcee01207777777777777777777777777777777777777777777777777777777777777777007601b44b3a90d97444a14074c2bf69ff971d88fd27e3ba2da8b11cf3910f087dedf6030140000b00080000000000000007001002cbeddd5e01bcb90c5002f6a710bc7957af406d2a6a9df600dbfa36951abf3534100185d286a688ac17d96cdb2880a8f7174e151dfb90742370effeeaae391ee359df1100 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-nonce/quorum_pubkey.hex b/packages/rs-drive-proof-verifier/tests/vectors/identity-nonce/quorum_pubkey.hex new file mode 100644 index 00000000000..a1912bdde28 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-nonce/quorum_pubkey.hex @@ -0,0 +1 @@ +b6087e2054b847ec64a1e18af3930d39fb040b73eb8a10620f9adcb1be85bf7d5ea961dc2458d601ba9003b1e39ead15 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/identity-nonce/signature.hex b/packages/rs-drive-proof-verifier/tests/vectors/identity-nonce/signature.hex new file mode 100644 index 00000000000..0ca209f79f3 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/identity-nonce/signature.hex @@ -0,0 +1 @@ +a4fca3d223938deeb9da82d0021a2cfb8cd7463412f7613c8943cd86a4f26b9aa81daf9d218c310ed3bb9e9c6a80b38118d16d27ff981dcc7ca46a65c95be36036eb0e1c4bc31801d2aa5699fc3d9932295f375bec3073e03c4279668429d319 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-tampered-signature/manifest.json b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-tampered-signature/manifest.json new file mode 100644 index 00000000000..2198d5ccc35 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-tampered-signature/manifest.json @@ -0,0 +1,30 @@ +{ + "description": "One bit flipped in the BLS signature; verification must fail with an invalid-signature error.", + "source": { + "platform_repo_tag": "v4.0.0", + "grovedb_repo_tag": "v5.0.0", + "generated_protocol_version": 12 + }, + "request": { + "type": "identity_balance", + "identity_id": "7777777777777777777777777777777777777777777777777777777777777777" + }, + "block": { + "height": 123456, + "core_chain_locked_height": 2000000, + "epoch": 0, + "time_ms": 1700000000000, + "protocol_version": 12, + "chain_id": "dash-testnet-51" + }, + "proof_meta": { + "round": 0, + "quorum_type": 106, + "quorum_hash_hex": "01080f161d242b323940474e555c636a71787f868d949ba2a9b0b7bec5ccd3da", + "block_id_hash_hex": "090c0f1215181b1e2124272a2d303336393c3f4245484b4e5154575a5d606366" + }, + "expected": { + "kind": "error", + "class": "invalid_signature" + } +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-tampered-signature/proof.hex b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-tampered-signature/proof.hex new file mode 100644 index 00000000000..255f940a0c5 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-tampered-signature/proof.hex @@ -0,0 +1 @@ +0100da01039118e921c386a7a9c166dbad8a7df9b87fa7f3dc8e3bd4fb42e124cffaa65a02cc9a023abb3efe685ac357116032ee5eb34884d6c3e5861ea7ac662ab511f2371001282192d9f288b3dd8ceeba34fda695ec21d080458ed5d9503eb5916a63494a7a040160002d0401207777777777777777777777777777777777777777777777777777777777777777fd00000002540be400006ab14e39df7d262e55bae17e60bab5d996cb66d6ded567f4d445ba536eef3b931001f61ef78f4632c6b8cb48fd3087644cf1775a597afa62b67660943fccfabd887b1111010160002f03207777777777777777777777777777777777777777777777777777777777777777000b03fd00000002540be4000000 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-tampered-signature/quorum_pubkey.hex b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-tampered-signature/quorum_pubkey.hex new file mode 100644 index 00000000000..a1912bdde28 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-tampered-signature/quorum_pubkey.hex @@ -0,0 +1 @@ +b6087e2054b847ec64a1e18af3930d39fb040b73eb8a10620f9adcb1be85bf7d5ea961dc2458d601ba9003b1e39ead15 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-tampered-signature/signature.hex b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-tampered-signature/signature.hex new file mode 100644 index 00000000000..e22b25531cb --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-tampered-signature/signature.hex @@ -0,0 +1 @@ +a4fca3d223938deeb9da83d0021a2cfb8cd7463412f7613c8943cd86a4f26b9aa81daf9d218c310ed3bb9e9c6a80b38118d16d27ff981dcc7ca46a65c95be36036eb0e1c4bc31801d2aa5699fc3d9932295f375bec3073e03c4279668429d319 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-valid/manifest.json b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-valid/manifest.json new file mode 100644 index 00000000000..54af7a37e8b --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-valid/manifest.json @@ -0,0 +1,31 @@ +{ + "description": "Envelope grovedb proof with a valid quorum signature; full tenderdash verification must pass.", + "source": { + "platform_repo_tag": "v4.0.0", + "grovedb_repo_tag": "v5.0.0", + "generated_protocol_version": 12 + }, + "request": { + "type": "identity_balance", + "identity_id": "7777777777777777777777777777777777777777777777777777777777777777" + }, + "block": { + "height": 123456, + "core_chain_locked_height": 2000000, + "epoch": 0, + "time_ms": 1700000000000, + "protocol_version": 12, + "chain_id": "dash-testnet-51" + }, + "proof_meta": { + "round": 0, + "quorum_type": 106, + "quorum_hash_hex": "01080f161d242b323940474e555c636a71787f868d949ba2a9b0b7bec5ccd3da", + "block_id_hash_hex": "090c0f1215181b1e2124272a2d303336393c3f4245484b4e5154575a5d606366" + }, + "expected": { + "kind": "identity_balance", + "balance": 5000000000 + }, + "expected_root_hash_hex": "dad905d8fddd7a31089ed57521ff006ec5946b5648d48056bce493357675ab72" +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-valid/proof.hex b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-valid/proof.hex new file mode 100644 index 00000000000..255f940a0c5 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-valid/proof.hex @@ -0,0 +1 @@ +0100da01039118e921c386a7a9c166dbad8a7df9b87fa7f3dc8e3bd4fb42e124cffaa65a02cc9a023abb3efe685ac357116032ee5eb34884d6c3e5861ea7ac662ab511f2371001282192d9f288b3dd8ceeba34fda695ec21d080458ed5d9503eb5916a63494a7a040160002d0401207777777777777777777777777777777777777777777777777777777777777777fd00000002540be400006ab14e39df7d262e55bae17e60bab5d996cb66d6ded567f4d445ba536eef3b931001f61ef78f4632c6b8cb48fd3087644cf1775a597afa62b67660943fccfabd887b1111010160002f03207777777777777777777777777777777777777777777777777777777777777777000b03fd00000002540be4000000 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-valid/quorum_pubkey.hex b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-valid/quorum_pubkey.hex new file mode 100644 index 00000000000..a1912bdde28 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-valid/quorum_pubkey.hex @@ -0,0 +1 @@ +b6087e2054b847ec64a1e18af3930d39fb040b73eb8a10620f9adcb1be85bf7d5ea961dc2458d601ba9003b1e39ead15 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-valid/signature.hex b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-valid/signature.hex new file mode 100644 index 00000000000..0ca209f79f3 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-valid/signature.hex @@ -0,0 +1 @@ +a4fca3d223938deeb9da82d0021a2cfb8cd7463412f7613c8943cd86a4f26b9aa81daf9d218c310ed3bb9e9c6a80b38118d16d27ff981dcc7ca46a65c95be36036eb0e1c4bc31801d2aa5699fc3d9932295f375bec3073e03c4279668429d319 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-block-id-hash/manifest.json b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-block-id-hash/manifest.json new file mode 100644 index 00000000000..3b49b649f4b --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-block-id-hash/manifest.json @@ -0,0 +1,30 @@ +{ + "description": "Proof metadata carries a block id hash the quorum never signed; must fail with an invalid-signature error.", + "source": { + "platform_repo_tag": "v4.0.0", + "grovedb_repo_tag": "v5.0.0", + "generated_protocol_version": 12 + }, + "request": { + "type": "identity_balance", + "identity_id": "7777777777777777777777777777777777777777777777777777777777777777" + }, + "block": { + "height": 123456, + "core_chain_locked_height": 2000000, + "epoch": 0, + "time_ms": 1700000000000, + "protocol_version": 12, + "chain_id": "dash-testnet-51" + }, + "proof_meta": { + "round": 0, + "quorum_type": 106, + "quorum_hash_hex": "01080f161d242b323940474e555c636a71787f868d949ba2a9b0b7bec5ccd3da", + "block_id_hash_hex": "090c0f1215171b1e2124272a2d303336393c3f4245484b4e5154575a5d606366" + }, + "expected": { + "kind": "error", + "class": "invalid_signature" + } +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-block-id-hash/proof.hex b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-block-id-hash/proof.hex new file mode 100644 index 00000000000..255f940a0c5 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-block-id-hash/proof.hex @@ -0,0 +1 @@ +0100da01039118e921c386a7a9c166dbad8a7df9b87fa7f3dc8e3bd4fb42e124cffaa65a02cc9a023abb3efe685ac357116032ee5eb34884d6c3e5861ea7ac662ab511f2371001282192d9f288b3dd8ceeba34fda695ec21d080458ed5d9503eb5916a63494a7a040160002d0401207777777777777777777777777777777777777777777777777777777777777777fd00000002540be400006ab14e39df7d262e55bae17e60bab5d996cb66d6ded567f4d445ba536eef3b931001f61ef78f4632c6b8cb48fd3087644cf1775a597afa62b67660943fccfabd887b1111010160002f03207777777777777777777777777777777777777777777777777777777777777777000b03fd00000002540be4000000 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-block-id-hash/quorum_pubkey.hex b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-block-id-hash/quorum_pubkey.hex new file mode 100644 index 00000000000..a1912bdde28 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-block-id-hash/quorum_pubkey.hex @@ -0,0 +1 @@ +b6087e2054b847ec64a1e18af3930d39fb040b73eb8a10620f9adcb1be85bf7d5ea961dc2458d601ba9003b1e39ead15 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-block-id-hash/signature.hex b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-block-id-hash/signature.hex new file mode 100644 index 00000000000..0ca209f79f3 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-block-id-hash/signature.hex @@ -0,0 +1 @@ +a4fca3d223938deeb9da82d0021a2cfb8cd7463412f7613c8943cd86a4f26b9aa81daf9d218c310ed3bb9e9c6a80b38118d16d27ff981dcc7ca46a65c95be36036eb0e1c4bc31801d2aa5699fc3d9932295f375bec3073e03c4279668429d319 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-quorum-key/manifest.json b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-quorum-key/manifest.json new file mode 100644 index 00000000000..af9c549bde3 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-quorum-key/manifest.json @@ -0,0 +1,30 @@ +{ + "description": "Valid signature checked against a different quorum's public key; must fail with an invalid-signature error.", + "source": { + "platform_repo_tag": "v4.0.0", + "grovedb_repo_tag": "v5.0.0", + "generated_protocol_version": 12 + }, + "request": { + "type": "identity_balance", + "identity_id": "7777777777777777777777777777777777777777777777777777777777777777" + }, + "block": { + "height": 123456, + "core_chain_locked_height": 2000000, + "epoch": 0, + "time_ms": 1700000000000, + "protocol_version": 12, + "chain_id": "dash-testnet-51" + }, + "proof_meta": { + "round": 0, + "quorum_type": 106, + "quorum_hash_hex": "01080f161d242b323940474e555c636a71787f868d949ba2a9b0b7bec5ccd3da", + "block_id_hash_hex": "090c0f1215181b1e2124272a2d303336393c3f4245484b4e5154575a5d606366" + }, + "expected": { + "kind": "error", + "class": "invalid_signature" + } +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-quorum-key/proof.hex b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-quorum-key/proof.hex new file mode 100644 index 00000000000..255f940a0c5 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-quorum-key/proof.hex @@ -0,0 +1 @@ +0100da01039118e921c386a7a9c166dbad8a7df9b87fa7f3dc8e3bd4fb42e124cffaa65a02cc9a023abb3efe685ac357116032ee5eb34884d6c3e5861ea7ac662ab511f2371001282192d9f288b3dd8ceeba34fda695ec21d080458ed5d9503eb5916a63494a7a040160002d0401207777777777777777777777777777777777777777777777777777777777777777fd00000002540be400006ab14e39df7d262e55bae17e60bab5d996cb66d6ded567f4d445ba536eef3b931001f61ef78f4632c6b8cb48fd3087644cf1775a597afa62b67660943fccfabd887b1111010160002f03207777777777777777777777777777777777777777777777777777777777777777000b03fd00000002540be4000000 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-quorum-key/quorum_pubkey.hex b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-quorum-key/quorum_pubkey.hex new file mode 100644 index 00000000000..42440c3cdbf --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-quorum-key/quorum_pubkey.hex @@ -0,0 +1 @@ +99d85ad48c7ca9ffbe49f170e444a77ca98035a446c0fe9919180860757ef0d73e8a04abb18f5b67558baed45e748100 diff --git a/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-quorum-key/signature.hex b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-quorum-key/signature.hex new file mode 100644 index 00000000000..0ca209f79f3 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors/quorum-sig-wrong-quorum-key/signature.hex @@ -0,0 +1 @@ +a4fca3d223938deeb9da82d0021a2cfb8cd7463412f7613c8943cd86a4f26b9aa81daf9d218c310ed3bb9e9c6a80b38118d16d27ff981dcc7ca46a65c95be36036eb0e1c4bc31801d2aa5699fc3d9932295f375bec3073e03c4279668429d319 diff --git a/packages/rs-drive-proof-verifier/tests/vectors_contested.rs b/packages/rs-drive-proof-verifier/tests/vectors_contested.rs new file mode 100644 index 00000000000..d812d4dc183 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors_contested.rs @@ -0,0 +1,177 @@ +//! Contested-resource (DPNS name contest) proof-vector regression tests: +//! an active contest, a finished contest with a winner, and proof of +//! absence. Requests are built through [`TryFromRequest::try_to_request`] +//! so the gRPC round-trip the SDK relies on is exercised too. + +#![cfg(feature = "mocks")] + +mod common; + +use common::{identifier, load_case, Case, Expected, RequestSpec, NETWORK}; +use dapi_grpc::platform::v0::{self as platform, get_contested_resource_vote_state_response}; +use dpp::platform_value::Value; +use dpp::voting::vote_info_storage::contested_document_vote_poll_winner_info::ContestedDocumentVotePollWinnerInfo; +use dpp::voting::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePoll; +use drive::query::vote_poll_vote_state_query::{ + ContestedDocumentVotePollDriveQuery, ContestedDocumentVotePollDriveQueryResultType, +}; +use drive_proof_verifier::from_request::TryFromRequest; +use drive_proof_verifier::types::Contenders; +use drive_proof_verifier::FromProof; + +fn contested_pair( + case: &Case, +) -> ( + platform::GetContestedResourceVoteStateRequest, + platform::GetContestedResourceVoteStateResponse, +) { + let RequestSpec::ContestedVoteState { + contract_id, + document_type_name, + index_name, + index_values, + count, + } = &case.manifest.request + else { + panic!("{}: expected a contested_vote_state request", case.name); + }; + let query = ContestedDocumentVotePollDriveQuery { + vote_poll: ContestedDocumentResourceVotePoll { + contract_id: identifier(contract_id), + document_type_name: document_type_name.clone(), + index_name: index_name.clone(), + index_values: index_values + .iter() + .map(|value| Value::Text(value.clone())) + .collect(), + }, + result_type: ContestedDocumentVotePollDriveQueryResultType::VoteTally, + offset: None, + limit: Some(*count), + start_at: None, + allow_include_locked_and_abstaining_vote_tally: true, + }; + let request = query + .try_to_request() + .expect("contested query must convert to a gRPC request"); + let response = platform::GetContestedResourceVoteStateResponse { + version: Some(get_contested_resource_vote_state_response::Version::V0( + get_contested_resource_vote_state_response::GetContestedResourceVoteStateResponseV0 { + metadata: Some(case.metadata()), + result: Some(get_contested_resource_vote_state_response::get_contested_resource_vote_state_response_v0::Result::Proof( + case.grpc_proof(), + )), + }, + )), + }; + (request, response) +} + +fn verify_contested(case: &Case) -> Option { + let (request, response) = contested_pair(case); + Contenders::maybe_from_proof( + request, + response, + NETWORK, + case.platform_version(), + &case.provider(), + ) + .unwrap_or_else(|e| panic!("{}: contested proof must verify: {e}", case.name)) +} + +fn assert_contenders(case: &Case, contenders: &Contenders) { + let Expected::Contested { + contenders: expected_contenders, + abstain_votes, + lock_votes, + .. + } = &case.manifest.expected + else { + panic!("{}: manifest expectation mismatch", case.name); + }; + assert_eq!( + contenders.contenders.len(), + expected_contenders.len(), + "{}: contender count", + case.name + ); + for expected in expected_contenders { + let id = identifier(&expected.identity_id); + let contender = contenders + .contenders + .get(&id) + .unwrap_or_else(|| panic!("{}: contender {} missing", case.name, expected.identity_id)); + assert_eq!( + contender.vote_tally(), + expected.votes, + "{}: votes for {}", + case.name, + expected.identity_id + ); + } + assert_eq!( + contenders.abstain_vote_tally, *abstain_votes, + "{}: abstain votes", + case.name + ); + assert_eq!( + contenders.lock_vote_tally, *lock_votes, + "{}: lock votes", + case.name + ); +} + +#[test] +fn contested_vote_state_active() { + let case = load_case("contested-vote-state-active"); + let contenders = verify_contested(&case).expect("active contest must be found"); + assert_contenders(&case, &contenders); + assert!( + contenders.winner.is_none(), + "active contest must have no winner yet" + ); +} + +#[test] +fn contested_vote_state_finished() { + let case = load_case("contested-vote-state-finished"); + let contenders = verify_contested(&case).expect("finished contest must be found"); + assert_contenders(&case, &contenders); + let Expected::Contested { + finished, + winner_identity_id, + .. + } = &case.manifest.expected + else { + panic!("manifest expectation mismatch"); + }; + assert!(*finished); + let (winner_info, finalization_block) = contenders + .winner + .as_ref() + .expect("finished contest must carry winner info"); + let expected_winner = winner_identity_id + .as_deref() + .map(identifier) + .expect("finished fixture names a winner"); + assert_eq!( + *winner_info, + ContestedDocumentVotePollWinnerInfo::WonByIdentity(expected_winner) + ); + assert!( + finalization_block.time_ms > 0, + "finalization block info must be present" + ); +} + +#[test] +fn contested_vote_state_absent() { + let case = load_case("contested-vote-state-absent"); + let Expected::ContestedAbsent = case.manifest.expected else { + panic!("manifest expectation mismatch"); + }; + assert!( + verify_contested(&case).is_none(), + "absent contest must verify as proof of non-existence (Ok(None))" + ); +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors_documents.rs b/packages/rs-drive-proof-verifier/tests/vectors_documents.rs new file mode 100644 index 00000000000..e6eb7753f3d --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors_documents.rs @@ -0,0 +1,251 @@ +//! Documents-family (DPNS / Dashpay) proof-vector regression tests. +//! +//! The fixture grovedb state stores placeholder ASCII payloads at the +//! document positions (real documents were not re-fixtured for this corpus), +//! so neither half of these vectors can run a full end-to-end positive +//! verification the way the identity/contested families do. Instead they +//! pin two narrower, still-real things: +//! +//! 1. the [`DriveDocumentQuery`] shape each DAPI query maps to still matches +//! the proof the server generated. This is checked with `drive`'s own +//! `verify_proof_keep_serialized` -- a lower-level call on the `drive` +//! dev-dependency, *not* this crate's public [`FromProof`] entry point -- +//! comparing the root hash and the recovered serialized payloads +//! byte-for-byte. A DAPI query-shape drift (wrong field name, missing +//! clause, wrong ordering) changes the query's grovedb path and fails +//! this root-hash pin. +//! 2. that this crate's real public entry point, +//! `>::maybe_from_proof_with_metadata`, +//! itself replays the same grovedb proof internally (via +//! `DriveDocumentQuery::verify_proof`) and then fails cleanly (an `Err`, +//! never a panic) once it tries to decode the placeholder payload as a +//! DPP document -- before the quorum signature is ever consulted. +//! +//! Neither half reaches the tenderdash BLS check: the placeholder payloads +//! make that unreachable here. Coverage of the signature layer itself lives +//! in `vectors_quorum_sig.rs`. + +#![cfg(feature = "mocks")] + +mod common; + +use std::collections::BTreeMap; + +use common::{hex_vec, identifier, load_case, Case, Expected, RequestSpec, NETWORK}; +use dapi_grpc::platform::v0::{self as platform, get_documents_response}; +use dpp::data_contract::accessors::v0::DataContractV0Getters; +use dpp::platform_value::Value; +use dpp::prelude::DataContract; +use dpp::system_data_contracts::{load_system_data_contract, SystemDataContract}; +use drive::query::{DriveDocumentQuery, InternalClauses, OrderClause, WhereClause, WhereOperator}; +use drive_proof_verifier::types::Documents; +use drive_proof_verifier::{Error, FromProof}; +use indexmap::IndexMap; + +fn equal_clause(field: &str, value: Value) -> (String, WhereClause) { + ( + field.to_string(), + WhereClause { + field: field.to_string(), + operator: WhereOperator::Equal, + value, + }, + ) +} + +fn asc_order(field: &str) -> IndexMap { + let mut order_by = IndexMap::new(); + order_by.insert( + field.to_string(), + OrderClause { + field: field.to_string(), + ascending: true, + }, + ); + order_by +} + +/// Builds the [`DriveDocumentQuery`] for the case, mirroring the query +/// shapes the Dash Core Platform GUI transport sends (pinned by the fixture +/// vectors). +fn document_query<'a>(case: &Case, contract: &'a DataContract) -> DriveDocumentQuery<'a> { + let (document_type_name, internal_clauses, order_by, limit) = match &case.manifest.request { + RequestSpec::DocumentsDpnsExact { + normalized_label, + limit, + } => ( + "domain", + InternalClauses { + equal_clauses: BTreeMap::from([ + equal_clause( + "normalizedParentDomainName", + Value::Text("dash".to_string()), + ), + equal_clause("normalizedLabel", Value::Text(normalized_label.to_string())), + ]), + ..Default::default() + }, + IndexMap::new(), + *limit, + ), + RequestSpec::DocumentsDpnsPrefix { + normalized_prefix, + limit, + } => ( + "domain", + InternalClauses { + equal_clauses: BTreeMap::from([equal_clause( + "normalizedParentDomainName", + Value::Text("dash".to_string()), + )]), + range_clause: Some(WhereClause { + field: "normalizedLabel".to_string(), + operator: WhereOperator::StartsWith, + value: Value::Text(normalized_prefix.to_string()), + }), + ..Default::default() + }, + asc_order("normalizedLabel"), + *limit, + ), + RequestSpec::DocumentsDashpayProfile { owner_id } => ( + "profile", + InternalClauses { + equal_clauses: BTreeMap::from([equal_clause( + "$ownerId", + Value::Identifier(identifier(owner_id).into_buffer()), + )]), + ..Default::default() + }, + IndexMap::new(), + 1, + ), + RequestSpec::DocumentsDashpayContacts { + identity_id, + to_identity, + limit, + } => ( + "contactRequest", + InternalClauses { + equal_clauses: BTreeMap::from([equal_clause( + if *to_identity { "toUserId" } else { "$ownerId" }, + Value::Identifier(identifier(identity_id).into_buffer()), + )]), + ..Default::default() + }, + asc_order("$createdAt"), + *limit, + ), + _ => panic!("{}: not a documents request", case.name), + }; + DriveDocumentQuery { + contract, + document_type: contract + .document_type_for_name(document_type_name) + .expect("system contract document type"), + internal_clauses, + offset: None, + limit: Some(limit), + order_by, + start_at: None, + start_at_included: false, + block_time_ms: None, + } +} + +fn contract_for(case: &Case) -> SystemDataContract { + match &case.manifest.request { + RequestSpec::DocumentsDpnsExact { .. } | RequestSpec::DocumentsDpnsPrefix { .. } => { + SystemDataContract::DPNS + } + RequestSpec::DocumentsDashpayProfile { .. } + | RequestSpec::DocumentsDashpayContacts { .. } => SystemDataContract::Dashpay, + _ => panic!("{}: not a documents request", case.name), + } +} + +fn run_documents_case(name: &str) { + let case = load_case(name); + let Expected::DocumentsPlaceholder { + serialized_documents, + } = &case.manifest.expected + else { + panic!("{name}: manifest expectation mismatch"); + }; + let platform_version = case.platform_version(); + let contract = load_system_data_contract(contract_for(&case), platform_version) + .expect("load system data contract"); + let query = document_query(&case, &contract); + + // The grovedb layer must verify: same root hash the fixture quorum + // signed, and exactly the recorded placeholder payloads. + let (root_hash, serialized) = query + .verify_proof_keep_serialized(&case.grovedb_proof, platform_version) + .unwrap_or_else(|e| panic!("{name}: grovedb layer must verify: {e}")); + assert_eq!( + hex::encode(root_hash), + case.manifest + .expected_root_hash_hex + .as_deref() + .expect("documents cases pin a root hash"), + "{name}: root hash" + ); + assert_eq!( + serialized, + serialized_documents + .iter() + .map(|hex| hex_vec(hex)) + .collect::>(), + "{name}: proven serialized payloads" + ); + + // Through the crate's public API the placeholder payload cannot decode + // into a DPP document: FromProof must surface a clean error. + let response = platform::GetDocumentsResponse { + version: Some(get_documents_response::Version::V0( + get_documents_response::GetDocumentsResponseV0 { + metadata: Some(case.metadata()), + result: Some( + get_documents_response::get_documents_response_v0::Result::Proof( + case.grpc_proof(), + ), + ), + }, + )), + }; + let error = >::maybe_from_proof_with_metadata( + query, + response, + NETWORK, + platform_version, + &case.provider(), + ) + .expect_err("placeholder document payload must fail to decode"); + assert!( + matches!( + error, + Error::DriveError { .. } | Error::ProtocolError { .. } + ), + "{name}: expected a document decode error, got: {error:?}" + ); +} + +#[test] +fn dpns_domain_exact() { + run_documents_case("dpns-domain-exact"); +} + +#[test] +fn dpns_domain_prefix() { + run_documents_case("dpns-domain-prefix"); +} + +#[test] +fn dashpay_profile() { + run_documents_case("dashpay-profile"); +} + +#[test] +fn dashpay_contacts_incoming() { + run_documents_case("dashpay-contacts-incoming"); +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors_identity.rs b/packages/rs-drive-proof-verifier/tests/vectors_identity.rs new file mode 100644 index 00000000000..7201bf48b26 --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors_identity.rs @@ -0,0 +1,259 @@ +//! Identity-family proof-vector regression tests: balance, nonce, contract +//! nonce, and public keys, plus the corrupted-proof negative case. Every +//! case replays a recorded Dash Core fixture proof through +//! [`FromProof::maybe_from_proof_with_metadata`] with the real fixture +//! quorum signature, so both the grovedb and tenderdash layers are checked. + +#![cfg(feature = "mocks")] + +mod common; + +use common::{identifier, load_case, Case, Expected, RequestSpec, NETWORK}; +use dapi_grpc::platform::v0::get_identity_contract_nonce_response::get_identity_contract_nonce_response_v0::Result as ContractNonceResult; +use dapi_grpc::platform::v0::{ + self as platform, get_identity_balance_request, get_identity_balance_response, + get_identity_contract_nonce_request, get_identity_contract_nonce_response, + get_identity_keys_request, get_identity_keys_response, get_identity_nonce_request, + get_identity_nonce_response, key_request_type, AllKeys, KeyRequestType, +}; +use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; +use dpp::identity::{IdentityPublicKey, KeyID}; +use dpp::serialization::PlatformDeserializable; +use drive_proof_verifier::types::{ + IdentityBalance, IdentityContractNonceFetcher, IdentityNonceFetcher, IdentityPublicKeys, +}; +use drive_proof_verifier::{Error, FromProof}; + +fn balance_pair( + case: &Case, +) -> ( + platform::GetIdentityBalanceRequest, + platform::GetIdentityBalanceResponse, +) { + let RequestSpec::IdentityBalance { identity_id } = &case.manifest.request else { + panic!("{}: expected an identity_balance request", case.name); + }; + let request = platform::GetIdentityBalanceRequest { + version: Some(get_identity_balance_request::Version::V0( + get_identity_balance_request::GetIdentityBalanceRequestV0 { + id: identifier(identity_id).to_vec(), + prove: true, + }, + )), + }; + let response = platform::GetIdentityBalanceResponse { + version: Some(get_identity_balance_response::Version::V0( + get_identity_balance_response::GetIdentityBalanceResponseV0 { + metadata: Some(case.metadata()), + result: Some( + get_identity_balance_response::get_identity_balance_response_v0::Result::Proof( + case.grpc_proof(), + ), + ), + }, + )), + }; + (request, response) +} + +// The crate's own Error type is what the public API returns; its size is +// not this test's concern. +#[allow(clippy::result_large_err)] +fn verify_balance_case(case: &Case) -> Result, Error> { + let (request, response) = balance_pair(case); + IdentityBalance::maybe_from_proof( + request, + response, + NETWORK, + case.platform_version(), + &case.provider(), + ) +} + +#[test] +fn identity_balance() { + let case = load_case("identity-balance"); + let Expected::IdentityBalance { balance: expected } = case.manifest.expected else { + panic!("manifest expectation mismatch"); + }; + let (request, response) = balance_pair(&case); + let (balance, metadata, proof) = IdentityBalance::maybe_from_proof_with_metadata( + request, + response, + NETWORK, + case.platform_version(), + &case.provider(), + ) + .expect("identity balance proof must verify"); + assert_eq!(balance, Some(expected)); + assert_eq!(metadata.height, case.manifest.block.height); + assert_eq!(metadata.chain_id, case.manifest.block.chain_id); + assert_eq!(proof.grovedb_proof, case.grovedb_proof); +} + +#[test] +fn identity_nonce() { + let case = load_case("identity-nonce"); + let RequestSpec::IdentityNonce { identity_id } = &case.manifest.request else { + panic!("manifest request mismatch"); + }; + let Expected::IdentityNonce { nonce: expected } = case.manifest.expected else { + panic!("manifest expectation mismatch"); + }; + let request = platform::GetIdentityNonceRequest { + version: Some(get_identity_nonce_request::Version::V0( + get_identity_nonce_request::GetIdentityNonceRequestV0 { + identity_id: identifier(identity_id).to_vec(), + prove: true, + }, + )), + }; + let response = platform::GetIdentityNonceResponse { + version: Some(get_identity_nonce_response::Version::V0( + get_identity_nonce_response::GetIdentityNonceResponseV0 { + metadata: Some(case.metadata()), + result: Some( + get_identity_nonce_response::get_identity_nonce_response_v0::Result::Proof( + case.grpc_proof(), + ), + ), + }, + )), + }; + let fetcher = IdentityNonceFetcher::maybe_from_proof( + request, + response, + NETWORK, + case.platform_version(), + &case.provider(), + ) + .expect("identity nonce proof must verify") + .expect("nonce must be proven present"); + assert_eq!(fetcher.0, expected); +} + +#[test] +fn identity_contract_nonce() { + let case = load_case("identity-contract-nonce"); + let RequestSpec::IdentityContractNonce { + identity_id, + contract_id, + } = &case.manifest.request + else { + panic!("manifest request mismatch"); + }; + let Expected::IdentityContractNonce { nonce: expected } = case.manifest.expected else { + panic!("manifest expectation mismatch"); + }; + let request = platform::GetIdentityContractNonceRequest { + version: Some(get_identity_contract_nonce_request::Version::V0( + get_identity_contract_nonce_request::GetIdentityContractNonceRequestV0 { + identity_id: identifier(identity_id).to_vec(), + contract_id: identifier(contract_id).to_vec(), + prove: true, + }, + )), + }; + let response = platform::GetIdentityContractNonceResponse { + version: Some(get_identity_contract_nonce_response::Version::V0( + get_identity_contract_nonce_response::GetIdentityContractNonceResponseV0 { + metadata: Some(case.metadata()), + result: Some(ContractNonceResult::Proof(case.grpc_proof())), + }, + )), + }; + let fetcher = IdentityContractNonceFetcher::maybe_from_proof( + request, + response, + NETWORK, + case.platform_version(), + &case.provider(), + ) + .expect("identity contract nonce proof must verify") + .expect("contract nonce must be proven present"); + assert_eq!(fetcher.0, expected); +} + +#[test] +fn identity_keys() { + let case = load_case("identity-keys"); + let RequestSpec::IdentityKeys { identity_id } = &case.manifest.request else { + panic!("manifest request mismatch"); + }; + let Expected::IdentityKeys { serialized_keys } = &case.manifest.expected else { + panic!("manifest expectation mismatch"); + }; + let request = platform::GetIdentityKeysRequest { + version: Some(get_identity_keys_request::Version::V0( + get_identity_keys_request::GetIdentityKeysRequestV0 { + identity_id: identifier(identity_id).to_vec(), + request_type: Some(KeyRequestType { + request: Some(key_request_type::Request::AllKeys(AllKeys {})), + }), + limit: None, + offset: None, + prove: true, + }, + )), + }; + let response = platform::GetIdentityKeysResponse { + version: Some(get_identity_keys_response::Version::V0( + get_identity_keys_response::GetIdentityKeysResponseV0 { + metadata: Some(case.metadata()), + result: Some( + get_identity_keys_response::get_identity_keys_response_v0::Result::Proof( + case.grpc_proof(), + ), + ), + }, + )), + }; + let keys = IdentityPublicKeys::maybe_from_proof( + request, + response, + NETWORK, + case.platform_version(), + &case.provider(), + ) + .expect("identity keys proof must verify") + .expect("keys must be proven present"); + + let expected: Vec = serialized_keys + .iter() + .map(|serialized| { + IdentityPublicKey::deserialize_from_bytes(&common::hex_vec(serialized)) + .expect("expected fixture key must deserialize") + }) + .collect(); + assert_eq!(keys.len(), expected.len()); + for expected_key in &expected { + let key = keys + .get(&expected_key.id()) + .unwrap_or_else(|| panic!("key id {} missing from proof", expected_key.id())) + .as_ref() + .unwrap_or_else(|| panic!("key id {} proven absent", expected_key.id())); + assert_eq!(key, expected_key); + } + assert_eq!( + keys.keys().copied().collect::>(), + vec![0, 1, 2], + "keys must arrive ordered by id" + ); +} + +// A flipped bit inside the grovedb proof must surface as a clean proof +// error before the quorum signature is ever consulted -- never a panic and +// never an Ok result. +#[test] +fn corrupted_grovedb_proof_is_rejected() { + let case = load_case("identity-balance-corrupted-proof"); + let Expected::Error { class } = case.manifest.expected else { + panic!("manifest expectation mismatch"); + }; + assert_eq!(class, common::ErrorClass::ProofInvalid); + let error = verify_balance_case(&case).expect_err("corrupted proof must not verify"); + assert!( + matches!(error, Error::GroveDBError { .. } | Error::DriveError { .. }), + "expected a grovedb/drive proof error, got: {error:?}" + ); +} diff --git a/packages/rs-drive-proof-verifier/tests/vectors_quorum_sig.rs b/packages/rs-drive-proof-verifier/tests/vectors_quorum_sig.rs new file mode 100644 index 00000000000..8b099eb98ad --- /dev/null +++ b/packages/rs-drive-proof-verifier/tests/vectors_quorum_sig.rs @@ -0,0 +1,148 @@ +//! Tenderdash quorum-signature regression tests, seeded from the Dash Core +//! `quorum_sig_vectors.json` fixture (tenderdash v1.5.1, basic BLS scheme). +//! The positive case runs a full identity-balance verification whose +//! envelope carries a real quorum signature over the state; the negatives +//! flip exactly one ingredient each (signature bit, quorum key, block id +//! hash, or a `ResponseMetadata` field folded into the signed `StateId`) +//! and must fail with an invalid-signature error -- proving the signature +//! actually binds those inputs. + +#![cfg(feature = "mocks")] + +mod common; + +use common::{identifier, load_case, Case, ErrorClass, Expected, RequestSpec, NETWORK}; +use dapi_grpc::platform::v0::{ + self as platform, get_identity_balance_request, get_identity_balance_response, +}; +use drive_proof_verifier::types::IdentityBalance; +use drive_proof_verifier::{Error, FromProof}; + +// The crate's own Error type is what the public API returns; its size is +// not this test's concern. +#[allow(clippy::result_large_err)] +fn verify_balance(case: &Case) -> Result, Error> { + verify_balance_with_metadata(case, case.metadata()) +} + +/// Like [`verify_balance`], but lets the caller substitute the response +/// metadata that gets carried alongside the case's untouched proof envelope +/// -- used to prove the metadata itself is inside the signed `StateId`. +#[allow(clippy::result_large_err)] +fn verify_balance_with_metadata( + case: &Case, + metadata: platform::ResponseMetadata, +) -> Result, Error> { + let RequestSpec::IdentityBalance { identity_id } = &case.manifest.request else { + panic!("{}: expected an identity_balance request", case.name); + }; + let request = platform::GetIdentityBalanceRequest { + version: Some(get_identity_balance_request::Version::V0( + get_identity_balance_request::GetIdentityBalanceRequestV0 { + id: identifier(identity_id).to_vec(), + prove: true, + }, + )), + }; + let response = platform::GetIdentityBalanceResponse { + version: Some(get_identity_balance_response::Version::V0( + get_identity_balance_response::GetIdentityBalanceResponseV0 { + metadata: Some(metadata), + result: Some( + get_identity_balance_response::get_identity_balance_response_v0::Result::Proof( + case.grpc_proof(), + ), + ), + }, + )), + }; + IdentityBalance::maybe_from_proof( + request, + response, + NETWORK, + case.platform_version(), + &case.provider(), + ) +} + +fn expect_invalid_signature(name: &str) { + let case = load_case(name); + let Expected::Error { class } = case.manifest.expected else { + panic!("{name}: manifest expectation mismatch"); + }; + assert_eq!(class, ErrorClass::InvalidSignature); + let error = verify_balance(&case).expect_err("quorum signature check must fail"); + // A wrong key or wrong signed payload fails the pairing check + // (InvalidSignature); a bit-flipped signature may already fail G2 point + // decompression (SignatureVerificationError). Both are proper + // rejections of a bad quorum signature. + assert!( + matches!( + error, + Error::InvalidSignature { .. } | Error::SignatureVerificationError { .. } + ), + "{name}: expected a signature rejection, got: {error:?}" + ); +} + +#[test] +fn valid_quorum_signature_verifies() { + let case = load_case("quorum-sig-valid"); + let Expected::IdentityBalance { balance: expected } = case.manifest.expected else { + panic!("manifest expectation mismatch"); + }; + let balance = verify_balance(&case) + .expect("envelope with a valid quorum signature must verify end to end"); + assert_eq!(balance, Some(expected)); +} + +#[test] +fn tampered_signature_is_rejected() { + expect_invalid_signature("quorum-sig-tampered-signature"); +} + +#[test] +fn wrong_quorum_key_is_rejected() { + expect_invalid_signature("quorum-sig-wrong-quorum-key"); +} + +#[test] +fn wrong_block_id_hash_is_rejected() { + expect_invalid_signature("quorum-sig-wrong-block-id-hash"); +} + +// The quorum signs a `StateId` built from `height`, `core_chain_locked_height`, +// `time_ms`, and the app hash (see `verify_tenderdash_proof` in `src/verify.rs`). +// The proof envelope and signature bytes are untouched here -- only the +// out-of-band `ResponseMetadata` a server could independently lie about is +// mutated -- so a pass here would mean the metadata is never actually bound +// by the signature. +fn expect_metadata_tamper_breaks_signature(mutate: impl Fn(&mut platform::ResponseMetadata)) { + let case = load_case("quorum-sig-valid"); + let mut metadata = case.metadata(); + mutate(&mut metadata); + let error = verify_balance_with_metadata(&case, metadata) + .expect_err("tampered metadata must break the quorum signature check"); + assert!( + matches!( + error, + Error::InvalidSignature { .. } | Error::SignatureVerificationError { .. } + ), + "expected a signature rejection, got: {error:?}" + ); +} + +#[test] +fn tampered_height_breaks_signature() { + expect_metadata_tamper_breaks_signature(|metadata| metadata.height += 1); +} + +#[test] +fn tampered_time_ms_breaks_signature() { + expect_metadata_tamper_breaks_signature(|metadata| metadata.time_ms += 1); +} + +#[test] +fn tampered_core_chain_locked_height_breaks_signature() { + expect_metadata_tamper_breaks_signature(|metadata| metadata.core_chain_locked_height += 1); +}