diff --git a/packages/rs-drive-abci/src/query/mod.rs b/packages/rs-drive-abci/src/query/mod.rs index 65734caa79c..509a1815c1a 100644 --- a/packages/rs-drive-abci/src/query/mod.rs +++ b/packages/rs-drive-abci/src/query/mod.rs @@ -1883,6 +1883,7 @@ mod tests { use drive::drive::protocol_upgrade::{ desired_version_for_validators_path, versions_counter_path, versions_counter_path_vec, }; + use drive::drive::Drive; use drive::grovedb::{Element, PathQuery, Query, QueryItem}; use drive::query::GroveDb; use integer_encoding::VarInt; @@ -2211,6 +2212,13 @@ mod tests { .0; assert_eq!(count, 1); + + let upgrade = Drive::verify_upgrade_state(proof.grovedb_proof.as_slice(), version) + .expect("expected to verify the upgrade counts") + .1; + + assert_eq!(upgrade.len(), 1); + assert_eq!(upgrade.get(&1), Some(1).as_ref()); } } @@ -2229,6 +2237,7 @@ mod tests { desired_version_for_validators_path, desired_version_for_validators_path_vec, versions_counter_path, }; + use drive::drive::Drive; use drive::grovedb::{Element, PathQuery, Query, QueryItem, SizedQuery}; use drive::query::GroveDb; use integer_encoding::VarInt; @@ -2588,6 +2597,18 @@ mod tests { .0; assert_eq!(count, 1); + + let upgrade = Drive::verify_upgrade_vote_status( + proof.grovedb_proof.as_slice(), + Some(validator_pro_tx_hash), + 5, + version, + ) + .expect("expected to verify the upgrade counts") + .1; + + assert_eq!(upgrade.len(), 1); + assert_eq!(upgrade.get(&validator_pro_tx_hash), Some(1).as_ref()); } } diff --git a/packages/rs-drive/src/drive/verify/system/mod.rs b/packages/rs-drive/src/drive/verify/system/mod.rs index 96c266a8d5a..f9b5d162451 100644 --- a/packages/rs-drive/src/drive/verify/system/mod.rs +++ b/packages/rs-drive/src/drive/verify/system/mod.rs @@ -1 +1,3 @@ mod verify_epoch_infos; +mod verify_upgrade_state; +mod verify_upgrade_vote_status; diff --git a/packages/rs-drive/src/drive/verify/system/verify_upgrade_state/mod.rs b/packages/rs-drive/src/drive/verify/system/verify_upgrade_state/mod.rs new file mode 100644 index 00000000000..7c0838ef5c9 --- /dev/null +++ b/packages/rs-drive/src/drive/verify/system/verify_upgrade_state/mod.rs @@ -0,0 +1,51 @@ +use crate::drive::verify::RootHash; +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use dpp::block::epoch::EpochIndex; +use dpp::block::extended_epoch_info::ExtendedEpochInfo; +use dpp::util::deserializer::ProtocolVersion; +use dpp::version::PlatformVersion; +use nohash_hasher::IntMap; + +mod v0; + +impl Drive { + /// Verifies a proof containing the current upgrade state. + /// + /// # Parameters + /// + /// - `proof`: A byte slice representing the proof to be verified. + /// - `platform_version`: the platform version, + /// + /// # Returns + /// + /// Returns a `Result` with a tuple of `RootHash` and `Vec`. The `Vec` + /// represents verified epoch information if it exists. + /// + /// # Errors + /// + /// Returns an `Error` if: + /// + /// - The proof is corrupted. + /// - The GroveDb query fails. + pub fn verify_upgrade_state( + proof: &[u8], + platform_version: &PlatformVersion, + ) -> Result<(RootHash, IntMap), Error> { + match platform_version + .drive + .methods + .verify + .system + .verify_upgrade_state + { + 0 => Drive::verify_upgrade_state_v0(proof), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_upgrade_state".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/verify/system/verify_upgrade_state/v0/mod.rs b/packages/rs-drive/src/drive/verify/system/verify_upgrade_state/v0/mod.rs new file mode 100644 index 00000000000..6f109c1d897 --- /dev/null +++ b/packages/rs-drive/src/drive/verify/system/verify_upgrade_state/v0/mod.rs @@ -0,0 +1,62 @@ +use crate::drive::protocol_upgrade::versions_counter_path_vec; +use crate::drive::verify::RootHash; +use crate::drive::Drive; +use crate::error::proof::ProofError; +use crate::error::Error; +use crate::query::{Query, QueryItem}; +use dpp::util::deserializer::ProtocolVersion; +use grovedb::{GroveDb, PathQuery}; +use integer_encoding::VarInt; +use nohash_hasher::IntMap; +use std::ops::RangeFull; +impl Drive { + /// Verifies a proof containing the current upgrade state. + /// + /// # Parameters + /// + /// - `proof`: A byte slice representing the proof to be verified. + /// - `platform_version`: the platform version, + /// + /// # Returns + /// + /// Returns a `Result` with a tuple of `RootHash` and `IntMap`. The `IntMap` + /// represents vote count of each version in the current epoch. + /// + /// # Errors + /// + /// Returns an `Error` if: + /// + /// - The proof is corrupted. + /// - The GroveDb query fails. + pub(super) fn verify_upgrade_state_v0( + proof: &[u8], + ) -> Result<(RootHash, IntMap), Error> { + let path_query = PathQuery::new_unsized( + versions_counter_path_vec(), + Query::new_single_query_item(QueryItem::RangeFull(RangeFull)), + ); + + let (root_hash, elements) = GroveDb::verify_query(proof, &path_query)?; + + let protocol_version_map = elements + .into_iter() + .map(|(_, key, element)| { + let version = ProtocolVersion::decode_var(key.as_slice()) + .ok_or(ProofError::CorruptedProof("protocol version not decodable"))? + .0; + let element = element.ok_or(ProofError::CorruptedProof( + "expected a count for each version, got none", + ))?; + let count_bytes = element.as_item_bytes().map_err(|_| { + ProofError::CorruptedProof("expected an item for the element of a version") + })?; + let count = u64::decode_var(count_bytes) + .ok_or(ProofError::CorruptedProof("version count not decodable"))? + .0; + Ok((version, count)) + }) + .collect::, Error>>()?; + + Ok((root_hash, protocol_version_map)) + } +} diff --git a/packages/rs-drive/src/drive/verify/system/verify_upgrade_vote_status/mod.rs b/packages/rs-drive/src/drive/verify/system/verify_upgrade_vote_status/mod.rs new file mode 100644 index 00000000000..1a6c3e6295c --- /dev/null +++ b/packages/rs-drive/src/drive/verify/system/verify_upgrade_vote_status/mod.rs @@ -0,0 +1,53 @@ +mod v0; + +use crate::drive::verify::RootHash; +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use dpp::util::deserializer::ProtocolVersion; +use dpp::version::PlatformVersion; +use std::collections::BTreeMap; + +impl Drive { + /// Verifies a proof containing potentially multiple epoch infos. + /// + /// # Parameters + /// + /// - `proof`: A byte slice representing the proof to be verified. + /// - `first_pro_tx_hash`: the first pro tx hash that we are querying for. + /// - `count`: the amount of Evonodes that we want to retrieve. + /// - `platform_version`: the platform version, + /// + /// # Returns + /// + /// Returns a `Result` with a tuple of `RootHash` and `BTreeMap<[u8;32], ProtocolVersion>`. The `BTreeMap<[u8;32], ProtocolVersion>` + /// represents a map of the version that each Evonode has voted for. + /// + /// # Errors + /// + /// Returns an `Error` if: + /// + /// - The proof is corrupted. + /// - The GroveDb query fails. + pub fn verify_upgrade_vote_status( + proof: &[u8], + start_protx_hash: Option<[u8; 32]>, + count: u16, + platform_version: &PlatformVersion, + ) -> Result<(RootHash, BTreeMap<[u8; 32], ProtocolVersion>), Error> { + match platform_version + .drive + .methods + .verify + .system + .verify_upgrade_vote_status + { + 0 => Drive::verify_upgrade_vote_status_v0(proof, start_protx_hash, count), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "verify_upgrade_vote_status".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/verify/system/verify_upgrade_vote_status/v0/mod.rs b/packages/rs-drive/src/drive/verify/system/verify_upgrade_vote_status/v0/mod.rs new file mode 100644 index 00000000000..e5e4c01a073 --- /dev/null +++ b/packages/rs-drive/src/drive/verify/system/verify_upgrade_vote_status/v0/mod.rs @@ -0,0 +1,75 @@ +use crate::drive::protocol_upgrade::{ + desired_version_for_validators_path_vec, versions_counter_path_vec, +}; +use crate::drive::verify::RootHash; +use crate::drive::Drive; +use crate::error::proof::ProofError; +use crate::error::Error; +use crate::query::{Query, QueryItem}; +use dpp::util::deserializer::ProtocolVersion; +use grovedb::{GroveDb, PathQuery, SizedQuery}; +use integer_encoding::VarInt; +use std::collections::BTreeMap; +use std::ops::RangeFull; +impl Drive { + /// Verifies a proof containing the current upgrade state. + /// + /// # Parameters + /// + /// - `proof`: A byte slice representing the proof to be verified. + /// - `first_pro_tx_hash`: the first pro tx hash that we are querying for. + /// - `count`: the amount of Evonodes that we want to retrieve. + /// + /// # Returns + /// + /// Returns a `Result` with a tuple of `RootHash` and `BTreeMap<[u8;32], ProtocolVersion>`. The `BTreeMap<[u8;32], ProtocolVersion>` + /// represents a map of the version that each Evonode has voted for. + /// + /// # Errors + /// + /// Returns an `Error` if: + /// + /// - The proof is corrupted. + /// - The GroveDb query fails. + pub(super) fn verify_upgrade_vote_status_v0( + proof: &[u8], + start_protx_hash: Option<[u8; 32]>, + count: u16, + ) -> Result<(RootHash, BTreeMap<[u8; 32], ProtocolVersion>), Error> { + let path = desired_version_for_validators_path_vec(); + + let query_item = if let Some(start_protx_hash) = start_protx_hash { + QueryItem::RangeFrom(start_protx_hash.to_vec()..) + } else { + QueryItem::RangeFull(RangeFull) + }; + + let path_query = PathQuery::new( + path, + SizedQuery::new(Query::new_single_query_item(query_item), Some(count), None), + ); + + let (root_hash, elements) = GroveDb::verify_query(proof, &path_query)?; + + let protocol_version_map = elements + .into_iter() + .map(|(_, key, element)| { + let pro_tx_hash: [u8; 32] = key + .try_into() + .map_err(|_| ProofError::CorruptedProof("protocol version not decodable"))?; + let element = element.ok_or(ProofError::CorruptedProof( + "expected a count for each version, got none", + ))?; + let version_bytes = element.as_item_bytes().map_err(|_| { + ProofError::CorruptedProof("expected an item for the element of a version") + })?; + let version = u32::decode_var(version_bytes) + .ok_or(ProofError::CorruptedProof("version count not decodable"))? + .0; + Ok((pro_tx_hash, version)) + }) + .collect::, Error>>()?; + + Ok((root_hash, protocol_version_map)) + } +} diff --git a/packages/rs-platform-version/src/version/drive_versions.rs b/packages/rs-platform-version/src/version/drive_versions.rs index 5c4b0d4e11c..eb8d6f7da77 100644 --- a/packages/rs-platform-version/src/version/drive_versions.rs +++ b/packages/rs-platform-version/src/version/drive_versions.rs @@ -91,6 +91,8 @@ pub struct DriveVerifyIdentityMethodVersions { #[derive(Clone, Debug, Default)] pub struct DriveVerifySystemMethodVersions { pub verify_epoch_infos: FeatureVersion, + pub verify_upgrade_state: FeatureVersion, + pub verify_upgrade_vote_status: FeatureVersion, } #[derive(Clone, Debug, Default)] diff --git a/packages/rs-platform-version/src/version/mocks/v2_test.rs b/packages/rs-platform-version/src/version/mocks/v2_test.rs index 1e5c701fe3a..59f7cbeac8d 100644 --- a/packages/rs-platform-version/src/version/mocks/v2_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v2_test.rs @@ -252,6 +252,8 @@ pub(crate) const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { }, system: DriveVerifySystemMethodVersions { verify_epoch_infos: 0, + verify_upgrade_state: 0, + verify_upgrade_vote_status: 0, }, }, identity: DriveIdentityMethodVersions { diff --git a/packages/rs-platform-version/src/version/mocks/v3_test.rs b/packages/rs-platform-version/src/version/mocks/v3_test.rs index b6c1fa4a561..aa1c08fbd18 100644 --- a/packages/rs-platform-version/src/version/mocks/v3_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v3_test.rs @@ -260,6 +260,8 @@ pub(crate) const TEST_PLATFORM_V3: PlatformVersion = PlatformVersion { }, system: DriveVerifySystemMethodVersions { verify_epoch_infos: 0, + verify_upgrade_state: 0, + verify_upgrade_vote_status: 0, }, }, identity: DriveIdentityMethodVersions { diff --git a/packages/rs-platform-version/src/version/v1.rs b/packages/rs-platform-version/src/version/v1.rs index 40428e1dadf..dfb11af8acb 100644 --- a/packages/rs-platform-version/src/version/v1.rs +++ b/packages/rs-platform-version/src/version/v1.rs @@ -249,6 +249,8 @@ pub(super) const PLATFORM_V1: PlatformVersion = PlatformVersion { }, system: DriveVerifySystemMethodVersions { verify_epoch_infos: 0, + verify_upgrade_state: 0, + verify_upgrade_vote_status: 0, }, }, identity: DriveIdentityMethodVersions {