diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs index 07a3058b46..7c5d1a1ed1 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs @@ -9,8 +9,8 @@ use crate::platform_types::validator_set::ValidatorSet; use crate::rpc::core::CoreRPCLike; use dpp::dashcore::QuorumHash; -use std::cmp::Ordering; use std::collections::BTreeMap; +use tracing::Level; impl Platform where @@ -33,51 +33,58 @@ where core_block_height: u32, start_from_scratch: bool, ) -> Result<(), Error> { - if !start_from_scratch && core_block_height == block_platform_state.core_height() { + let _span = tracing::span!(Level::TRACE, "update_quorum_info", core_block_height).entered(); + + if start_from_scratch { + tracing::debug!("update quorum info from scratch up to {core_block_height}"); + } else if core_block_height != block_platform_state.core_height() { tracing::debug!( - method = "update_quorum_info_v0", - "no update quorum at height {}", + previous_core_block_height = block_platform_state.core_height(), + "update quorum info from {} to {}", + block_platform_state.core_height(), core_block_height ); + } else { + tracing::debug!("quorum info at height {core_block_height} already updated"); + return Ok(()); // no need to do anything } - tracing::debug!( - method = "update_quorum_info_v0", - "update of quorums for height {}", - core_block_height - ); - let quorum_list = self + + let all_quorums_by_type = self .core_rpc - .get_quorum_listextended(Some(core_block_height))?; - let quorum_info = quorum_list - .quorums_by_type - .get(&self.config.quorum_type()) - .ok_or(Error::Execution(ExecutionError::DashCoreBadResponseError( - format!( - "expected quorums of type {}, but did not receive any from Dash Core", - self.config.quorum_type - ), - )))?; - - tracing::debug!( - method = "update_quorum_info_v0", - "old {:?}", - block_platform_state.validator_sets() - ); - - tracing::debug!( - method = "update_quorum_info_v0", - "new quorum_info {:?}", - quorum_info - ); + .get_quorum_listextended_by_type(Some(core_block_height))?; + + let validator_quorums_list = + all_quorums_by_type + .get(&self.config.quorum_type()) + .ok_or(Error::Execution(ExecutionError::DashCoreBadResponseError( + format!( + "expected quorums of type {}, but did not receive any from Dash Core", + self.config.quorum_type + ), + )))?; // Remove validator_sets entries that are no longer valid for the core block height block_platform_state .validator_sets_mut() - .retain(|key, _| quorum_info.contains_key(key)); + .retain(|quorum_hash, _| { + let has_quorum = validator_quorums_list.contains_key::(quorum_hash); - // Fetch quorum info results and their keys from the RPC - let mut quorum_infos = quorum_info + if has_quorum { + tracing::trace!( + ?quorum_hash, + quorum_type = ?self.config.quorum_type(), + "remove validator set {} with quorum type {}", + quorum_hash, + self.config.quorum_type() + ) + } + + has_quorum + }); + + // Fetch quorum info and their keys from the RPC for new quorums + let mut quorum_infos = validator_quorums_list .iter() .filter(|(key, _)| { !block_platform_state @@ -88,6 +95,7 @@ where let quorum_info_result = self.core_rpc .get_quorum_info(self.config.quorum_type(), key, None)?; + Ok((*key, quorum_info_result)) }) .collect::, Error>>()?; @@ -102,27 +110,39 @@ where } }); - // Map to quorums - let new_quorums = quorum_infos + // Map to validator sets + let new_validator_sets = quorum_infos .into_iter() - .map(|(key, info_result)| { + .map(|(quorum_hash, info_result)| { let validator_set = ValidatorSet::V0(ValidatorSetV0::try_from_quorum_info_result( info_result, block_platform_state, )?); - Ok((key, validator_set)) + + tracing::trace!( + ?validator_set, + ?quorum_hash, + quorum_type = ?self.config.quorum_type(), + "add new validator set {} with quorum type {}", + quorum_hash, + self.config.quorum_type() + ); + + Ok((quorum_hash, validator_set)) }) .collect::, Error>>()?; + // Add new validator_sets entries block_platform_state .validator_sets_mut() - .extend(new_quorums.into_iter()); + .extend(new_validator_sets); + // Sort all validator sets into deterministic order by core block height of creation block_platform_state .validator_sets_mut() .sort_by(|_, quorum_a, _, quorum_b| { let primary_comparison = quorum_b.core_height().cmp(&quorum_a.core_height()); - if primary_comparison == Ordering::Equal { + if primary_comparison == std::cmp::Ordering::Equal { quorum_b .quorum_hash() .cmp(quorum_a.quorum_hash()) @@ -132,23 +152,7 @@ where } }); - tracing::debug!( - method = "update_quorum_info_v0", - "new {:?}", - block_platform_state.validator_sets() - ); - - let quorums_by_type = quorum_list - .quorums_by_type - .into_iter() - .map(|(quorum_type, quorum_list)| { - let sorted_quorum_list = quorum_list.into_iter().collect(); - - (quorum_type, sorted_quorum_list) - }) - .collect(); - - block_platform_state.set_quorums_extended_info(quorums_by_type); + block_platform_state.set_quorums_extended_info(all_quorums_by_type); Ok(()) } diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/fetch_documents.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/fetch_documents.rs index 75f5abfe02..1b55ac6a67 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/fetch_documents.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/documents_batch/state/v0/fetch_documents.rs @@ -95,8 +95,6 @@ pub(crate) fn fetch_documents_for_transitions_knowing_contract_id_and_document_t )); }; - let contract_fetch_info = contract_fetch_info; - let Some(document_type) = contract_fetch_info .contract .document_type_optional_for_name(document_type_name) diff --git a/packages/rs-drive-abci/src/rpc/core.rs b/packages/rs-drive-abci/src/rpc/core.rs index a24a667462..d1b74005e1 100644 --- a/packages/rs-drive-abci/src/rpc/core.rs +++ b/packages/rs-drive-abci/src/rpc/core.rs @@ -9,12 +9,12 @@ use dashcore_rpc::json::GetTransactionResult; use dashcore_rpc::{Auth, Client, Error, RpcApi}; use dpp::dashcore::{hashes::Hash, InstantLock}; use serde_json::Value; -use std::collections::HashMap; +use std::collections::BTreeMap; use std::time::Duration; use tenderdash_abci::proto::types::CoreChainLock; /// Information returned by QuorumListExtended -pub type QuorumListExtendedInfo = HashMap; +pub type QuorumListExtendedInfo = BTreeMap; /// Core height must be of type u32 (Platform heights are u64) pub type CoreHeight = u32; @@ -51,13 +51,13 @@ pub trait CoreRPCLike { /// Get chain tips fn get_chain_tips(&self) -> Result; - /// Get list of quorums at a given height. + /// Get list of quorums by type at a given height. /// /// See - fn get_quorum_listextended( + fn get_quorum_listextended_by_type( &self, height: Option, - ) -> Result; + ) -> Result, Error>; /// Get quorum information. /// @@ -224,11 +224,24 @@ impl CoreRPCLike for DefaultCoreRPC { retry!(self.inner.get_chain_tips()) } - fn get_quorum_listextended( + fn get_quorum_listextended_by_type( &self, height: Option, - ) -> Result { - retry!(self.inner.get_quorum_listextended(height)) + ) -> Result, Error> { + let all_quorums_list = get_quorum_listextended(&self.inner, height)?; + + // Sort in deterministic order + let sorted_quorums_by_type = all_quorums_list + .quorums_by_type + .into_iter() + .map(|(quorum_type, quorum_list)| { + let sorted_quorum_list: BTreeMap<_, _> = quorum_list.into_iter().collect(); + + (quorum_type, sorted_quorum_list) + }) + .collect(); + + Ok(sorted_quorums_by_type) } fn get_quorum_info( @@ -310,3 +323,10 @@ impl CoreRPCLike for DefaultCoreRPC { retry!(self.inner.mnsync_status()) } } + +fn get_quorum_listextended( + inner: &Client, + height: Option, +) -> Result { + retry!(inner.get_quorum_listextended(height)) +} diff --git a/packages/rs-drive-abci/tests/strategy_tests/execution.rs b/packages/rs-drive-abci/tests/strategy_tests/execution.rs index 8ac9bf446a..96d313147e 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/execution.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/execution.rs @@ -260,15 +260,13 @@ pub(crate) fn run_chain_for_strategy( platform .core_rpc - .expect_get_quorum_listextended() + .expect_get_quorum_listextended_by_type() .returning(move |core_height: Option| { if !strategy.rotate_quorums { - Ok(dashcore_rpc::dashcore_rpc_json::ExtendedQuorumListResult { - quorums_by_type: HashMap::from([( - QuorumType::Llmq100_67, - quorums_details.clone().into_iter().collect(), - )]), - }) + Ok(BTreeMap::from([( + QuorumType::Llmq100_67, + quorums_details.clone().into_iter().collect(), + )])) } else { let core_height = core_height.expect("expected a core height"); // if we rotate quorums we shouldn't give back the same ones every time @@ -296,9 +294,7 @@ pub(crate) fn run_chain_for_strategy( .collect() }; - Ok(dashcore_rpc::dashcore_rpc_json::ExtendedQuorumListResult { - quorums_by_type: HashMap::from([(QuorumType::Llmq100_67, quorums)]), - }) + Ok(BTreeMap::from([(QuorumType::Llmq100_67, quorums)])) } }); @@ -312,7 +308,7 @@ pub(crate) fn run_chain_for_strategy( .expect_get_quorum_info() .returning(move |_, quorum_hash: &QuorumHash, _| { Ok(quorums_info - .get(quorum_hash) + .get::(quorum_hash) .unwrap_or_else(|| panic!("expected to get quorum {}", hex::encode(quorum_hash))) .clone()) }); @@ -525,7 +521,7 @@ pub(crate) fn start_chain_for_strategy( .expect("expected quorums to be initialized"); let current_quorum_with_test_info = quorums - .get(¤t_quorum_hash) + .get::(¤t_quorum_hash) .expect("expected a quorum to be found"); // init chain @@ -635,7 +631,8 @@ pub(crate) fn continue_chain_for_strategy( let mut total_withdrawals = vec![]; - let mut current_quorum_with_test_info = quorums.get(¤t_quorum_hash).unwrap(); + let mut current_quorum_with_test_info = + quorums.get::(¤t_quorum_hash).unwrap(); let mut validator_set_updates = BTreeMap::new(); @@ -662,7 +659,8 @@ pub(crate) fn continue_chain_for_strategy( epoch: Epoch::new(epoch_info.current_epoch_index).unwrap(), }; if current_quorum_with_test_info.quorum_hash != current_quorum_hash { - current_quorum_with_test_info = quorums.get(¤t_quorum_hash).unwrap(); + current_quorum_with_test_info = + quorums.get::(¤t_quorum_hash).unwrap(); } let proposer = current_quorum_with_test_info @@ -686,7 +684,7 @@ pub(crate) fn continue_chain_for_strategy( next_protocol_version, change_block_height, } = proposer_versions - .get(&proposer.pro_tx_hash) + .get::(&proposer.pro_tx_hash) .expect("expected to have version"); if &block_height >= change_block_height { *next_protocol_version