From edd06dee2407f6ca889c94228f1470ec218156a8 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Fri, 4 Oct 2024 11:34:24 +0200 Subject: [PATCH 1/6] fix(sdk)!: preserve order of objects returned by drive --- Cargo.lock | 47 +++++++------ packages/rs-drive-proof-verifier/Cargo.toml | 1 + packages/rs-drive-proof-verifier/src/proof.rs | 69 +++++++++++-------- .../rs-drive-proof-verifier/src/provider.rs | 2 +- packages/rs-drive-proof-verifier/src/types.rs | 4 +- packages/rs-sdk/src/mock/requests.rs | 31 +++++++-- packages/rs-sdk/src/mock/sdk.rs | 13 ++-- .../src/platform/block_info_from_metadata.rs | 4 +- packages/rs-sdk/src/platform/fetch_many.rs | 12 ++-- packages/rs-sdk/tests/fetch/config.rs | 6 +- .../rs-sdk/tests/fetch/contested_resource.rs | 2 +- .../fetch/contested_resource_vote_state.rs | 2 +- packages/rs-sdk/tests/fetch/document.rs | 3 +- packages/rs-sdk/tests/fetch/epoch.rs | 12 ++-- packages/rs-sdk/tests/fetch/mock_fetch.rs | 3 +- .../rs-sdk/tests/fetch/mock_fetch_many.rs | 7 +- 16 files changed, 129 insertions(+), 89 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6a05f5b530c..163a9e82406 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1464,7 +1464,7 @@ dependencies = [ "env_logger 0.9.3", "getrandom", "hex", - "indexmap 2.4.0", + "indexmap 2.6.0", "integer-encoding", "itertools 0.12.1", "json-schema-compatibility-validator", @@ -1517,7 +1517,7 @@ dependencies = [ "grovedb-storage", "grovedb-version", "hex", - "indexmap 2.4.0", + "indexmap 2.6.0", "integer-encoding", "intmap", "itertools 0.11.0", @@ -1561,7 +1561,7 @@ dependencies = [ "envy", "file-rotate", "hex", - "indexmap 2.4.0", + "indexmap 2.6.0", "integer-encoding", "itertools 0.10.5", "lazy_static", @@ -1601,6 +1601,7 @@ dependencies = [ "dpp", "drive", "hex", + "indexmap 2.6.0", "platform-serialization", "platform-serialization-derive", "serde", @@ -2082,7 +2083,7 @@ dependencies = [ "grovedbg-types", "hex", "hex-literal", - "indexmap 2.4.0", + "indexmap 2.6.0", "integer-encoding", "intmap", "itertools 0.12.1", @@ -2138,7 +2139,7 @@ dependencies = [ "grovedb-version", "grovedb-visualize", "hex", - "indexmap 2.4.0", + "indexmap 2.6.0", "integer-encoding", "num_cpus", "rand", @@ -2214,7 +2215,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.4.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -2233,7 +2234,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.4.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -2265,6 +2266,12 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + [[package]] name = "hdrhistogram" version = "7.5.4" @@ -2602,12 +2609,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.0", "serde", ] @@ -2974,7 +2981,7 @@ dependencies = [ "hyper 1.4.1", "hyper-tls", "hyper-util", - "indexmap 2.4.0", + "indexmap 2.6.0", "ipnet", "metrics", "metrics-util", @@ -3445,7 +3452,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.4.0", + "indexmap 2.6.0", ] [[package]] @@ -3523,7 +3530,7 @@ dependencies = [ "bs58 0.5.1", "ciborium", "hex", - "indexmap 2.4.0", + "indexmap 2.6.0", "lazy_static", "platform-serialization", "platform-version", @@ -4510,7 +4517,7 @@ version = "1.0.126" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3b863381a05ffefbc82571a2d893edf47b27fb0ebedbf582c39640e51abebef" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "itoa", "memchr", "ryu", @@ -4585,7 +4592,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.4.0", + "indexmap 2.6.0", "serde", "serde_derive", "serde_json", @@ -5323,7 +5330,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "toml_datetime", "winnow 0.5.40", ] @@ -5334,7 +5341,7 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "toml_datetime", "winnow 0.5.40", ] @@ -5345,7 +5352,7 @@ version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", @@ -5444,7 +5451,7 @@ source = "git+https://github.com/QuantumExplorer/tower?branch=fix/indexMap2OnV04 dependencies = [ "futures-core", "futures-util", - "indexmap 2.4.0", + "indexmap 2.6.0", "pin-project", "pin-project-lite", "rand", @@ -6207,7 +6214,7 @@ dependencies = [ "crossbeam-utils", "displaydoc", "flate2", - "indexmap 2.4.0", + "indexmap 2.6.0", "memchr", "thiserror", "zopfli", diff --git a/packages/rs-drive-proof-verifier/Cargo.toml b/packages/rs-drive-proof-verifier/Cargo.toml index cef01f45d8f..12bf33398f2 100644 --- a/packages/rs-drive-proof-verifier/Cargo.toml +++ b/packages/rs-drive-proof-verifier/Cargo.toml @@ -43,3 +43,4 @@ serde_json = { version = "1.0.103", features = [ ], optional = true } hex = { version = "0.4.3" } derive_more = { version = "0.99.11" } +indexmap = { version = "2.6.0" } diff --git a/packages/rs-drive-proof-verifier/src/proof.rs b/packages/rs-drive-proof-verifier/src/proof.rs index 89fef813601..d63346fa085 100644 --- a/packages/rs-drive-proof-verifier/src/proof.rs +++ b/packages/rs-drive-proof-verifier/src/proof.rs @@ -43,6 +43,7 @@ use drive::query::vote_poll_contestant_votes_query::ContestedDocumentVotePollVot use drive::query::vote_poll_vote_state_query::ContestedDocumentVotePollDriveQuery; use drive::query::vote_polls_by_document_type_query::VotePollsByDocumentTypeQuery; use drive::query::{DriveDocumentQuery, VotePollsByEndDateDriveQuery}; +use indexmap::IndexMap; use std::array::TryFromSliceError; use std::collections::BTreeMap; use std::num::TryFromIntError; @@ -832,24 +833,23 @@ impl FromProof for DataContracts { verify_tenderdash_proof(proof, mtd, &root_hash, provider)?; - let maybe_contracts: Option>> = - if !contracts.is_empty() { - let contracts: DataContracts = contracts - .into_iter() - .try_fold(DataContracts::new(), |mut acc, (k, v)| { - Identifier::from_bytes(&k).map(|id| { - acc.insert(id, v); - acc - }) + let maybe_contracts: Option = if !contracts.is_empty() { + let contracts: DataContracts = contracts + .into_iter() + .try_fold(DataContracts::new(), |mut acc, (k, v)| { + Identifier::from_bytes(&k).map(|id| { + acc.insert(id, v); + acc }) - .map_err(|e| Error::ResultEncodingError { - error: e.to_string(), - })?; + }) + .map_err(|e| Error::ResultEncodingError { + error: e.to_string(), + })?; - Some(contracts) - } else { - None - }; + Some(contracts) + } else { + None + }; Ok((maybe_contracts, mtd.clone(), proof.clone())) } @@ -987,13 +987,13 @@ impl FromProof for ExtendedEpochInfo { provider, )?; - if let Some(mut e) = epochs.0 { + if let Some(e) = epochs.0 { if e.len() != 1 { return Err(Error::RequestError { error: format!("expected 1 epoch, got {}", e.len()), }); } - let epoch = e.pop_first().and_then(|v| v.1); + let epoch = e.into_iter().next().and_then(|v| v.1); Ok((epoch, epochs.1, epochs.2)) } else { Ok((None, epochs.1, epochs.2)) @@ -1056,7 +1056,7 @@ impl FromProof for ExtendedEpochInfos { (info.index, Some(v)) }) - .collect::>>(); + .collect::(); verify_tenderdash_proof(proof, mtd, &root_hash, provider)?; @@ -1203,10 +1203,11 @@ impl FromProof for Elements { let (root_hash, objects) = Drive::verify_elements(&proof.grovedb_proof, path, keys, platform_version)?; + let elements: Elements = Elements::from_iter(objects); verify_tenderdash_proof(proof, mtd, &root_hash, provider)?; - Ok((objects.into_option(), mtd.clone(), proof.clone())) + Ok((elements.into_option(), mtd.clone(), proof.clone())) } } @@ -1638,23 +1639,25 @@ impl FromProof for Vote { } }; - let (mut maybe_votes, mtd, proof) = - ResourceVotesByIdentity::maybe_from_proof_with_metadata( - request, - response, - network, - platform_version, - provider, - )?; + let (maybe_votes, mtd, proof) = ResourceVotesByIdentity::maybe_from_proof_with_metadata( + request, + response, + network, + platform_version, + provider, + )?; - let (id, vote) = match maybe_votes.as_mut() { + let (id, vote) = match maybe_votes { Some(v) if v.len() > 1 => { return Err(Error::ResponseDecodeError { error: format!("expected 1 vote, got {}", v.len()), }) } Some(v) if v.is_empty() => return Ok((None, mtd, proof)), - Some(v) => v.pop_first().expect("is_empty() must detect empty map"), + Some(v) => v + .into_iter() + .next() + .expect("is_empty() must detect empty map"), None => return Ok((None, mtd, proof)), }; @@ -1878,6 +1881,12 @@ impl Length for BTreeMap> { } } +impl Length for IndexMap> { + fn count_some(&self) -> usize { + self.values().filter(|v| v.is_some()).count() + } +} + /// Implement Length trait for a type /// /// # Arguments diff --git a/packages/rs-drive-proof-verifier/src/provider.rs b/packages/rs-drive-proof-verifier/src/provider.rs index ecead859946..e7eafd2e45f 100644 --- a/packages/rs-drive-proof-verifier/src/provider.rs +++ b/packages/rs-drive-proof-verifier/src/provider.rs @@ -47,7 +47,7 @@ pub trait ContextProvider: Send + Sync { /// # Returns /// /// * `Ok(Option>)`: On success, returns the data contract if it exists, or `None` if it does not. - /// We use Arc to avoid copying the data contract. + /// We use Arc to avoid copying the data contract. /// * `Err(Error)`: On failure, returns an error indicating why the operation failed. fn get_data_contract( &self, diff --git a/packages/rs-drive-proof-verifier/src/types.rs b/packages/rs-drive-proof-verifier/src/types.rs index d49301720b3..743034d3f74 100644 --- a/packages/rs-drive-proof-verifier/src/types.rs +++ b/packages/rs-drive-proof-verifier/src/types.rs @@ -31,6 +31,8 @@ use dpp::{ }; use drive::grovedb::query_result_type::Path; use drive::grovedb::Element; +// IndexMap is exposed to the public API +pub use indexmap::IndexMap; use std::collections::{BTreeMap, BTreeSet}; #[cfg(feature = "mocks")] @@ -57,7 +59,7 @@ pub use evonode_status::*; /// /// * `K`: The type of the keys in the map. /// * `O`: The type of the objects in the map. -pub type RetrievedObjects = BTreeMap>; +pub type RetrievedObjects = IndexMap>; /// A data structure that holds a set of objects of a generic type `O`, indexed by a key of type `K`. /// diff --git a/packages/rs-sdk/src/mock/requests.rs b/packages/rs-sdk/src/mock/requests.rs index 0b2e43692f1..c6e84f37dd7 100644 --- a/packages/rs-sdk/src/mock/requests.rs +++ b/packages/rs-sdk/src/mock/requests.rs @@ -3,7 +3,7 @@ use dpp::bincode::config::standard; use dpp::{ bincode, block::extended_epoch_info::ExtendedEpochInfo, - dashcore::{hashes::Hash, ProTxHash}, + dashcore::{hashes::Hash as CoreHash, ProTxHash}, document::{serialization_traits::DocumentCborMethodsV0, Document}, identifier::Identifier, identity::IdentityPublicKey, @@ -18,11 +18,11 @@ use dpp::{ use drive::grovedb::Element; use drive_proof_verifier::types::{ Contenders, ContestedResources, CurrentQuorumsInfo, ElementFetchRequestItem, EvoNodeStatus, - IdentityBalanceAndRevision, MasternodeProtocolVote, PrefundedSpecializedBalance, + IdentityBalanceAndRevision, IndexMap, MasternodeProtocolVote, PrefundedSpecializedBalance, ProposerBlockCounts, RetrievedIntegerValue, TotalCreditsInPlatform, VotePollsGroupedByTimestamp, Voters, }; -use std::collections::BTreeMap; +use std::{collections::BTreeMap, hash::Hash}; static BINCODE_CONFIG: bincode::config::Configuration = bincode::config::standard(); @@ -115,6 +115,29 @@ impl MockResponse for BTreeMap { } } +impl MockResponse for IndexMap { + fn mock_deserialize(sdk: &MockDashPlatformSdk, buf: &[u8]) -> Self + where + Self: Sized, + { + let (data, _): (IndexMap, Vec>, _) = + bincode::serde::decode_from_slice(buf, BINCODE_CONFIG).expect("decode BTreeMap"); + + data.into_iter() + .map(|(k, v)| (K::mock_deserialize(sdk, &k), V::mock_deserialize(sdk, &v))) + .collect() + } + + fn mock_serialize(&self, sdk: &MockDashPlatformSdk) -> Vec { + let data: IndexMap, Vec> = self + .iter() + .map(|(k, v)| (k.mock_serialize(sdk), v.mock_serialize(sdk))) + .collect(); + + bincode::serde::encode_to_vec(data, BINCODE_CONFIG).expect("encode BTreeMap") + } +} + /// Serialize and deserialize the object for mocking using bincode. /// /// Use this macro when the object implements platform serialization. @@ -232,7 +255,7 @@ impl MockResponse for ProTxHash { { let data = platform_versioned_decode_from_slice(buf, BINCODE_CONFIG, sdk.version()) .expect("decode ProTxHash"); - ProTxHash::from_raw_hash(Hash::from_byte_array(data)) + ProTxHash::from_raw_hash(CoreHash::from_byte_array(data)) } } diff --git a/packages/rs-sdk/src/mock/sdk.rs b/packages/rs-sdk/src/mock/sdk.rs index 02258c0cd13..1936acc8727 100644 --- a/packages/rs-sdk/src/mock/sdk.rs +++ b/packages/rs-sdk/src/mock/sdk.rs @@ -304,7 +304,7 @@ impl MockDashPlatformSdk { /// ## Generic Parameters /// /// - `O`: Type of the object that will be returned in response to the query. - /// Must implement [FetchMany]. `Vec` must implement [MockResponse]. + /// Must implement [FetchMany]. `Vec` must implement [MockResponse]. /// - `Q`: Type of the query that will be sent to Platform. Must implement [Query] and [Mockable]. /// /// ## Arguments @@ -330,20 +330,23 @@ impl MockDashPlatformSdk { K: Ord, O: FetchMany, Q: Query<>::Request>, - R: FromIterator<(K, Option)> + MockResponse + Send + Default, + R, >( &mut self, query: Q, objects: Option, ) -> Result<&mut Self, Error> where - R: MockResponse, <>::Request as TransportRequest>::Response: Default, - R: FromProof< + R: FromIterator<(K, Option)> + + FromProof< >::Request, Request = >::Request, Response = <>::Request as TransportRequest>::Response, - > + Sync, + > + MockResponse + + Sync + + Send + + Default, { let grpc_request = query.query(self.prove()).expect("query must be correct"); self.expect(grpc_request, objects).await?; diff --git a/packages/rs-sdk/src/platform/block_info_from_metadata.rs b/packages/rs-sdk/src/platform/block_info_from_metadata.rs index 713e1e176d4..5e96e136550 100644 --- a/packages/rs-sdk/src/platform/block_info_from_metadata.rs +++ b/packages/rs-sdk/src/platform/block_info_from_metadata.rs @@ -12,8 +12,8 @@ use drive::error::proof::ProofError; /// /// # Parameters /// - `response_metadata`: A reference to `ResponseMetadata` obtained from a platform response. -/// This metadata includes various block-related information such as time in milliseconds, -/// height, core chain locked height, and epoch. +/// This metadata includes various block-related information such as time in milliseconds, +/// height, core chain locked height, and epoch. /// /// # Returns /// If successful, returns `Ok(BlockInfo)` where `BlockInfo` contains: diff --git a/packages/rs-sdk/src/platform/fetch_many.rs b/packages/rs-sdk/src/platform/fetch_many.rs index 897be764ae0..4ecf6e42cc0 100644 --- a/packages/rs-sdk/src/platform/fetch_many.rs +++ b/packages/rs-sdk/src/platform/fetch_many.rs @@ -31,18 +31,16 @@ use dpp::{ block::extended_epoch_info::ExtendedEpochInfo, voting::votes::resource_vote::ResourceVote, }; use dpp::{document::Document, voting::contender_structs::ContenderWithSerializedDocument}; -use drive::grovedb::query_result_type::{Key, Path}; +use drive::grovedb::query_result_type::Key; use drive::grovedb::Element; use drive_proof_verifier::types::{ Contenders, ContestedResource, ContestedResources, DataContracts, Elements, ExtendedEpochInfos, - IdentityBalances, IdentityPublicKeys, KeysInPath, MasternodeProtocolVote, - MasternodeProtocolVotes, ProposerBlockCountById, ProposerBlockCountByRange, - ProposerBlockCounts, ProtocolVersionUpgrades, ResourceVotesByIdentity, - VotePollsGroupedByTimestamp, Voter, Voters, + IdentityBalances, IdentityPublicKeys, MasternodeProtocolVote, MasternodeProtocolVotes, + ProposerBlockCountById, ProposerBlockCountByRange, ProposerBlockCounts, + ProtocolVersionUpgrades, ResourceVotesByIdentity, VotePollsGroupedByTimestamp, Voter, Voters, }; use drive_proof_verifier::{types::Documents, FromProof}; use rs_dapi_client::{transport::TransportRequest, DapiRequest, RequestSettings}; -use std::collections::BTreeMap; /// Fetch multiple objects from Platform. /// @@ -240,7 +238,7 @@ impl FetchMany for Document { tracing::trace!(request=?document_query, response=?response, "fetch multiple documents"); // let object: Option> = sdk - let documents: BTreeMap> = sdk + let documents: Documents = sdk .parse_proof::(document_query, response) .await? .unwrap_or_default(); diff --git a/packages/rs-sdk/tests/fetch/config.rs b/packages/rs-sdk/tests/fetch/config.rs index 445904795d6..e260e4f3f2b 100644 --- a/packages/rs-sdk/tests/fetch/config.rs +++ b/packages/rs-sdk/tests/fetch/config.rs @@ -141,14 +141,14 @@ impl Config { /// ## Feature flags /// /// * `offline-testing` is not set - connect to Platform and generate - /// new test vectors during execution + /// new test vectors during execution /// * `offline-testing` is set - use mock implementation and - /// load existing test vectors from disk + /// load existing test vectors from disk /// /// ## Arguments /// /// * namespace - namespace to use when storing mock expectations; this is used to separate - /// expectations from different tests. + /// expectations from different tests. /// /// When empty string is provided, expectations are stored in the root of the dump directory. pub async fn setup_api(&self, namespace: &str) -> dash_sdk::Sdk { diff --git a/packages/rs-sdk/tests/fetch/contested_resource.rs b/packages/rs-sdk/tests/fetch/contested_resource.rs index 4f899c21261..31134769c88 100644 --- a/packages/rs-sdk/tests/fetch/contested_resource.rs +++ b/packages/rs-sdk/tests/fetch/contested_resource.rs @@ -278,7 +278,7 @@ async fn contested_resources_limit_PLAN_656() { }, Ok("ContestedResources([])".into()); "Non-existing end_index_values returns error")] #[test_case::test_case(|q| q.end_index_values = vec![Value::Array(vec![0.into(), 1.into()])], Err("incorrect index values error: too many end index values were provided"); "wrong type of end_index_values should return InvalidArgument")] #[test_case::test_case(|q| q.limit = Some(0), Err(r#"code: InvalidArgument"#); "limit 0 returns InvalidArgument")] -#[test_case::test_case(|q| q.limit = Some(std::u16::MAX), Err(r#"code: InvalidArgument"#); "limit std::u16::MAX returns InvalidArgument")] +#[test_case::test_case(|q| q.limit = Some(u16::MAX), Err(r#"code: InvalidArgument"#); "limit std::u16::MAX returns InvalidArgument")] // Disabled due to bug PLAN-656 // #[test_case::test_case(|q| { // q.start_index_values = vec![Value::Text("dash".to_string())]; diff --git a/packages/rs-sdk/tests/fetch/contested_resource_vote_state.rs b/packages/rs-sdk/tests/fetch/contested_resource_vote_state.rs index 69b66e0e486..944feeebe23 100644 --- a/packages/rs-sdk/tests/fetch/contested_resource_vote_state.rs +++ b/packages/rs-sdk/tests/fetch/contested_resource_vote_state.rs @@ -276,7 +276,7 @@ async fn contested_resource_vote_states_with_limit_PLAN_674() { type MutFn = fn(&mut ContestedDocumentVotePollDriveQuery); #[test_case(|q| q.limit = Some(0), Err("limit 0 out of bounds of [1, 100]"); "limit 0")] -#[test_case(|q| q.limit = Some(std::u16::MAX), Err("limit 65535 out of bounds of [1, 100]"); "limit std::u16::MAX")] +#[test_case(|q| q.limit = Some(u16::MAX), Err("limit 65535 out of bounds of [1, 100]"); "limit std::u16::MAX")] #[test_case(|q| q.start_at = Some(([0x11; 32], true)), Ok("Contenders { winner: None, contenders: {Identifier("); "start_at does not exist should return next contenders")] #[test_case(|q| q.start_at = Some(([0xff; 32], true)), Ok("Contenders { winner: None, contenders: {}, abstain_vote_tally: None, lock_vote_tally: None }"); "start_at 0xff;32 should return zero contenders")] #[test_case(|q| q.vote_poll.document_type_name = "nx doctype".to_string(), Err(r#"code: InvalidArgument, message: "document type nx doctype not found"#); "non existing document type returns InvalidArgument")] diff --git a/packages/rs-sdk/tests/fetch/document.rs b/packages/rs-sdk/tests/fetch/document.rs index 8263250d0b2..088cf731369 100644 --- a/packages/rs-sdk/tests/fetch/document.rs +++ b/packages/rs-sdk/tests/fetch/document.rs @@ -34,7 +34,8 @@ async fn document_read() { let first_doc = Document::fetch_many(&sdk, all_docs_query) .await .expect("fetch many documents") - .pop_first() + .into_iter() + .next() .expect("first item must exist") .1 .expect("document must exist"); diff --git a/packages/rs-sdk/tests/fetch/epoch.rs b/packages/rs-sdk/tests/fetch/epoch.rs index 8080e3b344b..0c8f429d7fb 100644 --- a/packages/rs-sdk/tests/fetch/epoch.rs +++ b/packages/rs-sdk/tests/fetch/epoch.rs @@ -1,5 +1,3 @@ -use std::collections::BTreeMap; - use super::{common::setup_logs, config::Config}; use dapi_grpc::platform::{ v0::{get_identity_request::GetIdentityRequestV0, GetIdentityRequest}, @@ -15,6 +13,7 @@ use dash_sdk::{ use dpp::block::epoch::EpochIndex; use dpp::block::extended_epoch_info::v0::ExtendedEpochInfoV0Getters; use dpp::block::extended_epoch_info::ExtendedEpochInfo; +use drive_proof_verifier::types::ExtendedEpochInfos; use rs_dapi_client::{DapiRequestExecutor, RequestSettings}; /// Get current epoch index from DAPI response metadata @@ -35,7 +34,7 @@ async fn get_current_epoch(sdk: &Sdk, cfg: &Config) -> EpochIndex { } /// Check some assertions on returned epochs list fn assert_epochs( - epochs: BTreeMap>, + epochs: ExtendedEpochInfos, starting_epoch: EpochIndex, current_epoch: EpochIndex, limit: u16, @@ -89,10 +88,9 @@ async fn test_epoch_list() { let current_epoch = get_current_epoch(&sdk, &cfg).await; // When we fetch epochs from the server, starting with `starting_epoch` - let epochs: BTreeMap> = - ExtendedEpochInfo::fetch_many(&sdk, starting_epoch) - .await - .expect("list epochs"); + let epochs: ExtendedEpochInfos = ExtendedEpochInfo::fetch_many(&sdk, starting_epoch) + .await + .expect("list epochs"); assert_epochs( epochs, diff --git a/packages/rs-sdk/tests/fetch/mock_fetch.rs b/packages/rs-sdk/tests/fetch/mock_fetch.rs index a5d49160772..056e707642f 100644 --- a/packages/rs-sdk/tests/fetch/mock_fetch.rs +++ b/packages/rs-sdk/tests/fetch/mock_fetch.rs @@ -1,5 +1,4 @@ -//! -//! +//! This module contains tests for the mock fetch functionality. use super::common::{mock_data_contract, mock_document_type}; use dash_sdk::{ diff --git a/packages/rs-sdk/tests/fetch/mock_fetch_many.rs b/packages/rs-sdk/tests/fetch/mock_fetch_many.rs index fdf3811d8d1..36bce785435 100644 --- a/packages/rs-sdk/tests/fetch/mock_fetch_many.rs +++ b/packages/rs-sdk/tests/fetch/mock_fetch_many.rs @@ -1,5 +1,3 @@ -use std::collections::BTreeMap; - use super::common::{mock_data_contract, mock_document_type}; use dash_sdk::{ platform::{DocumentQuery, FetchMany}, @@ -14,6 +12,7 @@ use dpp::{ }, document::{Document, DocumentV0Getters}, }; +use drive_proof_verifier::types::Documents; /// Given some data contract, document type and 1 document of this type, when I request multiple documents, I get that /// document. @@ -26,13 +25,13 @@ async fn test_mock_document_fetch_many() { let expected_doc = document_type .random_document(None, sdk.version()) .expect("document should be created"); - let expected = BTreeMap::from([(expected_doc.id(), Some(expected_doc.clone()))]); + let expected = Documents::from([(expected_doc.id(), Some(expected_doc.clone()))]); // document that should not be returned, as it will be defined as a duplicate let not_expected_doc = document_type .random_document(None, sdk.version()) .expect("document 2 should be created"); - let not_expected = BTreeMap::from([(not_expected_doc.id(), Some(not_expected_doc))]); + let not_expected = Documents::from([(not_expected_doc.id(), Some(not_expected_doc))]); let document_type_name = document_type.name(); From ccf93c3184a594b3a6c8fccb235d21f041d46b5f Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Fri, 4 Oct 2024 16:07:53 +0200 Subject: [PATCH 2/6] chore: apply feedback --- packages/rs-drive-proof-verifier/Cargo.toml | 1 + packages/rs-drive-proof-verifier/src/proof.rs | 6 +++++- packages/rs-drive-proof-verifier/src/types.rs | 14 +++++++------- packages/rs-drive-proof-verifier/src/unproved.rs | 2 +- packages/rs-sdk/src/mock/requests.rs | 4 ++-- packages/rs-sdk/tests/fetch/data_contract.rs | 7 ++++++- 6 files changed, 22 insertions(+), 12 deletions(-) diff --git a/packages/rs-drive-proof-verifier/Cargo.toml b/packages/rs-drive-proof-verifier/Cargo.toml index 12bf33398f2..1c68ebcc123 100644 --- a/packages/rs-drive-proof-verifier/Cargo.toml +++ b/packages/rs-drive-proof-verifier/Cargo.toml @@ -15,6 +15,7 @@ mocks = [ "dep:platform-serialization-derive", "dep:platform-serialization", "dpp/document-serde-conversion", + "indexmap/serde", ] [dependencies] diff --git a/packages/rs-drive-proof-verifier/src/proof.rs b/packages/rs-drive-proof-verifier/src/proof.rs index d63346fa085..6ad4b93f2be 100644 --- a/packages/rs-drive-proof-verifier/src/proof.rs +++ b/packages/rs-drive-proof-verifier/src/proof.rs @@ -904,7 +904,11 @@ impl FromProof for DataContractHistory verify_tenderdash_proof(proof, mtd, &root_hash, provider)?; - Ok((maybe_history, mtd.clone(), proof.clone())) + Ok(( + maybe_history.map(IndexMap::from_iter), + mtd.clone(), + proof.clone(), + )) } } diff --git a/packages/rs-drive-proof-verifier/src/types.rs b/packages/rs-drive-proof-verifier/src/types.rs index 743034d3f74..1aebc864452 100644 --- a/packages/rs-drive-proof-verifier/src/types.rs +++ b/packages/rs-drive-proof-verifier/src/types.rs @@ -75,12 +75,12 @@ pub type RetrievedObjects = IndexMap>; /// /// * `K`: The type of the keys in the map. /// * `I`: The type of the integer in the map. -pub type RetrievedIntegerValue = BTreeMap; +pub type RetrievedIntegerValue = IndexMap; /// History of a data contract. /// /// Contains a map of data contract revisions to data contracts. -pub type DataContractHistory = BTreeMap; +pub type DataContractHistory = IndexMap; /// Multiple data contracts. /// /// Mapping between data contract IDs and data contracts. @@ -114,14 +114,14 @@ impl Contenders { &self, document_type: &DocumentType, platform_version: &PlatformVersion, - ) -> Result, crate::Error> { + ) -> Result, crate::Error> { self.contenders .iter() .map(|(id, v)| { let contender = v.try_to_contender(document_type.as_ref(), platform_version)?; Ok((*id, contender)) }) - .collect::, dpp::ProtocolError>>() + .collect::, dpp::ProtocolError>>() .map_err(Into::into) } } @@ -450,7 +450,7 @@ impl FromIterator<(u64, Vec)> for VotePollsGroupedByTimestamp { // collect all vote polls for the same timestamp into a single vector let data = iter .into_iter() - .fold(BTreeMap::new(), |mut acc, (timestamp, vote_poll)| { + .fold(IndexMap::new(), |mut acc, (timestamp, vote_poll)| { let entry: &mut Vec = acc.entry(timestamp).or_default(); entry.extend(vote_poll); acc @@ -586,7 +586,7 @@ impl FromIterator<(ProTxHash, Option)> for ProposerBl let identifier = Identifier::from(pro_tx_hash.to_byte_array()); // Adjust this conversion logic as needed (identifier, block_count) }) - .collect::>(); + .collect::>(); ProposerBlockCounts(map) } @@ -604,7 +604,7 @@ impl FromIterator<(ProTxHash, Option)> for ProposerBlock let identifier = Identifier::from(pro_tx_hash.to_byte_array()); // Adjust this conversion logic as needed (identifier, block_count) }) - .collect::>(); + .collect::>(); ProposerBlockCounts(map) } diff --git a/packages/rs-drive-proof-verifier/src/unproved.rs b/packages/rs-drive-proof-verifier/src/unproved.rs index bc2f2e9e512..cc7c63c83ef 100644 --- a/packages/rs-drive-proof-verifier/src/unproved.rs +++ b/packages/rs-drive-proof-verifier/src/unproved.rs @@ -218,7 +218,7 @@ impl FromUnproved for CurrentQuorumsInfo let mut quorum_hash = [0u8; 32]; quorum_hash.copy_from_slice(&vs.quorum_hash); - // Parse ValidatorV0 members into a BTreeMap + // Parse ValidatorV0 members let members = vs .members .into_iter() diff --git a/packages/rs-sdk/src/mock/requests.rs b/packages/rs-sdk/src/mock/requests.rs index c6e84f37dd7..605e5e96217 100644 --- a/packages/rs-sdk/src/mock/requests.rs +++ b/packages/rs-sdk/src/mock/requests.rs @@ -121,7 +121,7 @@ impl MockResponse for IndexMap, Vec>, _) = - bincode::serde::decode_from_slice(buf, BINCODE_CONFIG).expect("decode BTreeMap"); + bincode::serde::decode_from_slice(buf, BINCODE_CONFIG).expect("decode IndexMap"); data.into_iter() .map(|(k, v)| (K::mock_deserialize(sdk, &k), V::mock_deserialize(sdk, &v))) @@ -134,7 +134,7 @@ impl MockResponse for IndexMap Date: Fri, 4 Oct 2024 16:10:53 +0200 Subject: [PATCH 3/6] Update packages/rs-sdk/tests/fetch/contested_resource.rs Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- packages/rs-sdk/tests/fetch/contested_resource.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rs-sdk/tests/fetch/contested_resource.rs b/packages/rs-sdk/tests/fetch/contested_resource.rs index 31134769c88..676e452df20 100644 --- a/packages/rs-sdk/tests/fetch/contested_resource.rs +++ b/packages/rs-sdk/tests/fetch/contested_resource.rs @@ -278,7 +278,7 @@ async fn contested_resources_limit_PLAN_656() { }, Ok("ContestedResources([])".into()); "Non-existing end_index_values returns error")] #[test_case::test_case(|q| q.end_index_values = vec![Value::Array(vec![0.into(), 1.into()])], Err("incorrect index values error: too many end index values were provided"); "wrong type of end_index_values should return InvalidArgument")] #[test_case::test_case(|q| q.limit = Some(0), Err(r#"code: InvalidArgument"#); "limit 0 returns InvalidArgument")] -#[test_case::test_case(|q| q.limit = Some(u16::MAX), Err(r#"code: InvalidArgument"#); "limit std::u16::MAX returns InvalidArgument")] +#[test_case::test_case(|q| q.limit = Some(u16::MAX), Err(r#"code: InvalidArgument"#); "limit u16::MAX returns InvalidArgument")] // Disabled due to bug PLAN-656 // #[test_case::test_case(|q| { // q.start_index_values = vec![Value::Text("dash".to_string())]; From 350bbf8ad9fce5e0041606228046a8a79d082510 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Fri, 4 Oct 2024 16:20:40 +0200 Subject: [PATCH 4/6] chore: apply rabbit feedback --- packages/rs-drive-proof-verifier/src/proof.rs | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/packages/rs-drive-proof-verifier/src/proof.rs b/packages/rs-drive-proof-verifier/src/proof.rs index 6ad4b93f2be..4369feec7b1 100644 --- a/packages/rs-drive-proof-verifier/src/proof.rs +++ b/packages/rs-drive-proof-verifier/src/proof.rs @@ -832,24 +832,17 @@ impl FromProof for DataContracts { })?; verify_tenderdash_proof(proof, mtd, &root_hash, provider)?; - - let maybe_contracts: Option = if !contracts.is_empty() { - let contracts: DataContracts = contracts - .into_iter() - .try_fold(DataContracts::new(), |mut acc, (k, v)| { - Identifier::from_bytes(&k).map(|id| { - acc.insert(id, v); - acc - }) + let maybe_contracts = contracts + .into_iter() + .map(|(k, v)| { + Identifier::from_bytes(&k).map(|id| (id, v)).map_err(|e| { + Error::ResultEncodingError { + error: e.to_string(), + } }) - .map_err(|e| Error::ResultEncodingError { - error: e.to_string(), - })?; - - Some(contracts) - } else { - None - }; + }) + .collect::>()? + .into_option(); Ok((maybe_contracts, mtd.clone(), proof.clone())) } From 050751f86e43b1fce77dc579b0fcdd1796b0e853 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Fri, 4 Oct 2024 20:23:36 +0200 Subject: [PATCH 5/6] chore: apply rabbit review --- packages/rs-drive-proof-verifier/src/types.rs | 40 ++++++++++++------- packages/rs-sdk/src/mock/requests.rs | 6 +-- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/packages/rs-drive-proof-verifier/src/types.rs b/packages/rs-drive-proof-verifier/src/types.rs index 1aebc864452..89b729851ec 100644 --- a/packages/rs-drive-proof-verifier/src/types.rs +++ b/packages/rs-drive-proof-verifier/src/types.rs @@ -51,9 +51,15 @@ pub use evonode_status::*; /// from a server using [`FetchMany`](dash_sdk::platform::FetchMany) or parsing a proof that contains multiple objects /// using [`FromProof`](crate::FromProof). /// -/// Each key in the `RetrievedObjects` corresponds to an object of generic type `O`. -/// If an object is found for a given key, the value is `Some(object)`. -/// If no object is found for a given key, the value is `None`. +/// Each key `K` in the `RetrievedObjects` corresponds to zero or one object of generic type `O`: +/// * if an object is found for a given key, the value is `Some(object)`, +/// * if no object is found for a given key, the value is `None`; this can be interpreted as a proof of absence. +/// +/// This data structure preserves order of objects insertion. However, actual order of objects depends on the order of +/// objects returned by Dash Drive, which is not always guaranteed to be correct. +/// You can sort the objects by key if you need a specific order; see [`IndexMap::sort_keys`] and similar methods. +/// +/// `RetrievedObjects` is a wrapper around the [`IndexMap`] type. /// /// # Generic Type Parameters /// @@ -61,26 +67,32 @@ pub use evonode_status::*; /// * `O`: The type of the objects in the map. pub type RetrievedObjects = IndexMap>; -/// A data structure that holds a set of objects of a generic type `O`, indexed by a key of type `K`. +/// A data structure that holds a set of values of a generic type `I`, indexed by a key of type `K`. /// /// This type is typically returned by functions that operate on multiple objects, such as fetching multiple objects /// from a server using [`FetchMany`](dash_sdk::platform::FetchMany) or parsing a proof that contains multiple objects /// using [`FromProof`](crate::FromProof). /// -/// Each key in the `RetrievedObjects` corresponds to an object of generic type `O`. -/// If a value is found for a given key, the value is `value`. -/// If no value is found for a given key, the value is `0`. +/// Each key in this data structure corresponds to an existing value of generic type `I`. It differs from +/// [`RetrievedObjects`] in that it does not contain `Option`, but only `I`, so it cannot be interpreted as a +/// proof of absence. +/// +/// This data structure preserves the order of object insertion. However, the actual order of objects depends on the +/// order of objects returned by Dash Drive, which is not always guaranteed to be correct. +/// You can sort the objects by key if you need a specific order; see [`IndexMap::sort_keys`] and similar methods. +/// +/// The ordering of the objects is guaranteed to be the same as the order of objects returned by Dash Drive. /// /// # Generic Type Parameters /// /// * `K`: The type of the keys in the map. -/// * `I`: The type of the integer in the map. -pub type RetrievedIntegerValue = IndexMap; +/// * `I`: The type of the integer values in the map. +pub type RetrievedValues = IndexMap; /// History of a data contract. /// /// Contains a map of data contract revisions to data contracts. -pub type DataContractHistory = IndexMap; +pub type DataContractHistory = RetrievedValues; /// Multiple data contracts. /// /// Mapping between data contract IDs and data contracts. @@ -114,14 +126,14 @@ impl Contenders { &self, document_type: &DocumentType, platform_version: &PlatformVersion, - ) -> Result, crate::Error> { + ) -> Result, crate::Error> { self.contenders .iter() .map(|(id, v)| { let contender = v.try_to_contender(document_type.as_ref(), platform_version)?; Ok((*id, contender)) }) - .collect::, dpp::ProtocolError>>() + .collect::, dpp::ProtocolError>>() .map_err(Into::into) } } @@ -450,7 +462,7 @@ impl FromIterator<(u64, Vec)> for VotePollsGroupedByTimestamp { // collect all vote polls for the same timestamp into a single vector let data = iter .into_iter() - .fold(IndexMap::new(), |mut acc, (timestamp, vote_poll)| { + .fold(BTreeMap::new(), |mut acc, (timestamp, vote_poll)| { let entry: &mut Vec = acc.entry(timestamp).or_default(); entry.extend(vote_poll); acc @@ -572,7 +584,7 @@ pub type MasternodeProtocolVotes = RetrievedObjects); +pub struct ProposerBlockCounts(pub RetrievedValues); impl FromIterator<(ProTxHash, Option)> for ProposerBlockCounts { fn from_iter)>>( diff --git a/packages/rs-sdk/src/mock/requests.rs b/packages/rs-sdk/src/mock/requests.rs index 605e5e96217..582c3628a05 100644 --- a/packages/rs-sdk/src/mock/requests.rs +++ b/packages/rs-sdk/src/mock/requests.rs @@ -19,8 +19,8 @@ use drive::grovedb::Element; use drive_proof_verifier::types::{ Contenders, ContestedResources, CurrentQuorumsInfo, ElementFetchRequestItem, EvoNodeStatus, IdentityBalanceAndRevision, IndexMap, MasternodeProtocolVote, PrefundedSpecializedBalance, - ProposerBlockCounts, RetrievedIntegerValue, TotalCreditsInPlatform, - VotePollsGroupedByTimestamp, Voters, + ProposerBlockCounts, RetrievedValues, TotalCreditsInPlatform, VotePollsGroupedByTimestamp, + Voters, }; use std::{collections::BTreeMap, hash::Hash}; @@ -268,7 +268,7 @@ impl MockResponse for ProposerBlockCounts { where Self: Sized, { - let data = RetrievedIntegerValue::::mock_deserialize(sdk, buf); + let data = RetrievedValues::::mock_deserialize(sdk, buf); ProposerBlockCounts(data) } } From 638871882405c3b6dd7d78a71e331acd07c388a8 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Tue, 15 Oct 2024 13:17:25 +0200 Subject: [PATCH 6/6] fix(sdk): into_option() should return Some() for proof of non-existence --- packages/rs-drive-proof-verifier/src/proof.rs | 74 +++++++++++++++---- packages/rs-drive-proof-verifier/src/types.rs | 9 +-- 2 files changed, 62 insertions(+), 21 deletions(-) diff --git a/packages/rs-drive-proof-verifier/src/proof.rs b/packages/rs-drive-proof-verifier/src/proof.rs index e615a9a8f23..3685df1779d 100644 --- a/packages/rs-drive-proof-verifier/src/proof.rs +++ b/packages/rs-drive-proof-verifier/src/proof.rs @@ -832,7 +832,7 @@ impl FromProof for DataContracts { })?; verify_tenderdash_proof(proof, mtd, &root_hash, provider)?; - let maybe_contracts = contracts + let contracts = contracts .into_iter() .map(|(k, v)| { Identifier::from_bytes(&k).map(|id| (id, v)).map_err(|e| { @@ -841,8 +841,13 @@ impl FromProof for DataContracts { } }) }) - .collect::>()? - .into_option(); + .collect::>()?; + + let maybe_contracts = if contracts.is_empty() { + None + } else { + Some(contracts) + }; Ok((maybe_contracts, mtd.clone(), proof.clone())) } @@ -1376,8 +1381,7 @@ impl FromProof for ContestedResources { verify_tenderdash_proof(proof, mtd, &root_hash, provider)?; - let resources: ContestedResources = - items.into_iter().map(|v| ContestedResource(v)).collect(); + let resources: ContestedResources = items.into_iter().map(ContestedResource).collect(); Ok((resources.into_option(), mtd.clone(), proof.clone())) } @@ -1849,6 +1853,8 @@ fn u32_to_u16_opt(i: u32) -> Result, Error> { pub trait Length { /// Return number of non-None elements in the data structure fn count_some(&self) -> usize; + /// Return number of all elements in the data structure, including None + fn count(&self) -> usize; } impl Length for Option { @@ -1858,30 +1864,52 @@ impl Length for Option { Some(i) => i.count_some(), } } + fn count(&self) -> usize { + match self { + None => 0, + Some(i) => i.count(), + } + } } impl Length for Vec> { fn count_some(&self) -> usize { self.iter().filter(|v| v.is_some()).count() } + + fn count(&self) -> usize { + self.len() + } } impl Length for Vec<(K, Option)> { fn count_some(&self) -> usize { self.iter().filter(|(_, v)| v.is_some()).count() } + + fn count(&self) -> usize { + self.len() + } } impl Length for BTreeMap> { fn count_some(&self) -> usize { self.values().filter(|v| v.is_some()).count() } + + fn count(&self) -> usize { + self.len() + } } impl Length for IndexMap> { fn count_some(&self) -> usize { self.values().filter(|v| v.is_some()).count() } + + fn count(&self) -> usize { + self.len() + } } /// Implement Length trait for a type @@ -1891,16 +1919,24 @@ impl Length for IndexMap> { /// * `$object`: The type for which to implement Length trait /// * `$len`: A closure that returns the length of the object; if ommitted, defaults to 1 macro_rules! define_length { - ($object:ty,$len:expr) => { + ($object:ty,$some:expr,$counter:expr) => { impl Length for $object { fn count_some(&self) -> usize { #[allow(clippy::redundant_closure_call)] - $len(self) + $some(self) + } + + fn count(&self) -> usize { + #[allow(clippy::redundant_closure_call)] + $counter(self) } } }; + ($object:ty,$some:expr) => { + define_length!($object, $some, $some); + }; ($object:ty) => { - define_length!($object, |_| 1); + define_length!($object, |_| 1, |_| 1); }; } @@ -1910,22 +1946,30 @@ define_length!(Document); define_length!(Identity); define_length!(IdentityBalance); define_length!(IdentityBalanceAndRevision); -define_length!(IdentitiesContractKeys, |x: &IdentitiesContractKeys| x - .values() - .map(|v| v.count_some()) - .sum()); +define_length!( + IdentitiesContractKeys, + |x: &IdentitiesContractKeys| x.values().map(|v| v.count_some()).sum(), + |x: &IdentitiesContractKeys| x.len() +); define_length!(ContestedResources, |x: &ContestedResources| x.0.len()); define_length!(Contenders, |x: &Contenders| x.contenders.len()); define_length!(Voters, |x: &Voters| x.0.len()); define_length!( VotePollsGroupedByTimestamp, - |x: &VotePollsGroupedByTimestamp| x.0.iter().map(|v| v.1.len()).sum() + |x: &VotePollsGroupedByTimestamp| x.0.iter().map(|v| v.1.len()).sum(), + |x: &VotePollsGroupedByTimestamp| x.0.len() ); + +/// Convert a type into an Option trait IntoOption where Self: Sized, { - /// For zero-length data structures, return None, otherwise return Some(self) + /// For zero-length data structures, return None, otherwise return Some(self). + /// + /// In case of a zero-length data structure, the function returns None. + /// Otherwise, it returns Some(self), even it all values are None. This is to ensure that proof of absence + /// preserves the keys that are not present in the data structure. fn into_option(self) -> Option; } @@ -1934,7 +1978,7 @@ impl IntoOption for L { where Self: Sized, { - if self.count_some() == 0 { + if self.count() == 0 { None } else { Some(self) diff --git a/packages/rs-drive-proof-verifier/src/types.rs b/packages/rs-drive-proof-verifier/src/types.rs index 30a004bec18..40fa528a546 100644 --- a/packages/rs-drive-proof-verifier/src/types.rs +++ b/packages/rs-drive-proof-verifier/src/types.rs @@ -81,8 +81,6 @@ pub type RetrievedObjects = IndexMap>; /// order of objects returned by Dash Drive, which is not always guaranteed to be correct. /// You can sort the objects by key if you need a specific order; see [`IndexMap::sort_keys`] and similar methods. /// -/// The ordering of the objects is guaranteed to be the same as the order of objects returned by Dash Drive. -/// /// # Generic Type Parameters /// /// * `K`: The type of the keys in the map. @@ -254,10 +252,9 @@ impl ContestedResource { ) } } - -impl Into for ContestedResource { - fn into(self) -> Value { - self.0 +impl From for Value { + fn from(resource: ContestedResource) -> Self { + resource.0 } }