From 18369b0b0e01fdb64276be6fc66bf711e10c6758 Mon Sep 17 00:00:00 2001 From: Ayush Mishra Date: Tue, 1 Oct 2024 18:16:00 +0530 Subject: [PATCH] Challenge sub trees and make them ready for payout (#434) ## Description ## Types of Changes Please select the branch type you are merging and fill in the relevant template. - [ ] Hotfix - [ ] Release - [ ] Fix or Feature ## Fix or Feature ### Types of Changes - [ ] Tech Debt (Code improvements) - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Dependency upgrade (A change in substrate or any 3rd party crate version) ### Migrations and Hooks - [ ] This change requires a runtime migration. - [ ] Modifies `on_initialize` - [ ] Modifies `on_finalize` ### Checklist for Fix or Feature - [ ] Change has been tested locally. - [ ] Change adds / updates tests if applicable. - [ ] Changelog doc updated. - [ ] `spec_version` has been incremented. - [ ] `network-relayer`'s [events](https://github.com/Cerebellum-Network/network-relayer/blob/dev-cere/shared/substrate/events.go) have been updated according to the blockchain events if applicable. - [ ] All CI checks have been passed successfully ## Checklist for Hotfix - [ ] Change has been deployed to Testnet. - [ ] Change has been tested in Testnet. - [ ] Changelog has been updated. - [ ] Crate version has been updated. - [ ] `spec_version` has been incremented. - [ ] Transaction version has been updated if required. - [ ] Pull Request to `dev` has been created. - [ ] Pull Request to `staging` has been created. - [ ] `network-relayer`'s [events](https://github.com/Cerebellum-Network/network-relayer/blob/dev-cere/shared/substrate/events.go) have been updated according to the blockchain events if applicable. - [ ] All CI checks have been passed successfully ## Checklist for Release - [ ] Change has been deployed to Devnet. - [ ] Change has been tested in Devnet. - [ ] Change has been deployed to Qanet. - [ ] Change has been tested in Qanet. - [ ] Change has been deployed to Testnet. - [ ] Change has been tested in Testnet. - [ ] Changelog has been updated. - [ ] Crate version has been updated. - [ ] Spec version has been updated. - [ ] Transaction version has been updated if required. - [ ] All CI checks have been passed successfully --- Cargo.lock | 2 + Cargo.toml | 1 + pallets/ddc-verification/Cargo.toml | 3 + pallets/ddc-verification/src/lib.rs | 497 +++++++++++++++++++++++++- pallets/ddc-verification/src/mock.rs | 1 + pallets/ddc-verification/src/tests.rs | 234 +++++++++++- runtime/cere-dev/src/lib.rs | 3 +- runtime/cere/src/lib.rs | 3 +- 8 files changed, 725 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index efb21d6d7..35a6e2fe6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5391,6 +5391,7 @@ name = "pallet-ddc-verification" version = "5.4.1" dependencies = [ "array-bytes", + "base64ct", "ddc-primitives", "frame-benchmarking", "frame-election-provider-support", @@ -5406,6 +5407,7 @@ dependencies = [ "pallet-timestamp", "parity-scale-codec", "polkadot-ckb-merkle-mountain-range", + "rand 0.8.5", "scale-info", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 95bd4e0f9..7a0cdd203 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ resolver = "2" [workspace.dependencies] # 3rd-party dependencies +base64ct = { version = "1.6.0" } blake2 = { version = "0.10.4", default-features = false } byte-unit = { version = "4.0.19", default-features = false, features = ["u128"] } chrono = { version = "0.4.31", default-features = false } diff --git a/pallets/ddc-verification/Cargo.toml b/pallets/ddc-verification/Cargo.toml index 514802392..909237ec7 100644 --- a/pallets/ddc-verification/Cargo.toml +++ b/pallets/ddc-verification/Cargo.toml @@ -10,6 +10,7 @@ repository.workspace = true [dependencies] array-bytes = { workspace = true } +base64ct = { workspace = true } # 3rd-party dependencies codec = { workspace = true } # Cere dependencies @@ -23,6 +24,7 @@ hex = { workspace = true } itertools = { workspace = true } log = { workspace = true } polkadot-ckb-merkle-mountain-range = { workspace = true } +rand = { workspace = true, features = ["small_rng", "alloc"], default-features = false } scale-info = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } @@ -45,6 +47,7 @@ sp-keystore = { workspace = true } [features] default = ["std"] std = [ + "rand/std", "hex/std", "polkadot-ckb-merkle-mountain-range/std", "codec/std", diff --git a/pallets/ddc-verification/src/lib.rs b/pallets/ddc-verification/src/lib.rs index 75af80015..4cec4c46e 100644 --- a/pallets/ddc-verification/src/lib.rs +++ b/pallets/ddc-verification/src/lib.rs @@ -11,6 +11,7 @@ use core::str; +use base64ct::{Base64, Encoding}; use ddc_primitives::{ traits::{ ClusterManager, ClusterValidator, CustomerVisitor, NodeVisitor, PayoutVisitor, @@ -45,6 +46,7 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*}; pub mod weights; use itertools::Itertools; +use rand::{prelude::*, rngs::SmallRng, SeedableRng}; use sp_staking::StakingInterface; use crate::weights::WeightInfo; @@ -68,6 +70,7 @@ pub mod pallet { frame_support::traits::StorageVersion::new(0); const SUCCESS_CODE: u16 = 200; + const BUF_SIZE: usize = 128; const RESPONSE_TIMEOUT: u64 = 20000; #[pallet::pallet] @@ -117,6 +120,7 @@ pub mod pallet { const MIN_DAC_NODES_FOR_CONSENSUS: u16; const MAX_PAYOUT_BATCH_COUNT: u16; const MAX_PAYOUT_BATCH_SIZE: u16; + const MAX_MERKLE_NODE_IDENTIFIER: u16; /// The access to staking functionality. type StakingVisitor: StakingInterface; type AccountIdConverter: From + Into; @@ -167,6 +171,13 @@ pub mod pallet { bucket_id: BucketId, validator: T::AccountId, }, + /// Not enough records for consensus. + NotEnoughRecordsForConsensus { + cluster_id: ClusterId, + era_id: DdcEra, + record_id: String, + validator: T::AccountId, + }, /// No activity in consensus. ActivityNotInConsensus { cluster_id: ClusterId, @@ -318,6 +329,14 @@ pub mod pallet { node_ids: Vec, validator: T::AccountId, }, + ChallengeResponseRetrievalError { + cluster_id: ClusterId, + era_id: DdcEra, + node_id: String, + bucket_id: BucketId, + node_pub_key: NodePubKey, + validator: T::AccountId, + }, } /// Consensus Errors @@ -334,6 +353,11 @@ pub mod pallet { era_id: DdcEra, bucket_id: BucketId, }, + NotEnoughRecordsForConsensus { + cluster_id: ClusterId, + era_id: DdcEra, + record_id: String, + }, /// No activity in consensus. ActivityNotInConsensus { cluster_id: ClusterId, @@ -370,6 +394,14 @@ pub mod pallet { bucket_id: BucketId, node_pub_key: NodePubKey, }, + /// Challenge Response Retrieval Error. + ChallengeResponseRetrievalError { + cluster_id: ClusterId, + era_id: DdcEra, + node_id: String, + bucket_id: BucketId, + node_pub_key: NodePubKey, + }, PrepareEraTransactionError { cluster_id: ClusterId, era_id: DdcEra, @@ -517,6 +549,7 @@ pub mod pallet { #[pallet::storage] #[pallet::getter(fn get_stash_for_ddc_validator)] pub type ValidatorToStashKey = StorageMap<_, Identity, T::AccountId, T::AccountId>; + #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo, PartialEq)] pub enum EraValidationStatus { ValidatingData, @@ -524,6 +557,7 @@ pub mod pallet { PayoutInProgress, PayoutFailed, PayoutSuccess, + PayoutSkipped, } #[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo, PartialEq)] @@ -636,6 +670,99 @@ pub mod pallet { pub(crate) number_of_gets: u64, } + /// Challenge Response + #[derive( + Debug, Serialize, Deserialize, Clone, Hash, Ord, PartialOrd, PartialEq, Eq, Encode, Decode, + )] + pub(crate) struct ChallengeAggregateResponse { + /// proofs + pub proofs: Vec, //todo! add optional fields + } + + #[derive( + Debug, Serialize, Deserialize, Clone, Hash, Ord, PartialOrd, PartialEq, Eq, Encode, Decode, + )] + pub(crate) struct Proof { + pub merkle_tree_node_id: u64, + pub usage: Usage, + pub path: Vec, //todo! add base64 deserialization + pub leafs: Vec, + } + + #[derive( + Debug, Serialize, Deserialize, Clone, Hash, Ord, PartialOrd, PartialEq, Eq, Encode, Decode, + )] + pub(crate) struct Usage { + /// Total amount of stored bytes. + pub stored_bytes: i64, + /// Total amount of transferred bytes. + pub transferred_bytes: u64, + /// Total number of puts. + pub number_of_puts: u64, + /// Total number of gets. + pub number_of_gets: u64, + } + + #[derive( + Debug, Serialize, Deserialize, Clone, Hash, Ord, PartialOrd, PartialEq, Eq, Encode, Decode, + )] + pub(crate) struct Leaf { + pub record: Record, + pub transferred_bytes: u64, + pub stored_bytes: i64, + // todo! add links if there is no record + } + + #[derive( + Debug, Serialize, Deserialize, Clone, Hash, Ord, PartialOrd, PartialEq, Eq, Encode, Decode, + )] + #[allow(non_snake_case)] + pub(crate) struct Record { + pub id: String, + pub upstream: Upstream, + pub downstream: Vec, + pub timestamp: String, + pub signature: Signature, + } + + #[derive( + Debug, Serialize, Deserialize, Clone, Hash, Ord, PartialOrd, PartialEq, Eq, Encode, Decode, + )] + pub(crate) struct Upstream { + pub request: Request, + } + + #[derive( + Debug, Serialize, Deserialize, Clone, Hash, Ord, PartialOrd, PartialEq, Eq, Encode, Decode, + )] + pub(crate) struct Downstream { + pub request: Request, + } + #[derive( + Debug, Serialize, Deserialize, Clone, Hash, Ord, PartialOrd, PartialEq, Eq, Encode, Decode, + )] + #[allow(non_snake_case)] + pub(crate) struct Request { + pub requestId: String, + pub requestType: String, + pub contentType: String, + pub bucketId: String, + pub pieceCid: String, + pub offset: String, + pub size: String, + pub timestamp: String, + pub signature: Signature, + } + + #[derive( + Debug, Serialize, Deserialize, Clone, Hash, Ord, PartialOrd, PartialEq, Eq, Encode, Decode, + )] + pub(crate) struct Signature { + pub algorithm: String, + pub signer: String, + pub value: String, + } + // Define a common trait pub trait Activity: Clone + Ord + PartialEq + Eq + Serialize + for<'de> Deserialize<'de> @@ -705,6 +832,30 @@ pub mod pallet { } } + impl Activity for Leaf { + fn get_consensus_id(&self) -> ActivityHash { + T::ActivityHasher::hash(&self.record.id.encode()).into() + } + + fn hash(&self) -> ActivityHash { + let mut data = self.record.id.encode(); + data.extend_from_slice(&self.record.upstream.request.requestType.encode()); + data.extend_from_slice(&self.stored_bytes.encode()); + data.extend_from_slice(&self.transferred_bytes.encode()); + T::ActivityHasher::hash(&data).into() + } + + fn get_consensus_error(&self, cluster_id: ClusterId, era_id: DdcEra) -> OCWError { + let record_id = &self.record.id; + + OCWError::NotEnoughRecordsForConsensus { + cluster_id, + era_id, + record_id: record_id.clone(), + } + } + } + /// Unwrap or send an error log macro_rules! unwrap_or_log_error { ($result:expr, $error_msg:expr) => { @@ -1342,14 +1493,26 @@ pub mod pallet { Self::fetch_customers_usage_for_era(cluster_id, era_activity.id, dac_nodes) .map_err(|err| vec![err])?; - let (bucket_node_aggregates_in_consensus, _bucket_node_aggregates_not_in_consensus) = + let (bucket_node_aggregates_in_consensus, bucket_node_aggregates_not_in_consensus) = Self::fetch_sub_trees(cluster_id, era_activity.id, customers_usage, min_nodes)?; - let customer_activity_hashes: Vec = bucket_node_aggregates_in_consensus - .clone() - .into_iter() - .map(|c| c.hash::()) - .collect(); + let mut bucket_aggregates_passed_challenges: Vec = vec![]; + + if !bucket_node_aggregates_not_in_consensus.is_empty() { + bucket_aggregates_passed_challenges = + Self::challenge_and_find_valid_sub_aggregates_not_in_consensus( + cluster_id, + era_activity.id, + dac_nodes, + bucket_node_aggregates_not_in_consensus, + )?; + } + + let mut total_bucket_aggregates = bucket_node_aggregates_in_consensus.clone(); + total_bucket_aggregates.extend(bucket_aggregates_passed_challenges); + + let customer_activity_hashes: Vec = + total_bucket_aggregates.clone().into_iter().map(|c| c.hash::()).collect(); let customer_activity_hashes_string: Vec = customer_activity_hashes.clone().into_iter().map(hex::encode).collect(); @@ -1470,6 +1633,203 @@ pub mod pallet { ))) } + pub(crate) fn challenge_and_find_valid_sub_aggregates_not_in_consensus( + cluster_id: &ClusterId, + era_id: DdcEra, + dac_nodes: &[(NodePubKey, StorageNodeParams)], + bucket_node_aggregates_not_in_consensus: Vec, + ) -> Result, Vec> { + let mut bucket_aggregates_passed_challenges: Vec = vec![]; + let mut bucket_aggregates_not_passed_challenges: Vec = + vec![]; + let number_of_identifiers = T::MAX_MERKLE_NODE_IDENTIFIER; + + log::info!( + "πŸš€ Challenge process starts when bucket sub aggregates are not in consensus!" + ); + + for bucket_node_aggregate_activity in bucket_node_aggregates_not_in_consensus { + let merkle_node_ids = Self::find_random_merkle_node_ids( + number_of_identifiers.into(), + bucket_node_aggregate_activity.clone(), + ); + let bucket_id = bucket_node_aggregate_activity.clone().bucket_id; + + log::info!("πŸš€ Merkle Node Identifiers for bucket_node_aggregate_activity: node id: {:?} bucket_id:{:?} identifiers: {:?}", + bucket_node_aggregate_activity.clone().node_id, bucket_id.clone(), merkle_node_ids); + + let challenge_responses = Self::fetch_challenge_responses( + cluster_id, + bucket_node_aggregate_activity.clone().node_id, + era_id, + bucket_id, + merkle_node_ids, + dac_nodes, + ) + .map_err(|err| vec![err])?; + + log::info!("πŸš€ Fetched challenge response node id: {:?} bucket_id:{:?} challenge_response: {:?}", + bucket_node_aggregate_activity.clone().node_id, bucket_id.clone(), challenge_responses); + + let resulting_hash_from_leafs_and_paths = + Self::find_resulting_hash_from_leafs_and_paths( + challenge_responses, + cluster_id, + era_id, + bucket_id, + bucket_node_aggregate_activity.clone().node_id, + )?; + + let root_challenge_responses = Self::fetch_challenge_responses( + cluster_id, + bucket_node_aggregate_activity.clone().node_id, + era_id, + bucket_id, + vec![1], + dac_nodes, + ) + .map_err(|err| vec![err])?; + + log::info!("πŸš€ Fetched Root challenge response node id: {:?} bucket_id:{:?} challenge_response: {:?}", + bucket_node_aggregate_activity.clone().node_id, bucket_id.clone(), root_challenge_responses); + + let merkle_root_hash = Self::find_resulting_hash_from_leafs_and_paths( + root_challenge_responses, + cluster_id, + era_id, + bucket_id, + bucket_node_aggregate_activity.clone().node_id, + )?; + + if resulting_hash_from_leafs_and_paths == merkle_root_hash { + log::info!( + "πŸš€πŸ‘ The node id: {:?} with bucket_id:{:?} has passed the challenge. The activity detail is {:?}", + bucket_node_aggregate_activity.clone().node_id, + bucket_id, + bucket_node_aggregate_activity + ); + + bucket_aggregates_passed_challenges.push(bucket_node_aggregate_activity); + } else { + log::info!( + "πŸš€πŸ‘Ž The node id: {:?} with bucket_id:{:?} has not passed the challenge. The activity detail is {:?}", + bucket_node_aggregate_activity.clone().node_id, + bucket_id, + bucket_node_aggregate_activity + ); + + bucket_aggregates_not_passed_challenges.push(bucket_node_aggregate_activity); + } + } + + let mut data_grouped = Vec::new(); + for (key, chunk) in + &bucket_aggregates_passed_challenges.into_iter().chunk_by(|elt| elt.bucket_id) + { + data_grouped.push((key, chunk.collect())); + } + + Ok(Self::fetch_valid_aggregates_passed_challenges(data_grouped)) + } + + pub(crate) fn fetch_valid_aggregates_passed_challenges( + bucket_aggregates_passed_challenges: Vec<(BucketId, Vec)>, + ) -> Vec { + let mut valid_aggregates_passed_challenges: Vec = vec![]; + + for (bucket_id, bucket_aggregates_passed_challenge_activities) in + bucket_aggregates_passed_challenges + { + let valid_activities = + bucket_aggregates_passed_challenge_activities.iter().cloned().max_by_key( + |activity| activity.transferred_bytes as i64 + activity.stored_bytes, + ); + + if let Some(activity) = valid_activities { + log::info!( + "πŸš€β›³οΈ The activity bucket_id:{:?} with maximum usage, which has passed the challenge. The activity detail is {:?}", + bucket_id, + activity + ); + valid_aggregates_passed_challenges.push(activity); + } + } + valid_aggregates_passed_challenges + } + + pub(crate) fn find_resulting_hash_from_leafs_and_paths( + challenge_responses: Vec, + cluster_id: &ClusterId, + era_id: DdcEra, + bucket_id: BucketId, + node_id: String, + ) -> Result> { + let mut resulting_hash_from_leafs_and_paths = ActivityHash::default(); + + for challenge_response in challenge_responses { + for proof in challenge_response.proofs { + let leaf_record_hashes: Vec = + proof.leafs.into_iter().map(|p| p.hash::()).collect(); + + let leaf_record_hashes_string: Vec = + leaf_record_hashes.clone().into_iter().map(hex::encode).collect(); + + log::info!("πŸš€ Fetched leaf record hashes node id: {:?} bucket_id:{:?} leaf_record_hashes: {:?}", + node_id, bucket_id.clone(), leaf_record_hashes_string); + + let leaf_node_root = + Self::create_merkle_root(cluster_id, era_id, &leaf_record_hashes) + .map_err(|err| vec![err])?; + + log::info!("πŸš€ Fetched leaf record root node id: {:?} bucket_id:{:?} leaf_record_root_hash: {:?}", + node_id, bucket_id.clone(), hex::encode(leaf_node_root)); + + let paths = proof.path.iter().rev(); + + resulting_hash_from_leafs_and_paths = leaf_node_root; + for path in paths { + let mut dec_buf = [0u8; BUF_SIZE]; + let bytes = Base64::decode(path, &mut dec_buf).unwrap(); // todo! remove unwrap + let path_hash: ActivityHash = + ActivityHash::from(sp_core::H256::from_slice(bytes)); + + let node_root = Self::create_merkle_root( + cluster_id, + era_id, + &[resulting_hash_from_leafs_and_paths, path_hash], + ) + .map_err(|err| vec![err])?; + + log::info!("πŸš€ Fetched leaf node root node id: {:?} bucket_id:{:?} for path:{:?} leaf_node_hash: {:?}", + node_id, bucket_id, path, hex::encode(node_root)); + + resulting_hash_from_leafs_and_paths = node_root; + } + } + } + + Ok(resulting_hash_from_leafs_and_paths) + } + pub(crate) fn find_random_merkle_node_ids( + number_of_identifiers: usize, + bucket_node_aggregates_activity: BucketNodeAggregatesActivity, + ) -> Vec { + let total_activity = bucket_node_aggregates_activity.number_of_puts + + bucket_node_aggregates_activity.number_of_gets; + let total_levels = total_activity.ilog2() + 1; + + let int_list: Vec = (0..total_levels as u64).collect(); + + let nonce = Self::store_and_fetch_nonce(bucket_node_aggregates_activity.node_id); + + let mut small_rng = SmallRng::seed_from_u64(nonce); + let ids: Vec = int_list + .choose_multiple(&mut small_rng, number_of_identifiers) + .cloned() + .collect::>(); + + ids + } pub(crate) fn fetch_sub_trees( cluster_id: &ClusterId, era_id: DdcEra, @@ -2188,6 +2548,25 @@ pub mod pallet { } } + pub(crate) fn store_and_fetch_nonce(node_id: String) -> u64 { + let key = format!("offchain::activities::nonce::{:?}", node_id).into_bytes(); + let encoded_nonce = sp_io::offchain::local_storage_get(StorageKind::PERSISTENT, &key) + .unwrap_or_else(|| 0.encode()); + + let nonce_data = match Decode::decode(&mut &encoded_nonce[..]) { + Ok(nonce) => nonce, + Err(err) => { + // Print error message with details of the decoding error + log::error!("πŸ¦€Decoding error while fetching nonce: {:?}", err); + 0 + }, + }; + + let new_nonce = nonce_data + 1; + + sp_io::offchain::local_storage_set(StorageKind::PERSISTENT, &key, &new_nonce.encode()); + nonce_data + } pub(crate) fn store_provider_id( // todo! (3) add tests node_id: String, @@ -2626,6 +3005,86 @@ pub mod pallet { Self::cluster_to_validate().ok_or(Error::ClusterToValidateRetrievalError) } + /// Fetch customer usage for an era. + /// + /// Parameters: + /// - `cluster_id`: cluster id of a cluster + /// - `era_id`: era id + /// - `node_params`: DAC node parameters + pub(crate) fn fetch_challenge_responses( + cluster_id: &ClusterId, + node_id: String, + era_id: DdcEra, + bucket_id: BucketId, + merkle_node_identifiers: Vec, + dac_nodes: &[(NodePubKey, StorageNodeParams)], + ) -> Result, OCWError> { + let mut challenge_responses = Vec::new(); + + for (node_pub_key, node_params) in dac_nodes { + // todo! probably shouldn't stop when some DAC is not responding as we can still + // work with others + let response = Self::fetch_challenge_response( + node_id.clone(), + era_id, + bucket_id, + merkle_node_identifiers.clone(), + node_params, + ) + .map_err(|_| OCWError::ChallengeResponseRetrievalError { + cluster_id: *cluster_id, + era_id, + node_id: node_id.clone(), + bucket_id, + node_pub_key: node_pub_key.clone(), + })?; + + challenge_responses.push(response); + } + + Ok(challenge_responses) + } + /// Fetch challenge response. + /// + /// Parameters: + /// - `cluster_id`: cluster id of a cluster + /// - `era_id`: era id + /// - `node_params`: DAC node parameters + pub(crate) fn fetch_challenge_response( + node_id: String, + era_id: DdcEra, + bucket_id: BucketId, + merkle_node_identifiers: Vec, + node_params: &StorageNodeParams, + ) -> Result { + let scheme = "http"; + let host = str::from_utf8(&node_params.host).map_err(|_| http::Error::Unknown)?; + + let result = merkle_node_identifiers + .iter() + .map(|x| format!("{}", x.clone())) + .collect::>() + .join(","); + + let url = format!( + "{}://{}:{}/activity/buckets/{}/challenge?eraId={}&nodeId={}&merkleTreeNodeId={}", + scheme, host, node_params.http_port, bucket_id, era_id, node_id, result + ); + + let request = http::Request::get(&url); + let timeout = sp_io::offchain::timestamp() + .add(sp_runtime::offchain::Duration::from_millis(RESPONSE_TIMEOUT)); + let pending = request.deadline(timeout).send().map_err(|_| http::Error::IoError)?; + + let response = + pending.try_wait(timeout).map_err(|_| http::Error::DeadlineReached)??; + if response.code != SUCCESS_CODE { + return Err(http::Error::Unknown); + } + + let body = response.body().collect::>(); + serde_json::from_slice(&body).map_err(|_| http::Error::Unknown) + } /// Fetch processed era. /// /// Parameters: @@ -3214,6 +3673,30 @@ pub mod pallet { validator: caller.clone(), }); }, + OCWError::ChallengeResponseRetrievalError { + cluster_id, + era_id, + node_id, + bucket_id, + node_pub_key, + } => { + Self::deposit_event(Event::ChallengeResponseRetrievalError { + cluster_id, + era_id, + node_id, + bucket_id, + node_pub_key, + validator: caller.clone(), + }); + }, + OCWError::NotEnoughRecordsForConsensus { cluster_id, era_id, record_id } => { + Self::deposit_event(Event::NotEnoughRecordsForConsensus { + cluster_id, + era_id, + record_id, + validator: caller.clone(), + }); + }, } } @@ -3437,7 +3920,7 @@ pub mod pallet { start_era: Default::default(), end_era: Default::default(), validators: Default::default(), - status: EraValidationStatus::PayoutSuccess, + status: EraValidationStatus::PayoutSkipped, }; let signed_validators = era_validation diff --git a/pallets/ddc-verification/src/mock.rs b/pallets/ddc-verification/src/mock.rs index 4166c2fa5..6b9fc3c69 100644 --- a/pallets/ddc-verification/src/mock.rs +++ b/pallets/ddc-verification/src/mock.rs @@ -233,6 +233,7 @@ impl crate::Config for Test { type StakingVisitor = Staking; type AccountIdConverter = AccountId; type CustomerVisitor = MockCustomerVisitor; + const MAX_MERKLE_NODE_IDENTIFIER: u16 = 4; } pub struct MockCustomerVisitor; diff --git a/pallets/ddc-verification/src/tests.rs b/pallets/ddc-verification/src/tests.rs index 32b83b78e..65e787516 100644 --- a/pallets/ddc-verification/src/tests.rs +++ b/pallets/ddc-verification/src/tests.rs @@ -2098,7 +2098,6 @@ fn test_single_ocw_pallet_integration() { ..Default::default() }; - offchain_state.expect_request(pending_request1); offchain_state.expect_request(pending_request2); offchain_state.expect_request(pending_request3); @@ -2253,7 +2252,6 @@ fn test_bucket_node_aggregates() { ..Default::default() }; - offchain_state.expect_request(pending_request1); offchain_state.expect_request(pending_request2); offchain_state.expect_request(pending_request3); @@ -2312,15 +2310,11 @@ fn test_bucket_node_aggregates() { ]; let customers_usage = - DdcVerification::fetch_customers_usage_for_era(&cluster_id, era_id, &dac_nodes).unwrap(); - + DdcVerification::fetch_customers_usage_for_era(&cluster_id, era_id, &dac_nodes) + .unwrap(); - let result = DdcVerification::fetch_sub_trees( - &cluster_id, - era_id, - customers_usage, - min_nodes, - ); + let result = + DdcVerification::fetch_sub_trees(&cluster_id, era_id, customers_usage, min_nodes); assert!(result.is_ok()); // Sub_aggregates which are in consensus @@ -2371,3 +2365,223 @@ fn test_bucket_node_aggregates() { ); }); } + +#[test] +fn test_find_random_merkle_node_ids() { + let mut ext = TestExternalities::default(); + let (offchain, _offchain_state) = TestOffchainExt::new(); + let (pool, _) = TestTransactionPoolExt::new(); + + ext.register_extension(OffchainWorkerExt::new(offchain.clone())); + ext.register_extension(OffchainDbExt::new(Box::new(offchain))); + ext.register_extension(TransactionPoolExt::new(pool)); + + ext.execute_with(|| { + let bucket_node_aggregates_not_in_consensus: BucketNodeAggregatesActivity = + BucketNodeAggregatesActivity { + bucket_id: 90235, + node_id: "0xb6186f80dce7190294665ab53860de2841383bb202c562bb8b81a624351fa319" + .to_string(), + stored_bytes: 0, + transferred_bytes: 505, + number_of_puts: 12, + number_of_gets: 13, + }; + + let total_activities = bucket_node_aggregates_not_in_consensus.number_of_gets + + bucket_node_aggregates_not_in_consensus.number_of_puts; + + let ids = DdcVerification::find_random_merkle_node_ids( + 3, + bucket_node_aggregates_not_in_consensus.clone(), + ); + for id in ids { + assert!(id < total_activities); + } + }); +} + +#[test] +fn test_challenge_sub_aggregates_not_in_consensus() { + let mut ext = new_test_ext(); + let (offchain, offchain_state) = TestOffchainExt::new(); + let (pool, _pool_state) = TestTransactionPoolExt::new(); + + let (pair, _seed) = sp_core::sr25519::Pair::from_phrase( + "spider sell nice animal border success square soda stem charge caution echo", + None, + ) + .unwrap(); + let keystore = MemoryKeystore::new(); + keystore + .insert( + KEY_TYPE, + "0xb6186f80dce7190294665ab53860de2841383bb202c562bb8b81a624351fa318", + pair.public().as_ref(), + ) + .unwrap(); + + ext.register_extension(OffchainWorkerExt::new(offchain.clone())); + ext.register_extension(OffchainDbExt::new(offchain)); + ext.register_extension(TransactionPoolExt::new(pool)); + ext.register_extension(KeystoreExt::new(keystore)); + + ext.execute_with(|| { + let mut offchain_state = offchain_state.write(); + let key = format!("offchain::validator::{:?}", KEY_TYPE).into_bytes(); + offchain_state.persistent_storage.set( + b"", + &key, + b"9ef98ad9c3626ba725e78d76cfcfc4b4d07e84f0388465bc7eb992e3e117234a".as_ref(), + ); + offchain_state.timestamp = Timestamp::from_unix_millis(0); + let host1 = "178.251.228.236"; + let host2 = "95.217.8.119"; + let host3 = "178.251.228.42"; + let host4 = "37.27.30.47"; + + let port = 8080; + + //todo! put them in resource file + let pending_request1 = PendingRequest { + method: "GET".to_string(), + uri: format!("http://{}:{}/activity/buckets/123229/challenge?eraId=5757773&nodeId=0x1f50f1455f60f5774564233d321a116ca45ae3188b2200999445706d04839d72&merkleTreeNodeId=0,2,1,3", host1, port), + response: Some(br#"{"proofs":[{"merkle_tree_node_id":3,"usage":{"stored_bytes":2097152,"transferred_bytes":1048576,"number_of_puts":1,"number_of_gets":1},"path":["hFnZfjnS5bAzgm5tHcWTxuJa5waDcaiU7OhBRofylhQ="],"leafs":[{"record":{"id":"17Z3vSjjRm6mWN3Swpw3Cw==","upstream":{"request":{"requestId":"e9920157-6c6a-485e-9f5a-1685ea6d4ef5","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_PIECE","bucketId":"1","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"0","timestamp":"1727346880632","signature":{"algorithm":"ED_25519","signer":"iNw0F9UFjsS0UD4MEuoaCom+IA/piSJCPUM0AU+msO4=","value":"KPDnQH5KZZQ2hksJ8F/w3GHwWloAm1QKoLt+SuUNYt3HxsGrh3r3q77COiu0jrwQ7mEsp/FFJp4pDp2Y1j2sDA=="}}},"downstream":[{"request":{"requestId":"a5bcaa37-97a4-45d2-beb9-c11cc955fb78","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_MERKLE_TREE","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"0","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"ulpjaksvopDDRRfYnrccUg5spkoRpfZlDARbjgfL4Y/X4HZNUp2cL5qQMHUosREB6PSMXr9rQvXYGA9kmrUBDg=="}}},{"request":{"requestId":"8af9ba14-4c49-438c-957d-d1a108a58b85","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_SEGMENT","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"524288","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"CLdw3HaQWVWdDHeog2SZjiEA4NZN6PD8vyw58JuQI7gMDpDXLFslMOcI7p/uNEyeDfNoKTAgNZpWbNR4vSZ/AA=="}}},{"request":{"requestId":"b3dc8833-d5aa-4e33-9afa-54584da29cda","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_SEGMENT","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"524288","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"5XTnDU/85DqWWpMy1kGRVK6ZHe/EYDeg2p07UbFnIr6xLX7n50k9MslwuF8jMl2/QoBrPnndHdCd5ssqV90kDg=="}}}],"timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"8WWGHaL3n8+bkuYQhTua3l+i3W//XXhlnzCpQ7VJ/BmfXQPFGEjIZsXw0kKr4+VXh/kWAncF3VrvW9nEi6G2CQ=="}},"transferred_bytes":1048576,"stored_bytes":0},{"record":{"id":"8Rg6VlRrSE65NsCY02OnlA==","upstream":{"request":{"requestId":"aacf30c4-b2e9-4f37-826d-0016c280f39b","requestType":"REQUEST_TYPE_PUT","contentType":"CONTENT_TYPE_METADATA","bucketId":"0","pieceCid":"AAAAAAAAAAEBAh4gaLfPG3AA1QwNFQc3VvJYsMAINAN6mMkvo5vk5HP8g/0=","offset":"0","size":"385","timestamp":"1727346880673","signature":{"algorithm":"ED_25519","signer":"xHUfclv0KTLyCz1NjsLAdMrEBfKdlta130WiEBvB14s=","value":"yPZt7Fyfp1aiJL+hYOg5rRtPPTNDMZwgReX2RX4bWbP8+ivreh1cNvSwnM5ln0EFqxTn53iVQpZeMWXUSiJeCw=="}}},"downstream":[],"timestamp":"1727346880673","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"zX0aGW/FuhddMAtGvN4Gjf6P1JaFGasrwf5yCrQPFv4qUB1GyACynb1s1+Mv0zpMAGOtIOcwaemoPu4fnOByBA=="}},"transferred_bytes":1048576,"stored_bytes":1048576}]}]}"#.to_vec()), + sent: true, + ..Default::default() + }; + + let pending_request2 = PendingRequest { + method: "GET".to_string(), + uri: format!("http://{}:{}/activity/buckets/123229/challenge?eraId=5757773&nodeId=0x1f50f1455f60f5774564233d321a116ca45ae3188b2200999445706d04839d72&merkleTreeNodeId=0,2,1,3", host2, port), + response: Some(br#"{"proofs":[{"merkle_tree_node_id":3,"usage":{"stored_bytes":2097152,"transferred_bytes":1048576,"number_of_puts":1,"number_of_gets":1},"path":["hFnZfjnS5bAzgm5tHcWTxuJa5waDcaiU7OhBRofylhQ="],"leafs":[{"record":{"id":"17Z3vSjjRm6mWN3Swpw3Cw==","upstream":{"request":{"requestId":"e9920157-6c6a-485e-9f5a-1685ea6d4ef5","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_PIECE","bucketId":"1","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"0","timestamp":"1727346880632","signature":{"algorithm":"ED_25519","signer":"iNw0F9UFjsS0UD4MEuoaCom+IA/piSJCPUM0AU+msO4=","value":"KPDnQH5KZZQ2hksJ8F/w3GHwWloAm1QKoLt+SuUNYt3HxsGrh3r3q77COiu0jrwQ7mEsp/FFJp4pDp2Y1j2sDA=="}}},"downstream":[{"request":{"requestId":"a5bcaa37-97a4-45d2-beb9-c11cc955fb78","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_MERKLE_TREE","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"0","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"ulpjaksvopDDRRfYnrccUg5spkoRpfZlDARbjgfL4Y/X4HZNUp2cL5qQMHUosREB6PSMXr9rQvXYGA9kmrUBDg=="}}},{"request":{"requestId":"8af9ba14-4c49-438c-957d-d1a108a58b85","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_SEGMENT","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"524288","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"CLdw3HaQWVWdDHeog2SZjiEA4NZN6PD8vyw58JuQI7gMDpDXLFslMOcI7p/uNEyeDfNoKTAgNZpWbNR4vSZ/AA=="}}},{"request":{"requestId":"b3dc8833-d5aa-4e33-9afa-54584da29cda","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_SEGMENT","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"524288","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"5XTnDU/85DqWWpMy1kGRVK6ZHe/EYDeg2p07UbFnIr6xLX7n50k9MslwuF8jMl2/QoBrPnndHdCd5ssqV90kDg=="}}}],"timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"8WWGHaL3n8+bkuYQhTua3l+i3W//XXhlnzCpQ7VJ/BmfXQPFGEjIZsXw0kKr4+VXh/kWAncF3VrvW9nEi6G2CQ=="}},"transferred_bytes":1048576,"stored_bytes":0},{"record":{"id":"8Rg6VlRrSE65NsCY02OnlA==","upstream":{"request":{"requestId":"aacf30c4-b2e9-4f37-826d-0016c280f39b","requestType":"REQUEST_TYPE_PUT","contentType":"CONTENT_TYPE_METADATA","bucketId":"0","pieceCid":"AAAAAAAAAAEBAh4gaLfPG3AA1QwNFQc3VvJYsMAINAN6mMkvo5vk5HP8g/0=","offset":"0","size":"385","timestamp":"1727346880673","signature":{"algorithm":"ED_25519","signer":"xHUfclv0KTLyCz1NjsLAdMrEBfKdlta130WiEBvB14s=","value":"yPZt7Fyfp1aiJL+hYOg5rRtPPTNDMZwgReX2RX4bWbP8+ivreh1cNvSwnM5ln0EFqxTn53iVQpZeMWXUSiJeCw=="}}},"downstream":[],"timestamp":"1727346880673","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"zX0aGW/FuhddMAtGvN4Gjf6P1JaFGasrwf5yCrQPFv4qUB1GyACynb1s1+Mv0zpMAGOtIOcwaemoPu4fnOByBA=="}},"transferred_bytes":1048576,"stored_bytes":1048576}]}]}"#.to_vec()), + sent: true, + ..Default::default() + }; + + let pending_request3 = PendingRequest { + method: "GET".to_string(), + uri: format!("http://{}:{}/activity/buckets/123229/challenge?eraId=5757773&nodeId=0x1f50f1455f60f5774564233d321a116ca45ae3188b2200999445706d04839d72&merkleTreeNodeId=0,2,1,3", host3, port), + response: Some(br#"{"proofs":[{"merkle_tree_node_id":3,"usage":{"stored_bytes":2097152,"transferred_bytes":1048576,"number_of_puts":1,"number_of_gets":1},"path":["hFnZfjnS5bAzgm5tHcWTxuJa5waDcaiU7OhBRofylhQ="],"leafs":[{"record":{"id":"17Z3vSjjRm6mWN3Swpw3Cw==","upstream":{"request":{"requestId":"e9920157-6c6a-485e-9f5a-1685ea6d4ef5","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_PIECE","bucketId":"1","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"0","timestamp":"1727346880632","signature":{"algorithm":"ED_25519","signer":"iNw0F9UFjsS0UD4MEuoaCom+IA/piSJCPUM0AU+msO4=","value":"KPDnQH5KZZQ2hksJ8F/w3GHwWloAm1QKoLt+SuUNYt3HxsGrh3r3q77COiu0jrwQ7mEsp/FFJp4pDp2Y1j2sDA=="}}},"downstream":[{"request":{"requestId":"a5bcaa37-97a4-45d2-beb9-c11cc955fb78","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_MERKLE_TREE","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"0","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"ulpjaksvopDDRRfYnrccUg5spkoRpfZlDARbjgfL4Y/X4HZNUp2cL5qQMHUosREB6PSMXr9rQvXYGA9kmrUBDg=="}}},{"request":{"requestId":"8af9ba14-4c49-438c-957d-d1a108a58b85","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_SEGMENT","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"524288","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"CLdw3HaQWVWdDHeog2SZjiEA4NZN6PD8vyw58JuQI7gMDpDXLFslMOcI7p/uNEyeDfNoKTAgNZpWbNR4vSZ/AA=="}}},{"request":{"requestId":"b3dc8833-d5aa-4e33-9afa-54584da29cda","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_SEGMENT","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"524288","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"5XTnDU/85DqWWpMy1kGRVK6ZHe/EYDeg2p07UbFnIr6xLX7n50k9MslwuF8jMl2/QoBrPnndHdCd5ssqV90kDg=="}}}],"timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"8WWGHaL3n8+bkuYQhTua3l+i3W//XXhlnzCpQ7VJ/BmfXQPFGEjIZsXw0kKr4+VXh/kWAncF3VrvW9nEi6G2CQ=="}},"transferred_bytes":1048576,"stored_bytes":0},{"record":{"id":"8Rg6VlRrSE65NsCY02OnlA==","upstream":{"request":{"requestId":"aacf30c4-b2e9-4f37-826d-0016c280f39b","requestType":"REQUEST_TYPE_PUT","contentType":"CONTENT_TYPE_METADATA","bucketId":"0","pieceCid":"AAAAAAAAAAEBAh4gaLfPG3AA1QwNFQc3VvJYsMAINAN6mMkvo5vk5HP8g/0=","offset":"0","size":"385","timestamp":"1727346880673","signature":{"algorithm":"ED_25519","signer":"xHUfclv0KTLyCz1NjsLAdMrEBfKdlta130WiEBvB14s=","value":"yPZt7Fyfp1aiJL+hYOg5rRtPPTNDMZwgReX2RX4bWbP8+ivreh1cNvSwnM5ln0EFqxTn53iVQpZeMWXUSiJeCw=="}}},"downstream":[],"timestamp":"1727346880673","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"zX0aGW/FuhddMAtGvN4Gjf6P1JaFGasrwf5yCrQPFv4qUB1GyACynb1s1+Mv0zpMAGOtIOcwaemoPu4fnOByBA=="}},"transferred_bytes":1048576,"stored_bytes":1048576}]}]}"#.to_vec()), + sent: true, + ..Default::default() + }; + + let pending_request4 = PendingRequest { + method: "GET".to_string(), + uri: format!("http://{}:{}/activity/buckets/123229/challenge?eraId=5757773&nodeId=0x1f50f1455f60f5774564233d321a116ca45ae3188b2200999445706d04839d72&merkleTreeNodeId=0,2,1,3", host4, port), + response: Some(br#"{"proofs":[{"merkle_tree_node_id":3,"usage":{"stored_bytes":2097152,"transferred_bytes":1048576,"number_of_puts":1,"number_of_gets":1},"path":["hFnZfjnS5bAzgm5tHcWTxuJa5waDcaiU7OhBRofylhQ="],"leafs":[{"record":{"id":"17Z3vSjjRm6mWN3Swpw3Cw==","upstream":{"request":{"requestId":"e9920157-6c6a-485e-9f5a-1685ea6d4ef5","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_PIECE","bucketId":"1","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"0","timestamp":"1727346880632","signature":{"algorithm":"ED_25519","signer":"iNw0F9UFjsS0UD4MEuoaCom+IA/piSJCPUM0AU+msO4=","value":"KPDnQH5KZZQ2hksJ8F/w3GHwWloAm1QKoLt+SuUNYt3HxsGrh3r3q77COiu0jrwQ7mEsp/FFJp4pDp2Y1j2sDA=="}}},"downstream":[{"request":{"requestId":"a5bcaa37-97a4-45d2-beb9-c11cc955fb78","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_MERKLE_TREE","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"0","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"ulpjaksvopDDRRfYnrccUg5spkoRpfZlDARbjgfL4Y/X4HZNUp2cL5qQMHUosREB6PSMXr9rQvXYGA9kmrUBDg=="}}},{"request":{"requestId":"8af9ba14-4c49-438c-957d-d1a108a58b85","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_SEGMENT","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"524288","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"CLdw3HaQWVWdDHeog2SZjiEA4NZN6PD8vyw58JuQI7gMDpDXLFslMOcI7p/uNEyeDfNoKTAgNZpWbNR4vSZ/AA=="}}},{"request":{"requestId":"b3dc8833-d5aa-4e33-9afa-54584da29cda","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_SEGMENT","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"524288","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"5XTnDU/85DqWWpMy1kGRVK6ZHe/EYDeg2p07UbFnIr6xLX7n50k9MslwuF8jMl2/QoBrPnndHdCd5ssqV90kDg=="}}}],"timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"8WWGHaL3n8+bkuYQhTua3l+i3W//XXhlnzCpQ7VJ/BmfXQPFGEjIZsXw0kKr4+VXh/kWAncF3VrvW9nEi6G2CQ=="}},"transferred_bytes":1048576,"stored_bytes":0},{"record":{"id":"8Rg6VlRrSE65NsCY02OnlA==","upstream":{"request":{"requestId":"aacf30c4-b2e9-4f37-826d-0016c280f39b","requestType":"REQUEST_TYPE_PUT","contentType":"CONTENT_TYPE_METADATA","bucketId":"0","pieceCid":"AAAAAAAAAAEBAh4gaLfPG3AA1QwNFQc3VvJYsMAINAN6mMkvo5vk5HP8g/0=","offset":"0","size":"385","timestamp":"1727346880673","signature":{"algorithm":"ED_25519","signer":"xHUfclv0KTLyCz1NjsLAdMrEBfKdlta130WiEBvB14s=","value":"yPZt7Fyfp1aiJL+hYOg5rRtPPTNDMZwgReX2RX4bWbP8+ivreh1cNvSwnM5ln0EFqxTn53iVQpZeMWXUSiJeCw=="}}},"downstream":[],"timestamp":"1727346880673","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"zX0aGW/FuhddMAtGvN4Gjf6P1JaFGasrwf5yCrQPFv4qUB1GyACynb1s1+Mv0zpMAGOtIOcwaemoPu4fnOByBA=="}},"transferred_bytes":1048576,"stored_bytes":1048576}]}]}"#.to_vec()), + sent: true, + ..Default::default() + }; + + let pending_request5 = PendingRequest { + method: "GET".to_string(), + uri: format!("http://{}:{}/activity/buckets/123229/challenge?eraId=5757773&nodeId=0x1f50f1455f60f5774564233d321a116ca45ae3188b2200999445706d04839d72&merkleTreeNodeId=1", host1, port), + response: Some(br#"{"proofs":[{"merkle_tree_node_id":3,"usage":{"stored_bytes":2097152,"transferred_bytes":1048576,"number_of_puts":1,"number_of_gets":1},"path":["hFnZfjnS5bAzgm5tHcWTxuJa5waDcaiU7OhBRofylhQ="],"leafs":[{"record":{"id":"17Z3vSjjRm6mWN3Swpw3Cw==","upstream":{"request":{"requestId":"e9920157-6c6a-485e-9f5a-1685ea6d4ef5","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_PIECE","bucketId":"1","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"0","timestamp":"1727346880632","signature":{"algorithm":"ED_25519","signer":"iNw0F9UFjsS0UD4MEuoaCom+IA/piSJCPUM0AU+msO4=","value":"KPDnQH5KZZQ2hksJ8F/w3GHwWloAm1QKoLt+SuUNYt3HxsGrh3r3q77COiu0jrwQ7mEsp/FFJp4pDp2Y1j2sDA=="}}},"downstream":[{"request":{"requestId":"a5bcaa37-97a4-45d2-beb9-c11cc955fb78","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_MERKLE_TREE","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"0","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"ulpjaksvopDDRRfYnrccUg5spkoRpfZlDARbjgfL4Y/X4HZNUp2cL5qQMHUosREB6PSMXr9rQvXYGA9kmrUBDg=="}}},{"request":{"requestId":"8af9ba14-4c49-438c-957d-d1a108a58b85","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_SEGMENT","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"524288","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"CLdw3HaQWVWdDHeog2SZjiEA4NZN6PD8vyw58JuQI7gMDpDXLFslMOcI7p/uNEyeDfNoKTAgNZpWbNR4vSZ/AA=="}}},{"request":{"requestId":"b3dc8833-d5aa-4e33-9afa-54584da29cda","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_SEGMENT","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"524288","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"5XTnDU/85DqWWpMy1kGRVK6ZHe/EYDeg2p07UbFnIr6xLX7n50k9MslwuF8jMl2/QoBrPnndHdCd5ssqV90kDg=="}}}],"timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"8WWGHaL3n8+bkuYQhTua3l+i3W//XXhlnzCpQ7VJ/BmfXQPFGEjIZsXw0kKr4+VXh/kWAncF3VrvW9nEi6G2CQ=="}},"transferred_bytes":1048576,"stored_bytes":0},{"record":{"id":"8Rg6VlRrSE65NsCY02OnlA==","upstream":{"request":{"requestId":"aacf30c4-b2e9-4f37-826d-0016c280f39b","requestType":"REQUEST_TYPE_PUT","contentType":"CONTENT_TYPE_METADATA","bucketId":"0","pieceCid":"AAAAAAAAAAEBAh4gaLfPG3AA1QwNFQc3VvJYsMAINAN6mMkvo5vk5HP8g/0=","offset":"0","size":"385","timestamp":"1727346880673","signature":{"algorithm":"ED_25519","signer":"xHUfclv0KTLyCz1NjsLAdMrEBfKdlta130WiEBvB14s=","value":"yPZt7Fyfp1aiJL+hYOg5rRtPPTNDMZwgReX2RX4bWbP8+ivreh1cNvSwnM5ln0EFqxTn53iVQpZeMWXUSiJeCw=="}}},"downstream":[],"timestamp":"1727346880673","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"zX0aGW/FuhddMAtGvN4Gjf6P1JaFGasrwf5yCrQPFv4qUB1GyACynb1s1+Mv0zpMAGOtIOcwaemoPu4fnOByBA=="}},"transferred_bytes":1048576,"stored_bytes":1048576}]}]}"#.to_vec()), + sent: true, + ..Default::default() + }; + + let pending_request6 = PendingRequest { + method: "GET".to_string(), + uri: format!("http://{}:{}/activity/buckets/123229/challenge?eraId=5757773&nodeId=0x1f50f1455f60f5774564233d321a116ca45ae3188b2200999445706d04839d72&merkleTreeNodeId=1", host2, port), + response: Some(br#"{"proofs":[{"merkle_tree_node_id":3,"usage":{"stored_bytes":2097152,"transferred_bytes":1048576,"number_of_puts":1,"number_of_gets":1},"path":["hFnZfjnS5bAzgm5tHcWTxuJa5waDcaiU7OhBRofylhQ="],"leafs":[{"record":{"id":"17Z3vSjjRm6mWN3Swpw3Cw==","upstream":{"request":{"requestId":"e9920157-6c6a-485e-9f5a-1685ea6d4ef5","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_PIECE","bucketId":"1","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"0","timestamp":"1727346880632","signature":{"algorithm":"ED_25519","signer":"iNw0F9UFjsS0UD4MEuoaCom+IA/piSJCPUM0AU+msO4=","value":"KPDnQH5KZZQ2hksJ8F/w3GHwWloAm1QKoLt+SuUNYt3HxsGrh3r3q77COiu0jrwQ7mEsp/FFJp4pDp2Y1j2sDA=="}}},"downstream":[{"request":{"requestId":"a5bcaa37-97a4-45d2-beb9-c11cc955fb78","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_MERKLE_TREE","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"0","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"ulpjaksvopDDRRfYnrccUg5spkoRpfZlDARbjgfL4Y/X4HZNUp2cL5qQMHUosREB6PSMXr9rQvXYGA9kmrUBDg=="}}},{"request":{"requestId":"8af9ba14-4c49-438c-957d-d1a108a58b85","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_SEGMENT","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"524288","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"CLdw3HaQWVWdDHeog2SZjiEA4NZN6PD8vyw58JuQI7gMDpDXLFslMOcI7p/uNEyeDfNoKTAgNZpWbNR4vSZ/AA=="}}},{"request":{"requestId":"b3dc8833-d5aa-4e33-9afa-54584da29cda","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_SEGMENT","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"524288","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"5XTnDU/85DqWWpMy1kGRVK6ZHe/EYDeg2p07UbFnIr6xLX7n50k9MslwuF8jMl2/QoBrPnndHdCd5ssqV90kDg=="}}}],"timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"8WWGHaL3n8+bkuYQhTua3l+i3W//XXhlnzCpQ7VJ/BmfXQPFGEjIZsXw0kKr4+VXh/kWAncF3VrvW9nEi6G2CQ=="}},"transferred_bytes":1048576,"stored_bytes":0},{"record":{"id":"8Rg6VlRrSE65NsCY02OnlA==","upstream":{"request":{"requestId":"aacf30c4-b2e9-4f37-826d-0016c280f39b","requestType":"REQUEST_TYPE_PUT","contentType":"CONTENT_TYPE_METADATA","bucketId":"0","pieceCid":"AAAAAAAAAAEBAh4gaLfPG3AA1QwNFQc3VvJYsMAINAN6mMkvo5vk5HP8g/0=","offset":"0","size":"385","timestamp":"1727346880673","signature":{"algorithm":"ED_25519","signer":"xHUfclv0KTLyCz1NjsLAdMrEBfKdlta130WiEBvB14s=","value":"yPZt7Fyfp1aiJL+hYOg5rRtPPTNDMZwgReX2RX4bWbP8+ivreh1cNvSwnM5ln0EFqxTn53iVQpZeMWXUSiJeCw=="}}},"downstream":[],"timestamp":"1727346880673","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"zX0aGW/FuhddMAtGvN4Gjf6P1JaFGasrwf5yCrQPFv4qUB1GyACynb1s1+Mv0zpMAGOtIOcwaemoPu4fnOByBA=="}},"transferred_bytes":1048576,"stored_bytes":1048576}]}]}"#.to_vec()), + sent: true, + ..Default::default() + }; + + let pending_request7 = PendingRequest { + method: "GET".to_string(), + uri: format!("http://{}:{}/activity/buckets/123229/challenge?eraId=5757773&nodeId=0x1f50f1455f60f5774564233d321a116ca45ae3188b2200999445706d04839d72&merkleTreeNodeId=1", host3, port), + response: Some(br#"{"proofs":[{"merkle_tree_node_id":3,"usage":{"stored_bytes":2097152,"transferred_bytes":1048576,"number_of_puts":1,"number_of_gets":1},"path":["hFnZfjnS5bAzgm5tHcWTxuJa5waDcaiU7OhBRofylhQ="],"leafs":[{"record":{"id":"17Z3vSjjRm6mWN3Swpw3Cw==","upstream":{"request":{"requestId":"e9920157-6c6a-485e-9f5a-1685ea6d4ef5","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_PIECE","bucketId":"1","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"0","timestamp":"1727346880632","signature":{"algorithm":"ED_25519","signer":"iNw0F9UFjsS0UD4MEuoaCom+IA/piSJCPUM0AU+msO4=","value":"KPDnQH5KZZQ2hksJ8F/w3GHwWloAm1QKoLt+SuUNYt3HxsGrh3r3q77COiu0jrwQ7mEsp/FFJp4pDp2Y1j2sDA=="}}},"downstream":[{"request":{"requestId":"a5bcaa37-97a4-45d2-beb9-c11cc955fb78","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_MERKLE_TREE","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"0","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"ulpjaksvopDDRRfYnrccUg5spkoRpfZlDARbjgfL4Y/X4HZNUp2cL5qQMHUosREB6PSMXr9rQvXYGA9kmrUBDg=="}}},{"request":{"requestId":"8af9ba14-4c49-438c-957d-d1a108a58b85","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_SEGMENT","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"524288","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"CLdw3HaQWVWdDHeog2SZjiEA4NZN6PD8vyw58JuQI7gMDpDXLFslMOcI7p/uNEyeDfNoKTAgNZpWbNR4vSZ/AA=="}}},{"request":{"requestId":"b3dc8833-d5aa-4e33-9afa-54584da29cda","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_SEGMENT","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"524288","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"5XTnDU/85DqWWpMy1kGRVK6ZHe/EYDeg2p07UbFnIr6xLX7n50k9MslwuF8jMl2/QoBrPnndHdCd5ssqV90kDg=="}}}],"timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"8WWGHaL3n8+bkuYQhTua3l+i3W//XXhlnzCpQ7VJ/BmfXQPFGEjIZsXw0kKr4+VXh/kWAncF3VrvW9nEi6G2CQ=="}},"transferred_bytes":1048576,"stored_bytes":0},{"record":{"id":"8Rg6VlRrSE65NsCY02OnlA==","upstream":{"request":{"requestId":"aacf30c4-b2e9-4f37-826d-0016c280f39b","requestType":"REQUEST_TYPE_PUT","contentType":"CONTENT_TYPE_METADATA","bucketId":"0","pieceCid":"AAAAAAAAAAEBAh4gaLfPG3AA1QwNFQc3VvJYsMAINAN6mMkvo5vk5HP8g/0=","offset":"0","size":"385","timestamp":"1727346880673","signature":{"algorithm":"ED_25519","signer":"xHUfclv0KTLyCz1NjsLAdMrEBfKdlta130WiEBvB14s=","value":"yPZt7Fyfp1aiJL+hYOg5rRtPPTNDMZwgReX2RX4bWbP8+ivreh1cNvSwnM5ln0EFqxTn53iVQpZeMWXUSiJeCw=="}}},"downstream":[],"timestamp":"1727346880673","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"zX0aGW/FuhddMAtGvN4Gjf6P1JaFGasrwf5yCrQPFv4qUB1GyACynb1s1+Mv0zpMAGOtIOcwaemoPu4fnOByBA=="}},"transferred_bytes":1048576,"stored_bytes":1048576}]}]}"#.to_vec()), + sent: true, + ..Default::default() + }; + + let pending_request8 = PendingRequest { + method: "GET".to_string(), + uri: format!("http://{}:{}/activity/buckets/123229/challenge?eraId=5757773&nodeId=0x1f50f1455f60f5774564233d321a116ca45ae3188b2200999445706d04839d72&merkleTreeNodeId=1", host4, port), + response: Some(br#"{"proofs":[{"merkle_tree_node_id":3,"usage":{"stored_bytes":2097152,"transferred_bytes":1048576,"number_of_puts":1,"number_of_gets":1},"path":["hFnZfjnS5bAzgm5tHcWTxuJa5waDcaiU7OhBRofylhQ="],"leafs":[{"record":{"id":"17Z3vSjjRm6mWN3Swpw3Cw==","upstream":{"request":{"requestId":"e9920157-6c6a-485e-9f5a-1685ea6d4ef5","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_PIECE","bucketId":"1","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"0","timestamp":"1727346880632","signature":{"algorithm":"ED_25519","signer":"iNw0F9UFjsS0UD4MEuoaCom+IA/piSJCPUM0AU+msO4=","value":"KPDnQH5KZZQ2hksJ8F/w3GHwWloAm1QKoLt+SuUNYt3HxsGrh3r3q77COiu0jrwQ7mEsp/FFJp4pDp2Y1j2sDA=="}}},"downstream":[{"request":{"requestId":"a5bcaa37-97a4-45d2-beb9-c11cc955fb78","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_MERKLE_TREE","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"0","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"ulpjaksvopDDRRfYnrccUg5spkoRpfZlDARbjgfL4Y/X4HZNUp2cL5qQMHUosREB6PSMXr9rQvXYGA9kmrUBDg=="}}},{"request":{"requestId":"8af9ba14-4c49-438c-957d-d1a108a58b85","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_SEGMENT","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"524288","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"CLdw3HaQWVWdDHeog2SZjiEA4NZN6PD8vyw58JuQI7gMDpDXLFslMOcI7p/uNEyeDfNoKTAgNZpWbNR4vSZ/AA=="}}},{"request":{"requestId":"b3dc8833-d5aa-4e33-9afa-54584da29cda","requestType":"REQUEST_TYPE_GET","contentType":"CONTENT_TYPE_SEGMENT","bucketId":"0","pieceCid":"AQIeIKLbs3OibO5qbLJ/PLCo1m02oFHWCl4s7S59GWgxDUbk","offset":"0","size":"524288","timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"5XTnDU/85DqWWpMy1kGRVK6ZHe/EYDeg2p07UbFnIr6xLX7n50k9MslwuF8jMl2/QoBrPnndHdCd5ssqV90kDg=="}}}],"timestamp":"1727346880633","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"8WWGHaL3n8+bkuYQhTua3l+i3W//XXhlnzCpQ7VJ/BmfXQPFGEjIZsXw0kKr4+VXh/kWAncF3VrvW9nEi6G2CQ=="}},"transferred_bytes":1048576,"stored_bytes":0},{"record":{"id":"8Rg6VlRrSE65NsCY02OnlA==","upstream":{"request":{"requestId":"aacf30c4-b2e9-4f37-826d-0016c280f39b","requestType":"REQUEST_TYPE_PUT","contentType":"CONTENT_TYPE_METADATA","bucketId":"0","pieceCid":"AAAAAAAAAAEBAh4gaLfPG3AA1QwNFQc3VvJYsMAINAN6mMkvo5vk5HP8g/0=","offset":"0","size":"385","timestamp":"1727346880673","signature":{"algorithm":"ED_25519","signer":"xHUfclv0KTLyCz1NjsLAdMrEBfKdlta130WiEBvB14s=","value":"yPZt7Fyfp1aiJL+hYOg5rRtPPTNDMZwgReX2RX4bWbP8+ivreh1cNvSwnM5ln0EFqxTn53iVQpZeMWXUSiJeCw=="}}},"downstream":[],"timestamp":"1727346880673","signature":{"algorithm":"ED_25519","signer":"CsfLnFNZTp9TjZlQxrzyjwwMe4OF3uouviQGK8ZA574=","value":"zX0aGW/FuhddMAtGvN4Gjf6P1JaFGasrwf5yCrQPFv4qUB1GyACynb1s1+Mv0zpMAGOtIOcwaemoPu4fnOByBA=="}},"transferred_bytes":1048576,"stored_bytes":1048576}]}]}"#.to_vec()), + sent: true, + ..Default::default() + }; + + offchain_state.expect_request(pending_request1); + offchain_state.expect_request(pending_request2); + offchain_state.expect_request(pending_request3); + offchain_state.expect_request(pending_request4); + offchain_state.expect_request(pending_request5); + offchain_state.expect_request(pending_request6); + offchain_state.expect_request(pending_request7); + offchain_state.expect_request(pending_request8); + drop(offchain_state); + + let cluster_id = ClusterId::from([1; 20]); + let era_id = 5757773; + + let node_params1 = StorageNodeParams { + ssl: false, + host: host1.as_bytes().to_vec(), + http_port: port, + mode: StorageNodeMode::DAC, + p2p_port: 5555, + grpc_port: 4444, + domain: b"example2.com".to_vec(), + }; + + let node_params2 = StorageNodeParams { + ssl: false, + host: host2.as_bytes().to_vec(), + http_port: port, + mode: StorageNodeMode::DAC, + p2p_port: 5555, + grpc_port: 4444, + domain: b"example3.com".to_vec(), + }; + + let node_params3 = StorageNodeParams { + ssl: false, + host: host3.as_bytes().to_vec(), + http_port: port, + mode: StorageNodeMode::DAC, + p2p_port: 5555, + grpc_port: 4444, + domain: b"example4.com".to_vec(), + }; + + let node_params4 = StorageNodeParams { + ssl: false, + host: host4.as_bytes().to_vec(), + http_port: port, + mode: StorageNodeMode::DAC, + p2p_port: 5555, + grpc_port: 4444, + domain: b"example5.com".to_vec(), + }; + + let dac_nodes: Vec<(NodePubKey, StorageNodeParams)> = vec![ + (NodePubKey::StoragePubKey(StorageNodePubKey::new([1; 32])), node_params1), + (NodePubKey::StoragePubKey(StorageNodePubKey::new([2; 32])), node_params2), + (NodePubKey::StoragePubKey(StorageNodePubKey::new([3; 32])), node_params3), + (NodePubKey::StoragePubKey(StorageNodePubKey::new([4; 32])), node_params4), + ]; + + let bucket_node_aggregates_not_in_consensus: Vec = + vec![BucketNodeAggregatesActivity { + bucket_id: 123229, + node_id: "0x1f50f1455f60f5774564233d321a116ca45ae3188b2200999445706d04839d72" + .to_string(), + stored_bytes: 0, + transferred_bytes: 25143977, + number_of_puts: 0, + number_of_gets: 10, + }]; + + let result = + DdcVerification::challenge_and_find_valid_sub_aggregates_not_in_consensus(&cluster_id, era_id, &dac_nodes, bucket_node_aggregates_not_in_consensus); + + assert!(result.is_ok()); + + }); +} diff --git a/runtime/cere-dev/src/lib.rs b/runtime/cere-dev/src/lib.rs index bd87fcece..db1e01a09 100644 --- a/runtime/cere-dev/src/lib.rs +++ b/runtime/cere-dev/src/lib.rs @@ -149,7 +149,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to 0. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 54126, + spec_version: 54127, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 19, @@ -1315,6 +1315,7 @@ impl pallet_ddc_verification::Config for Runtime { type StakingVisitor = pallet_staking::Pallet; type AccountIdConverter = AccountId32; type CustomerVisitor = pallet_ddc_customers::Pallet; + const MAX_MERKLE_NODE_IDENTIFIER: u16 = 3; } construct_runtime!( diff --git a/runtime/cere/src/lib.rs b/runtime/cere/src/lib.rs index bb4875a5a..7470590f1 100644 --- a/runtime/cere/src/lib.rs +++ b/runtime/cere/src/lib.rs @@ -143,7 +143,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // and set impl_version to 0. If only runtime // implementation changes and behavior does not, then leave spec_version as // is and increment impl_version. - spec_version: 54126, + spec_version: 54127, impl_version: 0, apis: RUNTIME_API_VERSIONS, transaction_version: 19, @@ -1323,6 +1323,7 @@ impl pallet_ddc_verification::Config for Runtime { type StakingVisitor = pallet_staking::Pallet; type AccountIdConverter = AccountId32; type CustomerVisitor = pallet_ddc_customers::Pallet; + const MAX_MERKLE_NODE_IDENTIFIER: u16 = 3; } construct_runtime!(