From 2faf307c0f299a42153bf3cd11c4d72505710bb1 Mon Sep 17 00:00:00 2001 From: mrnaveira <47919901+mrnaveira@users.noreply.github.com> Date: Thu, 11 Jan 2024 13:15:12 +0000 Subject: [PATCH 1/8] add qc to vn json_rpc --- .../src/json_rpc/handlers.rs | 54 +++++++++++++------ clients/validator_node_client/src/types.rs | 3 +- 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/applications/tari_validator_node/src/json_rpc/handlers.rs b/applications/tari_validator_node/src/json_rpc/handlers.rs index 94e8dff8a..21a8a9948 100644 --- a/applications/tari_validator_node/src/json_rpc/handlers.rs +++ b/applications/tari_validator_node/src/json_rpc/handlers.rs @@ -335,32 +335,54 @@ impl JsonRpcHandlers { pub async fn get_substate(&self, value: JsonRpcExtractor) -> JrpcResult { let answer_id = value.get_answer_id(); let data: GetSubstateRequest = value.parse_params()?; + let shard_id = ShardId::from_address(&data.address, data.version); - let maybe_substate = self + let mut tx = self .state_store - .with_read_tx(|tx| { - let shard_id = ShardId::from_address(&data.address, data.version); - SubstateRecord::get(tx, &shard_id).optional() - }) + .create_read_tx() + .map_err(internal_error(answer_id))?; + + let maybe_substate = SubstateRecord::get(&mut tx, &shard_id) + .optional() + .map_err(internal_error(answer_id))?; + + let Some(substate) = maybe_substate else { + return Ok(JsonRpcResponse::success(answer_id, GetSubstateResponse { + status: SubstateStatus::DoesNotExist, + created_by_tx: None, + value: None, + quorum_certificates: vec![], + })); + }; + + let created_qc = substate + .get_created_quorum_certificate(&mut tx) .map_err(internal_error(answer_id))?; - match maybe_substate { - Some(substate) if substate.is_destroyed() => Ok(JsonRpcResponse::success(answer_id, GetSubstateResponse { + let resp = if substate.is_destroyed() { + let destroyed_qc = substate + .get_destroyed_quorum_certificate(&mut tx) + .map_err(internal_error(answer_id))?; + GetSubstateResponse { status: SubstateStatus::Down, created_by_tx: Some(substate.created_by_transaction), value: None, - })), - Some(substate) => Ok(JsonRpcResponse::success(answer_id, GetSubstateResponse { + quorum_certificates: Some(created_qc) + .into_iter() + .chain(destroyed_qc) + .map(|qc| qc.into()) + .collect() + } + } else { + GetSubstateResponse { status: SubstateStatus::Up, created_by_tx: Some(substate.created_by_transaction), value: Some(substate.into_substate_value()), - })), - None => Ok(JsonRpcResponse::success(answer_id, GetSubstateResponse { - status: SubstateStatus::DoesNotExist, - created_by_tx: None, - value: None, - })), - } + quorum_certificates: vec![created_qc.into()], + } + }; + + Ok(JsonRpcResponse::success(answer_id, resp)) } pub async fn get_substates_created_by_transaction(&self, value: JsonRpcExtractor) -> JrpcResult { diff --git a/clients/validator_node_client/src/types.rs b/clients/validator_node_client/src/types.rs index 7c36b7d4d..e18e1b5d5 100644 --- a/clients/validator_node_client/src/types.rs +++ b/clients/validator_node_client/src/types.rs @@ -27,7 +27,7 @@ use serde::{Deserialize, Serialize}; use tari_common_types::{transaction::TxId, types::PublicKey}; use tari_dan_common_types::{committee::CommitteeShard, shard_bucket::ShardBucket, Epoch, ShardId}; use tari_dan_storage::{ - consensus_models::{Block, BlockId, ExecutedTransaction, QuorumDecision, SubstateRecord}, + consensus_models::{Block, BlockId, ExecutedTransaction, QuorumDecision, SubstateRecord, QuorumCertificate}, global::models::ValidatorNode, Ordering, }; @@ -271,6 +271,7 @@ pub struct GetSubstateResponse { pub value: Option, pub created_by_tx: Option, pub status: SubstateStatus, + pub quorum_certificates: Vec, } #[derive(Debug, Clone, Copy, Serialize, Deserialize)] From 96670d5011de336f212ebf96553321f93d469e41 Mon Sep 17 00:00:00 2001 From: mrnaveira <47919901+mrnaveira@users.noreply.github.com> Date: Thu, 11 Jan 2024 16:08:05 +0000 Subject: [PATCH 2/8] add qcs to vn rpc client --- .../tari_indexer/src/json_rpc/handlers.rs | 1 + .../tari_indexer/src/substate_manager.rs | 1 + dan_layer/validator_node_rpc/src/client.rs | 21 +++++++++++++------ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/applications/tari_indexer/src/json_rpc/handlers.rs b/applications/tari_indexer/src/json_rpc/handlers.rs index ce95c50a0..623cb54cb 100644 --- a/applications/tari_indexer/src/json_rpc/handlers.rs +++ b/applications/tari_indexer/src/json_rpc/handlers.rs @@ -317,6 +317,7 @@ impl JsonRpcHandlers { address, substate, created_by_tx, + quorum_certificates: _, } => Ok(JsonRpcResponse::success(answer_id, GetSubstateResponse { address, version: substate.version(), diff --git a/applications/tari_indexer/src/substate_manager.rs b/applications/tari_indexer/src/substate_manager.rs index a2861711f..267381db2 100644 --- a/applications/tari_indexer/src/substate_manager.rs +++ b/applications/tari_indexer/src/substate_manager.rs @@ -229,6 +229,7 @@ impl SubstateManager { address, substate, created_by_tx, + quorum_certificates: _, } => Ok(Some(SubstateResponse { address, version: substate.version(), diff --git a/dan_layer/validator_node_rpc/src/client.rs b/dan_layer/validator_node_rpc/src/client.rs index 39c8d0c02..a8d96b6c4 100644 --- a/dan_layer/validator_node_rpc/src/client.rs +++ b/dan_layer/validator_node_rpc/src/client.rs @@ -8,7 +8,7 @@ use async_trait::async_trait; use serde::{Deserialize, Serialize}; use tari_bor::{decode, decode_exact, encode}; use tari_dan_common_types::{NodeAddressable, PeerAddress, ShardId}; -use tari_dan_storage::consensus_models::Decision; +use tari_dan_storage::consensus_models::{Decision, QuorumCertificate}; use tari_engine_types::{ commit_result::ExecuteResult, substate::{Substate, SubstateAddress, SubstateValue}, @@ -66,12 +66,14 @@ pub enum SubstateResult { address: SubstateAddress, substate: Substate, created_by_tx: TransactionId, + quorum_certificates: Vec, }, Down { address: SubstateAddress, version: u32, created_by_tx: TransactionId, deleted_by_tx: TransactionId, + quorum_certificates: Vec, }, } @@ -135,11 +137,6 @@ impl ValidatorNodeRpcClient for TariValidatorNodeRpcClient { )) })?; - // TODO: verify the quorum certificates - // for qc in resp.quorum_certificates { - // let qc = QuorumCertificate::try_from(&qc)?; - // } - match status { SubstateStatus::Up => { let tx_hash = resp.created_transaction_hash.try_into().map_err(|_| { @@ -149,11 +146,17 @@ impl ValidatorNodeRpcClient for TariValidatorNodeRpcClient { })?; let substate = SubstateValue::from_bytes(&resp.substate) .map_err(|e| ValidatorNodeRpcClientError::InvalidResponse(anyhow!(e)))?; + let quorum_certificates = resp.quorum_certificates + .into_iter() + .map(|qc| qc.try_into()) + .collect::>() + .map_err(|_| ValidatorNodeRpcClientError::InvalidResponse(anyhow!("Node returned invalid quorum certificates")))?; Ok(SubstateResult::Up { substate: Substate::new(resp.version, substate), address: SubstateAddress::from_bytes(&resp.address) .map_err(|e| ValidatorNodeRpcClientError::InvalidResponse(anyhow!(e)))?, created_by_tx: tx_hash, + quorum_certificates }) }, SubstateStatus::Down => { @@ -167,12 +170,18 @@ impl ValidatorNodeRpcClient for TariValidatorNodeRpcClient { "Node returned an invalid or empty destroyed transaction hash" )) })?; + let quorum_certificates = resp.quorum_certificates + .into_iter() + .map(|qc| qc.try_into()) + .collect::>() + .map_err(|_| ValidatorNodeRpcClientError::InvalidResponse(anyhow!("Node returned invalid quorum certificates")))?; Ok(SubstateResult::Down { address: SubstateAddress::from_bytes(&resp.address) .map_err(|e| ValidatorNodeRpcClientError::InvalidResponse(anyhow!(e)))?, version: resp.version, deleted_by_tx, created_by_tx, + quorum_certificates, }) }, SubstateStatus::DoesNotExist => Ok(SubstateResult::DoesNotExist), From b4e1e819359574f7daf3d57b42c18045c732e3fb Mon Sep 17 00:00:00 2001 From: mrnaveira <47919901+mrnaveira@users.noreply.github.com> Date: Thu, 11 Jan 2024 22:23:58 +0000 Subject: [PATCH 3/8] add qc validation in the subsstate scanner --- Cargo.lock | 4 + .../tari_dan_app_utilities/Cargo.toml | 1 + .../tari_dan_app_utilities/src/lib.rs | 1 + .../src/signature_service.rs | 61 ++++++++++++++++ applications/tari_indexer/Cargo.toml | 1 + .../tari_indexer/src/dry_run/processor.rs | 6 +- .../tari_indexer/src/json_rpc/handlers.rs | 5 +- applications/tari_indexer/src/lib.rs | 4 +- .../tari_indexer/src/substate_manager.rs | 6 +- .../src/transaction_manager/mod.rs | 12 +-- .../tari_validator_node/src/bootstrap.rs | 6 +- .../src/dry_run_transaction_processor.rs | 4 +- .../src/substate_resolver.rs | 17 +++-- dan_layer/indexer_lib/Cargo.toml | 2 + dan_layer/indexer_lib/src/error.rs | 2 + dan_layer/indexer_lib/src/substate_scanner.rs | 73 ++++++++++++++++++- .../indexer_lib/src/transaction_autofiller.rs | 20 +++-- 17 files changed, 191 insertions(+), 34 deletions(-) create mode 100644 applications/tari_dan_app_utilities/src/signature_service.rs diff --git a/Cargo.lock b/Cargo.lock index 9f1ea30e3..3351b230b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9101,6 +9101,7 @@ dependencies = [ "tari_bor", "tari_common", "tari_common_types", + "tari_consensus", "tari_core", "tari_crypto", "tari_dan_common_types", @@ -9436,6 +9437,7 @@ dependencies = [ "tari_bor", "tari_common", "tari_common_types", + "tari_consensus", "tari_crypto", "tari_dan_app_utilities", "tari_dan_common_types", @@ -9484,7 +9486,9 @@ dependencies = [ "log", "rand", "serde", + "tari_consensus", "tari_dan_common_types", + "tari_dan_storage", "tari_engine_types", "tari_epoch_manager", "tari_template_lib", diff --git a/applications/tari_dan_app_utilities/Cargo.toml b/applications/tari_dan_app_utilities/Cargo.toml index 41c37e772..169e9c078 100644 --- a/applications/tari_dan_app_utilities/Cargo.toml +++ b/applications/tari_dan_app_utilities/Cargo.toml @@ -13,6 +13,7 @@ tari_core = { workspace = true, default-features = false, features = ["transacti tari_crypto = { workspace = true } tari_shutdown = { workspace = true } +tari_consensus = { workspace = true } tari_dan_common_types = { workspace = true } tari_state_store_sqlite = { workspace = true } tari_dan_engine = { workspace = true } diff --git a/applications/tari_dan_app_utilities/src/lib.rs b/applications/tari_dan_app_utilities/src/lib.rs index b3600006c..cf2ba9aa4 100644 --- a/applications/tari_dan_app_utilities/src/lib.rs +++ b/applications/tari_dan_app_utilities/src/lib.rs @@ -26,6 +26,7 @@ pub mod consensus_constants; pub mod keypair; pub mod p2p_config; pub mod seed_peer; +pub mod signature_service; pub mod substate_file_cache; pub mod template_manager; pub mod transaction_executor; diff --git a/applications/tari_dan_app_utilities/src/signature_service.rs b/applications/tari_dan_app_utilities/src/signature_service.rs new file mode 100644 index 000000000..8aa3382f8 --- /dev/null +++ b/applications/tari_dan_app_utilities/src/signature_service.rs @@ -0,0 +1,61 @@ +// Copyright 2024. The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use rand::rngs::OsRng; +use tari_common_types::types::{FixedHash, PublicKey}; +use tari_consensus::traits::{ValidatorSignatureService, VoteSignatureService}; +use crate::keypair::RistrettoKeypair; +use tari_dan_storage::consensus_models::{BlockId, QuorumDecision, ValidatorSchnorrSignature, ValidatorSignature}; + +#[derive(Debug, Clone)] +pub struct TariSignatureService { + keypair: RistrettoKeypair, +} + +impl TariSignatureService { + pub fn new(keypair: RistrettoKeypair) -> Self { + Self { keypair } + } +} + +impl ValidatorSignatureService for TariSignatureService { + fn sign>(&self, message: M) -> ValidatorSchnorrSignature { + ValidatorSchnorrSignature::sign(self.keypair.secret_key(), message, &mut OsRng).unwrap() + } + + fn public_key(&self) -> &PublicKey { + self.keypair.public_key() + } +} + +impl VoteSignatureService for TariSignatureService { + fn verify( + &self, + signature: &ValidatorSignature, + leaf_hash: &FixedHash, + block_id: &BlockId, + decision: &QuorumDecision, + ) -> bool { + let challenge = self.create_challenge(leaf_hash, block_id, decision); + signature.verify(challenge) + } +} diff --git a/applications/tari_indexer/Cargo.toml b/applications/tari_indexer/Cargo.toml index 4fcfbcc15..30de1f36b 100644 --- a/applications/tari_indexer/Cargo.toml +++ b/applications/tari_indexer/Cargo.toml @@ -14,6 +14,7 @@ tari_common_types = { workspace = true } tari_crypto = { workspace = true } tari_shutdown = { workspace = true } +tari_consensus = { workspace = true } tari_bor = { workspace = true, default-features = true } tari_dan_app_utilities = { workspace = true } tari_dan_common_types = { workspace = true } diff --git a/applications/tari_indexer/src/dry_run/processor.rs b/applications/tari_indexer/src/dry_run/processor.rs index 3a7a4ad90..2cfd89353 100644 --- a/applications/tari_indexer/src/dry_run/processor.rs +++ b/applications/tari_indexer/src/dry_run/processor.rs @@ -25,7 +25,7 @@ use std::{collections::HashMap, sync::Arc}; use log::info; use tari_dan_app_utilities::{ template_manager::implementation::TemplateManager, - transaction_executor::{TariDanTransactionProcessor, TransactionExecutor}, + transaction_executor::{TariDanTransactionProcessor, TransactionExecutor}, signature_service::TariSignatureService, }; use tari_dan_common_types::{Epoch, PeerAddress, ShardId}; use tari_dan_engine::{ @@ -62,7 +62,7 @@ pub struct DryRunTransactionProcessor { epoch_manager: EpochManagerHandle, client_provider: TariValidatorNodeRpcClientFactory, transaction_autofiller: - TransactionAutofiller, TariValidatorNodeRpcClientFactory, TSubstateCache>, + TransactionAutofiller, TariValidatorNodeRpcClientFactory, TSubstateCache, TariSignatureService>, template_manager: TemplateManager, } @@ -73,7 +73,7 @@ where TSubstateCache: SubstateCache + 'static epoch_manager: EpochManagerHandle, client_provider: TariValidatorNodeRpcClientFactory, substate_scanner: Arc< - SubstateScanner, TariValidatorNodeRpcClientFactory, TSubstateCache>, + SubstateScanner, TariValidatorNodeRpcClientFactory, TSubstateCache, TariSignatureService>, >, template_manager: TemplateManager, ) -> Self { diff --git a/applications/tari_indexer/src/json_rpc/handlers.rs b/applications/tari_indexer/src/json_rpc/handlers.rs index 623cb54cb..b86dede7f 100644 --- a/applications/tari_indexer/src/json_rpc/handlers.rs +++ b/applications/tari_indexer/src/json_rpc/handlers.rs @@ -32,7 +32,7 @@ use libp2p::swarm::dial_opts::{DialOpts, PeerCondition}; use log::{error, warn}; use serde_json::{self as json, json, Value}; use tari_base_node_client::{grpc::GrpcBaseNodeClient, types::BaseLayerConsensusConstants, BaseNodeClient}; -use tari_dan_app_utilities::{keypair::RistrettoKeypair, substate_file_cache::SubstateFileCache}; +use tari_dan_app_utilities::{keypair::RistrettoKeypair, substate_file_cache::SubstateFileCache, signature_service::TariSignatureService}; use tari_dan_common_types::{optional::Optional, public_key_to_peer_id, Epoch, PeerAddress}; use tari_dan_storage::consensus_models::Decision; use tari_epoch_manager::{base_layer::EpochManagerHandle, EpochManagerReader}; @@ -93,7 +93,7 @@ pub struct JsonRpcHandlers { substate_manager: Arc, epoch_manager: EpochManagerHandle, transaction_manager: - TransactionManager, TariValidatorNodeRpcClientFactory, SubstateFileCache>, + TransactionManager, TariValidatorNodeRpcClientFactory, SubstateFileCache, TariSignatureService>, dry_run_transaction_processor: DryRunTransactionProcessor, } @@ -107,6 +107,7 @@ impl JsonRpcHandlers { EpochManagerHandle, TariValidatorNodeRpcClientFactory, SubstateFileCache, + TariSignatureService, >, dry_run_transaction_processor: DryRunTransactionProcessor, ) -> Self { diff --git a/applications/tari_indexer/src/lib.rs b/applications/tari_indexer/src/lib.rs index 71293fb10..31b301edb 100644 --- a/applications/tari_indexer/src/lib.rs +++ b/applications/tari_indexer/src/lib.rs @@ -50,7 +50,7 @@ use tari_common::{ use tari_dan_app_utilities::{ consensus_constants::ConsensusConstants, keypair::setup_keypair_prompt, - substate_file_cache::SubstateFileCache, + substate_file_cache::SubstateFileCache, signature_service::TariSignatureService, }; use tari_dan_storage::global::DbFactory; use tari_dan_storage_sqlite::SqliteDbFactory; @@ -104,10 +104,12 @@ pub async fn run_indexer(config: ApplicationConfig, mut shutdown_signal: Shutdow let substate_cache = SubstateFileCache::new(substate_cache_dir) .map_err(|e| ExitError::new(ExitCode::ConfigError, format!("Substate cache error: {}", e)))?; + let signing_service = TariSignatureService::new(keypair.clone()); let dan_layer_scanner = Arc::new(SubstateScanner::new( services.epoch_manager.clone(), services.validator_node_client_factory.clone(), substate_cache, + signing_service, )); let substate_manager = Arc::new(SubstateManager::new( diff --git a/applications/tari_indexer/src/substate_manager.rs b/applications/tari_indexer/src/substate_manager.rs index 267381db2..711100a56 100644 --- a/applications/tari_indexer/src/substate_manager.rs +++ b/applications/tari_indexer/src/substate_manager.rs @@ -27,7 +27,7 @@ use log::info; use serde::{Deserialize, Serialize}; use tari_common_types::types::FixedHash; use tari_crypto::tari_utilities::message_format::MessageFormat; -use tari_dan_app_utilities::substate_file_cache::SubstateFileCache; +use tari_dan_app_utilities::{substate_file_cache::SubstateFileCache, signature_service::TariSignatureService}; use tari_dan_common_types::PeerAddress; use tari_engine_types::{ events::Event, @@ -82,14 +82,14 @@ pub struct EventResponse { pub struct SubstateManager { substate_scanner: - Arc, TariValidatorNodeRpcClientFactory, SubstateFileCache>>, + Arc, TariValidatorNodeRpcClientFactory, SubstateFileCache, TariSignatureService>>, substate_store: SqliteSubstateStore, } impl SubstateManager { pub fn new( dan_layer_scanner: Arc< - SubstateScanner, TariValidatorNodeRpcClientFactory, SubstateFileCache>, + SubstateScanner, TariValidatorNodeRpcClientFactory, SubstateFileCache, TariSignatureService>, >, substate_store: SqliteSubstateStore, ) -> Self { diff --git a/applications/tari_indexer/src/transaction_manager/mod.rs b/applications/tari_indexer/src/transaction_manager/mod.rs index fbfbd2c6e..095bda8df 100644 --- a/applications/tari_indexer/src/transaction_manager/mod.rs +++ b/applications/tari_indexer/src/transaction_manager/mod.rs @@ -25,6 +25,7 @@ mod error; use std::{collections::HashSet, fmt::Display, future::Future, iter, sync::Arc}; use log::*; +use tari_consensus::traits::VoteSignatureService; use tari_dan_common_types::{ optional::{IsNotFoundError, Optional}, NodeAddressable, @@ -49,25 +50,26 @@ use crate::transaction_manager::error::TransactionManagerError; const LOG_TARGET: &str = "tari::indexer::transaction_manager"; -pub struct TransactionManager { +pub struct TransactionManager { epoch_manager: TEpochManager, client_provider: TClientFactory, - transaction_autofiller: TransactionAutofiller, + transaction_autofiller: TransactionAutofiller, } -impl - TransactionManager +impl + TransactionManager where TAddr: NodeAddressable + 'static, TEpochManager: EpochManagerReader + 'static, TClientFactory: ValidatorNodeClientFactory + 'static, ::Error: IsNotFoundError + 'static, TSubstateCache: SubstateCache + 'static, + TSignatureService: VoteSignatureService + Send + Sync + Clone + 'static, { pub fn new( epoch_manager: TEpochManager, client_provider: TClientFactory, - substate_scanner: Arc>, + substate_scanner: Arc>, ) -> Self { Self { epoch_manager, diff --git a/applications/tari_validator_node/src/bootstrap.rs b/applications/tari_validator_node/src/bootstrap.rs index 6553432e7..d88f597fc 100644 --- a/applications/tari_validator_node/src/bootstrap.rs +++ b/applications/tari_validator_node/src/bootstrap.rs @@ -45,7 +45,7 @@ use tari_dan_app_utilities::{ substate_file_cache::SubstateFileCache, template_manager, template_manager::{implementation::TemplateManager, interface::TemplateManagerHandle}, - transaction_executor::TariDanTransactionProcessor, + transaction_executor::TariDanTransactionProcessor, signature_service::TariSignatureService, }; use tari_dan_common_types::{Epoch, NodeAddressable, NodeHeight, PeerAddress, ShardId}; use tari_dan_engine::fees::FeeTable; @@ -249,12 +249,16 @@ pub async fn spawn_services( let substate_cache = SubstateFileCache::new(substate_cache_dir) .map_err(|e| ExitError::new(ExitCode::ConfigError, format!("Substate cache error: {}", e)))?; + // Signature service + let signing_service = TariSignatureService::new(keypair.clone()); + // Mempool let virtual_substate_manager = VirtualSubstateManager::new(state_store.clone(), epoch_manager.clone()); let scanner = SubstateScanner::new( epoch_manager.clone(), validator_node_client_factory.clone(), substate_cache, + signing_service ); let substate_resolver = TariSubstateResolver::new( state_store.clone(), diff --git a/applications/tari_validator_node/src/dry_run_transaction_processor.rs b/applications/tari_validator_node/src/dry_run_transaction_processor.rs index 57c9c2142..797c10936 100644 --- a/applications/tari_validator_node/src/dry_run_transaction_processor.rs +++ b/applications/tari_validator_node/src/dry_run_transaction_processor.rs @@ -24,7 +24,7 @@ use log::info; use tari_dan_app_utilities::{ substate_file_cache::SubstateFileCache, template_manager::implementation::TemplateManager, - transaction_executor::{TariDanTransactionProcessor, TransactionExecutor, TransactionProcessorError}, + transaction_executor::{TariDanTransactionProcessor, TransactionExecutor, TransactionProcessorError}, signature_service::TariSignatureService, }; use tari_dan_common_types::PeerAddress; use tari_dan_engine::{ @@ -77,6 +77,7 @@ pub struct DryRunTransactionProcessor { EpochManagerHandle, TariValidatorNodeRpcClientFactory, SubstateFileCache, + TariSignatureService >, epoch_manager: EpochManagerHandle, payload_processor: TariDanTransactionProcessor>, @@ -91,6 +92,7 @@ impl DryRunTransactionProcessor { EpochManagerHandle, TariValidatorNodeRpcClientFactory, SubstateFileCache, + TariSignatureService, >, ) -> Self { Self { diff --git a/applications/tari_validator_node/src/substate_resolver.rs b/applications/tari_validator_node/src/substate_resolver.rs index fa8bd6661..a30159c5f 100644 --- a/applications/tari_validator_node/src/substate_resolver.rs +++ b/applications/tari_validator_node/src/substate_resolver.rs @@ -6,6 +6,7 @@ use std::{collections::HashSet, time::Instant}; use async_trait::async_trait; use log::*; use tari_common_types::types::PublicKey; +use tari_consensus::traits::VoteSignatureService; use tari_dan_common_types::{Epoch, ShardId}; use tari_dan_engine::{runtime::VirtualSubstates, state_store::memory::MemoryStateStore}; use tari_dan_storage::{consensus_models::SubstateRecord, StateStore, StorageError}; @@ -27,24 +28,25 @@ use crate::{ const LOG_TARGET: &str = "tari::dan::substate_resolver"; #[derive(Debug, Clone)] -pub struct TariSubstateResolver { +pub struct TariSubstateResolver { store: TStateStore, - scanner: SubstateScanner, + scanner: SubstateScanner, epoch_manager: TEpochManager, virtual_substate_manager: VirtualSubstateManager, } -impl - TariSubstateResolver +impl + TariSubstateResolver where TStateStore: StateStore, TEpochManager: EpochManagerReader, TValidatorNodeClientFactory: ValidatorNodeClientFactory, TSubstateCache: SubstateCache, + TSignatureService: VoteSignatureService, { pub fn new( store: TStateStore, - scanner: SubstateScanner, + scanner: SubstateScanner, epoch_manager: TEpochManager, virtual_substate_manager: VirtualSubstateManager, ) -> Self { @@ -148,13 +150,14 @@ where } #[async_trait] -impl SubstateResolver - for TariSubstateResolver +impl SubstateResolver + for TariSubstateResolver where TStateStore: StateStore + Sync + Send, TEpochManager: EpochManagerReader, TValidatorNodeClientFactory: ValidatorNodeClientFactory, TSubstateCache: SubstateCache, + TSignatureService: VoteSignatureService + Send + Sync, { type Error = SubstateResolverError; diff --git a/dan_layer/indexer_lib/Cargo.toml b/dan_layer/indexer_lib/Cargo.toml index e2ff189e6..141017083 100644 --- a/dan_layer/indexer_lib/Cargo.toml +++ b/dan_layer/indexer_lib/Cargo.toml @@ -14,6 +14,8 @@ tari_engine_types = { workspace = true } tari_transaction = { workspace = true } tari_template_lib = { workspace = true } tari_validator_node_rpc = { workspace = true } +tari_dan_storage = { workspace = true } +tari_consensus = { workspace = true } async-trait = { workspace = true } log = { workspace = true } diff --git a/dan_layer/indexer_lib/src/error.rs b/dan_layer/indexer_lib/src/error.rs index fbafb15f0..3a66162b1 100644 --- a/dan_layer/indexer_lib/src/error.rs +++ b/dan_layer/indexer_lib/src/error.rs @@ -26,4 +26,6 @@ pub enum IndexerError { FailedToParseTransactionHash(String), #[error("Substate cache operation failed: {0}")] SubstateCacheError(#[from] SubstateCacheError), + #[error("Invalid quorum certificate")] + InvalidQuorumCertificate, } diff --git a/dan_layer/indexer_lib/src/substate_scanner.rs b/dan_layer/indexer_lib/src/substate_scanner.rs index 060857301..9ba2608c5 100644 --- a/dan_layer/indexer_lib/src/substate_scanner.rs +++ b/dan_layer/indexer_lib/src/substate_scanner.rs @@ -22,6 +22,7 @@ use log::*; use rand::{prelude::*, rngs::OsRng}; +use tari_consensus::traits::VoteSignatureService; use tari_dan_common_types::{NodeAddressable, ShardId}; use tari_engine_types::{ events::Event, @@ -35,7 +36,7 @@ use tari_template_lib::{ }; use tari_transaction::TransactionId; use tari_validator_node_rpc::client::{SubstateResult, ValidatorNodeClientFactory, ValidatorNodeRpcClient}; - +use tari_dan_storage::consensus_models::QuorumCertificate; use crate::{ error::IndexerError, substate_cache::{SubstateCache, SubstateCacheEntry}, @@ -45,28 +46,32 @@ use crate::{ const LOG_TARGET: &str = "tari::indexer::dan_layer_scanner"; #[derive(Debug, Clone)] -pub struct SubstateScanner { +pub struct SubstateScanner { committee_provider: TEpochManager, validator_node_client_factory: TVnClient, substate_cache: TSubstateCache, + signing_service: TSignatureService, } -impl SubstateScanner +impl SubstateScanner where TAddr: NodeAddressable, TEpochManager: EpochManagerReader, TVnClient: ValidatorNodeClientFactory, TSubstateCache: SubstateCache, + TSignatureService: VoteSignatureService, { pub fn new( committee_provider: TEpochManager, validator_node_client_factory: TVnClient, substate_cache: TSubstateCache, + signing_service: TSignatureService, ) -> Self { Self { committee_provider, validator_node_client_factory, substate_cache, + signing_service } } @@ -311,9 +316,71 @@ where .get_substate(shard) .await .map_err(|e| IndexerError::ValidatorNodeClientError(e.to_string()))?; + + // validate the qc + match &result { + SubstateResult::DoesNotExist => (), + SubstateResult::Up { quorum_certificates, .. } => self.validate_qcs(&quorum_certificates, shard).await?, + SubstateResult::Down { quorum_certificates, .. } => self.validate_qcs(&quorum_certificates, shard).await?, + } + Ok(result) } + /// Validates Quorum Certificates associated with a substate + async fn validate_qcs(&self, qcs: &Vec, shard_id: ShardId) -> Result<(), IndexerError> { + let qc = qcs.last() + .ok_or(IndexerError::InvalidQuorumCertificate)?; + + // ignore genesis block. + if qc.epoch().as_u64() == 0 { + return Ok(()); + } + + // TODO: how to validate the block height? + + // fetch the committee members that should have signed the QC + let mut vns = vec![]; + for signature in qc.signatures() { + let vn = self.committee_provider + .get_validator_node_by_public_key(qc.epoch(), signature.public_key()) + .await?; + vns.push(vn.node_hash()); + } + + // validate the QC's merkle proof + let merkle_root = self.committee_provider + .get_validator_node_merkle_root(qc.epoch()) + .await?; + let proof = qc.merged_proof().clone(); + let vns_bytes = vns.iter().map(|hash| hash.to_vec()).collect(); + let is_proof_valid = proof.verify_consume(&merkle_root, vns_bytes) + .map_err(|_| IndexerError::InvalidQuorumCertificate)?; + if !is_proof_valid { + return Err(IndexerError::InvalidQuorumCertificate); + } + + // validate each signature in the QC + for (sign, leaf) in qc.signatures().iter().zip(vns.iter()) { + let challenge = self.signing_service.create_challenge(leaf, qc.block_id(), &qc.decision()); + if !sign.verify(challenge) { + return Err(IndexerError::InvalidQuorumCertificate); + } + } + + // validate that enough committee members have signed the QC + let committee_shard = self.committee_provider + .get_committee_shard(qc.epoch(), shard_id) + .await?; + let num_signatures_in_qc = u32::try_from(qc.signatures().len()) + .map_err(|_| IndexerError::InvalidQuorumCertificate)?; + if committee_shard.quorum_threshold() > num_signatures_in_qc { + return Err(IndexerError::InvalidQuorumCertificate); + } + + Ok(()) + } + /// Queries the network to obtain events emitted in a single transaction pub async fn get_events_for_transaction(&self, transaction_id: TransactionId) -> Result, IndexerError> { let substate_address = SubstateAddress::TransactionReceipt(transaction_id.into_array().into()); diff --git a/dan_layer/indexer_lib/src/transaction_autofiller.rs b/dan_layer/indexer_lib/src/transaction_autofiller.rs index 62d9ba20a..ef71c3dd7 100644 --- a/dan_layer/indexer_lib/src/transaction_autofiller.rs +++ b/dan_layer/indexer_lib/src/transaction_autofiller.rs @@ -4,6 +4,7 @@ use std::{collections::HashMap, sync::Arc}; use log::*; +use tari_consensus::traits::VoteSignatureService; use tari_dan_common_types::{NodeAddressable, ShardId}; use tari_engine_types::{ indexed_value::IndexedValueError, @@ -33,18 +34,19 @@ pub enum TransactionAutofillerError { JoinError(#[from] JoinError), } -pub struct TransactionAutofiller { - substate_scanner: Arc>, +pub struct TransactionAutofiller { + substate_scanner: Arc>, } -impl TransactionAutofiller +impl TransactionAutofiller where TEpochManager: EpochManagerReader + 'static, TVnClient: ValidatorNodeClientFactory + 'static, TAddr: NodeAddressable + 'static, TSubstateCache: SubstateCache + 'static, + TSignatureService: VoteSignatureService + Send + Sync + Clone + 'static, { - pub fn new(substate_scanner: Arc>) -> Self { + pub fn new(substate_scanner: Arc>) -> Self { Self { substate_scanner } } @@ -147,8 +149,8 @@ where } } -pub async fn get_substate_requirement( - substate_scanner: Arc>, +pub async fn get_substate_requirement( + substate_scanner: Arc>, transaction: Arc, req: SubstateRequirement, ) -> Result, IndexerError> @@ -157,6 +159,7 @@ where TVnClient: ValidatorNodeClientFactory, TAddr: NodeAddressable, TSubstateCache: SubstateCache, + TSignatureService: VoteSignatureService, { let scan_res = match req.version() { Some(version) => { @@ -200,8 +203,8 @@ where } } -pub async fn get_substate( - substate_scanner: Arc>, +pub async fn get_substate( + substate_scanner: Arc>, substate_address: SubstateAddress, version_hint: Option, ) -> Result @@ -210,6 +213,7 @@ where TVnClient: ValidatorNodeClientFactory, TAddr: NodeAddressable, TSubstateCache: SubstateCache, + TSignatureService: VoteSignatureService, { substate_scanner.get_substate(&substate_address, version_hint).await } From a6ba583f34cb60398de413b636201cf7bc3d61e2 Mon Sep 17 00:00:00 2001 From: mrnaveira <47919901+mrnaveira@users.noreply.github.com> Date: Sun, 14 Jan 2024 21:19:46 +0000 Subject: [PATCH 4/8] improve generics --- .../src/transaction_manager/mod.rs | 5 +- .../tari_validator_node/src/consensus/mod.rs | 4 +- .../src/dry_run_transaction_processor.rs | 2 +- .../src/substate_resolver.rs | 20 ++-- dan_layer/consensus/src/block_validations.rs | 31 +----- dan_layer/consensus/src/hotstuff/error.rs | 12 +-- dan_layer/consensus/src/lib.rs | 1 + .../src/quorum_certificate_validations.rs | 99 +++++++++++++++++++ dan_layer/indexer_lib/src/error.rs | 7 +- dan_layer/indexer_lib/src/substate_scanner.rs | 58 ++--------- .../indexer_lib/src/transaction_autofiller.rs | 10 +- 11 files changed, 144 insertions(+), 105 deletions(-) create mode 100644 dan_layer/consensus/src/quorum_certificate_validations.rs diff --git a/applications/tari_indexer/src/transaction_manager/mod.rs b/applications/tari_indexer/src/transaction_manager/mod.rs index 095bda8df..1bce67554 100644 --- a/applications/tari_indexer/src/transaction_manager/mod.rs +++ b/applications/tari_indexer/src/transaction_manager/mod.rs @@ -28,8 +28,7 @@ use log::*; use tari_consensus::traits::VoteSignatureService; use tari_dan_common_types::{ optional::{IsNotFoundError, Optional}, - NodeAddressable, - ShardId, + ShardId, DerivableFromPublicKey, }; use tari_engine_types::substate::SubstateAddress; use tari_epoch_manager::EpochManagerReader; @@ -59,7 +58,7 @@ pub struct TransactionManager TransactionManager where - TAddr: NodeAddressable + 'static, + TAddr: DerivableFromPublicKey + 'static, TEpochManager: EpochManagerReader + 'static, TClientFactory: ValidatorNodeClientFactory + 'static, ::Error: IsNotFoundError + 'static, diff --git a/applications/tari_validator_node/src/consensus/mod.rs b/applications/tari_validator_node/src/consensus/mod.rs index 25d0511ff..c6dd28f8d 100644 --- a/applications/tari_validator_node/src/consensus/mod.rs +++ b/applications/tari_validator_node/src/consensus/mod.rs @@ -22,8 +22,6 @@ use tokio::{ use crate::{ consensus::{ leader_selection::RoundRobinLeaderStrategy, - signature_service::TariSignatureService, - spec::TariConsensusSpec, state_manager::TariStateManager, }, event_subscription::EventSubscription, @@ -32,7 +30,9 @@ use crate::{ mod handle; mod leader_selection; mod signature_service; +pub use signature_service::TariSignatureService; mod spec; +pub use spec::TariConsensusSpec; mod state_manager; pub use handle::*; diff --git a/applications/tari_validator_node/src/dry_run_transaction_processor.rs b/applications/tari_validator_node/src/dry_run_transaction_processor.rs index 797c10936..aef5960bc 100644 --- a/applications/tari_validator_node/src/dry_run_transaction_processor.rs +++ b/applications/tari_validator_node/src/dry_run_transaction_processor.rs @@ -70,7 +70,7 @@ pub enum DryRunTransactionProcessorError { VirtualSubstateError(#[from] VirtualSubstateError), } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct DryRunTransactionProcessor { substate_resolver: TariSubstateResolver< SqliteStateStore, diff --git a/applications/tari_validator_node/src/substate_resolver.rs b/applications/tari_validator_node/src/substate_resolver.rs index a30159c5f..ceb034b6a 100644 --- a/applications/tari_validator_node/src/substate_resolver.rs +++ b/applications/tari_validator_node/src/substate_resolver.rs @@ -7,7 +7,7 @@ use async_trait::async_trait; use log::*; use tari_common_types::types::PublicKey; use tari_consensus::traits::VoteSignatureService; -use tari_dan_common_types::{Epoch, ShardId}; +use tari_dan_common_types::{Epoch, ShardId, DerivableFromPublicKey}; use tari_dan_engine::{runtime::VirtualSubstates, state_store::memory::MemoryStateStore}; use tari_dan_storage::{consensus_models::SubstateRecord, StateStore, StorageError}; use tari_engine_types::{ @@ -35,12 +35,13 @@ pub struct TariSubstateResolver, } -impl +impl TariSubstateResolver where - TStateStore: StateStore, - TEpochManager: EpochManagerReader, - TValidatorNodeClientFactory: ValidatorNodeClientFactory, + TAddr: DerivableFromPublicKey, + TStateStore: StateStore, + TEpochManager: EpochManagerReader, + TValidatorNodeClientFactory: ValidatorNodeClientFactory, TSubstateCache: SubstateCache, TSignatureService: VoteSignatureService, { @@ -150,12 +151,13 @@ where } #[async_trait] -impl SubstateResolver +impl SubstateResolver for TariSubstateResolver where - TStateStore: StateStore + Sync + Send, - TEpochManager: EpochManagerReader, - TValidatorNodeClientFactory: ValidatorNodeClientFactory, + TAddr: DerivableFromPublicKey, + TStateStore: StateStore + Sync + Send, + TEpochManager: EpochManagerReader, + TValidatorNodeClientFactory: ValidatorNodeClientFactory, TSubstateCache: SubstateCache, TSignatureService: VoteSignatureService + Send + Sync, { diff --git a/dan_layer/consensus/src/block_validations.rs b/dan_layer/consensus/src/block_validations.rs index e8207cbd0..2ecd69826 100644 --- a/dan_layer/consensus/src/block_validations.rs +++ b/dan_layer/consensus/src/block_validations.rs @@ -7,7 +7,7 @@ use tari_epoch_manager::EpochManagerReader; use crate::{ hotstuff::{HotStuffError, ProposalValidationError}, - traits::{ConsensusSpec, LeaderStrategy, VoteSignatureService}, + traits::{ConsensusSpec, LeaderStrategy}, quorum_certificate_validations::validate_quorum_certificate, }; pub fn check_hash_and_height(candidate_block: &Block) -> Result<(), ProposalValidationError> { @@ -86,36 +86,13 @@ pub async fn check_quorum_certificate( } .into()); } - let mut vns = vec![]; - for signature in candidate_block.justify().signatures() { - let vn = epoch_manager - .get_validator_node_by_public_key(candidate_block.justify().epoch(), signature.public_key()) - .await?; - vns.push(vn.node_hash()); - } - let merkle_root = epoch_manager - .get_validator_node_merkle_root(candidate_block.justify().epoch()) - .await?; - let qc = candidate_block.justify(); - let proof = qc.merged_proof().clone(); - if !proof.verify_consume(&merkle_root, vns.iter().map(|hash| hash.to_vec()).collect())? { - return Err(ProposalValidationError::QCisNotValid { qc: qc.clone() }.into()); - } - for (sign, leaf) in qc.signatures().iter().zip(vns.iter()) { - let challenge = vote_signing_service.create_challenge(leaf, qc.block_id(), &qc.decision()); - if !sign.verify(challenge) { - return Err(ProposalValidationError::QCInvalidSignature { qc: qc.clone() }.into()); - } - } let committee_shard = epoch_manager .get_committee_shard_by_validator_public_key(candidate_block.epoch(), candidate_block.proposed_by()) .await?; - if committee_shard.quorum_threshold() > - u32::try_from(qc.signatures().len()).map_err(|_| ProposalValidationError::QCisNotValid { qc: qc.clone() })? - { - return Err(ProposalValidationError::QuorumWasNotReached { qc: qc.clone() }.into()); - } + validate_quorum_certificate(&candidate_block.justify(), &committee_shard, vote_signing_service, epoch_manager).await + .map_err(|e| ProposalValidationError::QuorumCertificateValidationError(e))?; + Ok(()) } diff --git a/dan_layer/consensus/src/hotstuff/error.rs b/dan_layer/consensus/src/hotstuff/error.rs index f7b926ca2..31fe8cc92 100644 --- a/dan_layer/consensus/src/hotstuff/error.rs +++ b/dan_layer/consensus/src/hotstuff/error.rs @@ -3,13 +3,15 @@ use tari_dan_common_types::{Epoch, NodeHeight}; use tari_dan_storage::{ - consensus_models::{BlockId, LeafBlock, LockedBlock, QuorumCertificate, TransactionPoolError}, + consensus_models::{BlockId, LeafBlock, LockedBlock, TransactionPoolError}, StorageError, }; use tari_epoch_manager::EpochManagerError; use tari_mmr::BalancedBinaryMerkleProofError; use tari_transaction::TransactionId; +use crate::quorum_certificate_validations::QuorumCertificateValidationError; + #[derive(Debug, thiserror::Error)] pub enum HotStuffError { #[error("Storage error: {0}")] @@ -152,12 +154,8 @@ pub enum ProposalValidationError { MissingSignature { block_id: BlockId, height: NodeHeight }, #[error("Proposed block {block_id} {height} has invalid signature")] InvalidSignature { block_id: BlockId, height: NodeHeight }, - #[error("QC is not valid: {qc}")] - QCisNotValid { qc: QuorumCertificate }, - #[error("QC has invalid signature: {qc}")] - QCInvalidSignature { qc: QuorumCertificate }, - #[error("Quorum was not reached: {qc}")] - QuorumWasNotReached { qc: QuorumCertificate }, #[error("Merkle proof error: {0}")] BalancedBinaryMerkleProofError(#[from] BalancedBinaryMerkleProofError), + #[error("Quorum certificate validation error: {0}")] + QuorumCertificateValidationError(#[from] QuorumCertificateValidationError), } diff --git a/dan_layer/consensus/src/lib.rs b/dan_layer/consensus/src/lib.rs index 7674bed00..2b9ca7dda 100644 --- a/dan_layer/consensus/src/lib.rs +++ b/dan_layer/consensus/src/lib.rs @@ -4,4 +4,5 @@ mod block_validations; pub mod hotstuff; pub mod messages; +pub mod quorum_certificate_validations; pub mod traits; diff --git a/dan_layer/consensus/src/quorum_certificate_validations.rs b/dan_layer/consensus/src/quorum_certificate_validations.rs new file mode 100644 index 000000000..baf37541e --- /dev/null +++ b/dan_layer/consensus/src/quorum_certificate_validations.rs @@ -0,0 +1,99 @@ +// Copyright 2024. The Tari Project +// +// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +// following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following +// disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the +// following disclaimer in the documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote +// products derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +use crate::traits::VoteSignatureService; +use tari_dan_common_types::{committee::CommitteeShard, NodeHeight, DerivableFromPublicKey}; +use tari_dan_storage::consensus_models::QuorumCertificate; +use tari_epoch_manager::{EpochManagerReader, EpochManagerError}; + + +#[derive(Debug, thiserror::Error)] +pub enum QuorumCertificateValidationError { + #[error("QC has invalid merkle proof")] + InvalidMerkleProof, + #[error("QC has invalid signature")] + InvalidSignature, + #[error("Quorum was not reached")] + QuorumWasNotReached, + #[error("Malformed QC")] + MalformedCertificate, + #[error("Epoch manager error: {0}")] + StorageError(#[from] EpochManagerError), + #[error("Block {block_height} is not higher than justify {justify_block_height}")] + BlockNotHigherThanJustify { + justify_block_height: NodeHeight, + block_height: NodeHeight, + }, +} + +/// Validates Quorum Certificates in isolation +pub async fn validate_quorum_certificate< + TAddr: DerivableFromPublicKey, + TEpochManager: EpochManagerReader, + TSignatureService: VoteSignatureService> + (qc: &QuorumCertificate, committee_shard: &CommitteeShard, + vote_signing_service: &TSignatureService, + epoch_manager: &TEpochManager, +) -> Result<(), QuorumCertificateValidationError> { + // ignore genesis block. + if qc.epoch().as_u64() == 0 { + return Ok(()); + } + + // fetch the committee members that should have signed the QC + let mut vns = vec![]; + for signature in qc.signatures() { + let vn = epoch_manager + .get_validator_node_by_public_key(qc.epoch(), signature.public_key()) + .await?; + vns.push(vn.node_hash()); + } + + // validate the QC's merkle proof + let merkle_root = epoch_manager + .get_validator_node_merkle_root(qc.epoch()) + .await?; + let proof = qc.merged_proof().clone(); + let vns_bytes = vns.iter().map(|hash| hash.to_vec()).collect(); + let is_proof_valid = proof.verify_consume(&merkle_root, vns_bytes) + .map_err(|_| QuorumCertificateValidationError::InvalidMerkleProof)?; + if !is_proof_valid { + return Err(QuorumCertificateValidationError::InvalidMerkleProof); + } + + // validate each signature in the QC + for (sign, leaf) in qc.signatures().iter().zip(vns.iter()) { + let challenge = vote_signing_service.create_challenge(leaf, qc.block_id(), &qc.decision()); + if !sign.verify(challenge) { + return Err(QuorumCertificateValidationError::InvalidSignature); + } + } + + // validate that enough committee members have signed the QC + let num_signatures_in_qc = u32::try_from(qc.signatures().len()) + .map_err(|_| QuorumCertificateValidationError::MalformedCertificate)?; + if committee_shard.quorum_threshold() > num_signatures_in_qc { + return Err(QuorumCertificateValidationError::QuorumWasNotReached); + } + + Ok(()) +} diff --git a/dan_layer/indexer_lib/src/error.rs b/dan_layer/indexer_lib/src/error.rs index 3a66162b1..40fcb8a4c 100644 --- a/dan_layer/indexer_lib/src/error.rs +++ b/dan_layer/indexer_lib/src/error.rs @@ -1,6 +1,7 @@ // Copyright 2023 The Tari Project // SPDX-License-Identifier: BSD-3-Clause +use tari_consensus::quorum_certificate_validations::QuorumCertificateValidationError; use tari_engine_types::substate::SubstateAddress; use tari_epoch_manager::EpochManagerError; @@ -26,6 +27,8 @@ pub enum IndexerError { FailedToParseTransactionHash(String), #[error("Substate cache operation failed: {0}")] SubstateCacheError(#[from] SubstateCacheError), - #[error("Invalid quorum certificate")] - InvalidQuorumCertificate, + #[error("Quorum certificate validation error: {0}")] + QuorumCertificateValidationError(#[from] QuorumCertificateValidationError), + #[error("Missing quorum certificate")] + MissingQuorumCertificate, } diff --git a/dan_layer/indexer_lib/src/substate_scanner.rs b/dan_layer/indexer_lib/src/substate_scanner.rs index 9ba2608c5..29353b8b2 100644 --- a/dan_layer/indexer_lib/src/substate_scanner.rs +++ b/dan_layer/indexer_lib/src/substate_scanner.rs @@ -22,8 +22,8 @@ use log::*; use rand::{prelude::*, rngs::OsRng}; -use tari_consensus::traits::VoteSignatureService; -use tari_dan_common_types::{NodeAddressable, ShardId}; +use tari_consensus::{traits::VoteSignatureService, quorum_certificate_validations::validate_quorum_certificate}; +use tari_dan_common_types::{ShardId, DerivableFromPublicKey}; use tari_engine_types::{ events::Event, substate::{SubstateAddress, SubstateValue}, @@ -55,7 +55,7 @@ pub struct SubstateScanner SubstateScanner where - TAddr: NodeAddressable, + TAddr: DerivableFromPublicKey, TEpochManager: EpochManagerReader, TVnClient: ValidatorNodeClientFactory, TSubstateCache: SubstateCache, @@ -320,64 +320,24 @@ where // validate the qc match &result { SubstateResult::DoesNotExist => (), - SubstateResult::Up { quorum_certificates, .. } => self.validate_qcs(&quorum_certificates, shard).await?, - SubstateResult::Down { quorum_certificates, .. } => self.validate_qcs(&quorum_certificates, shard).await?, + SubstateResult::Up { quorum_certificates, .. } => self.validate_substate_qcs(&quorum_certificates, shard).await?, + SubstateResult::Down { quorum_certificates, .. } => self.validate_substate_qcs(&quorum_certificates, shard).await?, } Ok(result) } /// Validates Quorum Certificates associated with a substate - async fn validate_qcs(&self, qcs: &Vec, shard_id: ShardId) -> Result<(), IndexerError> { + async fn validate_substate_qcs(&self, qcs: &Vec, shard_id: ShardId) -> Result<(), IndexerError> { let qc = qcs.last() - .ok_or(IndexerError::InvalidQuorumCertificate)?; - - // ignore genesis block. - if qc.epoch().as_u64() == 0 { - return Ok(()); - } - - // TODO: how to validate the block height? - - // fetch the committee members that should have signed the QC - let mut vns = vec![]; - for signature in qc.signatures() { - let vn = self.committee_provider - .get_validator_node_by_public_key(qc.epoch(), signature.public_key()) - .await?; - vns.push(vn.node_hash()); - } - - // validate the QC's merkle proof - let merkle_root = self.committee_provider - .get_validator_node_merkle_root(qc.epoch()) - .await?; - let proof = qc.merged_proof().clone(); - let vns_bytes = vns.iter().map(|hash| hash.to_vec()).collect(); - let is_proof_valid = proof.verify_consume(&merkle_root, vns_bytes) - .map_err(|_| IndexerError::InvalidQuorumCertificate)?; - if !is_proof_valid { - return Err(IndexerError::InvalidQuorumCertificate); - } + .ok_or(IndexerError::MissingQuorumCertificate)?; - // validate each signature in the QC - for (sign, leaf) in qc.signatures().iter().zip(vns.iter()) { - let challenge = self.signing_service.create_challenge(leaf, qc.block_id(), &qc.decision()); - if !sign.verify(challenge) { - return Err(IndexerError::InvalidQuorumCertificate); - } - } - - // validate that enough committee members have signed the QC let committee_shard = self.committee_provider .get_committee_shard(qc.epoch(), shard_id) .await?; - let num_signatures_in_qc = u32::try_from(qc.signatures().len()) - .map_err(|_| IndexerError::InvalidQuorumCertificate)?; - if committee_shard.quorum_threshold() > num_signatures_in_qc { - return Err(IndexerError::InvalidQuorumCertificate); - } + validate_quorum_certificate(qc, &committee_shard, &self.signing_service, &self.committee_provider).await?; + Ok(()) } diff --git a/dan_layer/indexer_lib/src/transaction_autofiller.rs b/dan_layer/indexer_lib/src/transaction_autofiller.rs index ef71c3dd7..8afc2fcf7 100644 --- a/dan_layer/indexer_lib/src/transaction_autofiller.rs +++ b/dan_layer/indexer_lib/src/transaction_autofiller.rs @@ -5,7 +5,7 @@ use std::{collections::HashMap, sync::Arc}; use log::*; use tari_consensus::traits::VoteSignatureService; -use tari_dan_common_types::{NodeAddressable, ShardId}; +use tari_dan_common_types::{ShardId, DerivableFromPublicKey}; use tari_engine_types::{ indexed_value::IndexedValueError, substate::{Substate, SubstateAddress}, @@ -42,9 +42,9 @@ impl Transac where TEpochManager: EpochManagerReader + 'static, TVnClient: ValidatorNodeClientFactory + 'static, - TAddr: NodeAddressable + 'static, + TAddr: DerivableFromPublicKey + 'static, TSubstateCache: SubstateCache + 'static, - TSignatureService: VoteSignatureService + Send + Sync + Clone + 'static, + TSignatureService: VoteSignatureService + Send + Sync + 'static, { pub fn new(substate_scanner: Arc>) -> Self { Self { substate_scanner } @@ -157,7 +157,7 @@ pub async fn get_substate_requirement, TVnClient: ValidatorNodeClientFactory, - TAddr: NodeAddressable, + TAddr: DerivableFromPublicKey, TSubstateCache: SubstateCache, TSignatureService: VoteSignatureService, { @@ -211,7 +211,7 @@ pub async fn get_substate, TVnClient: ValidatorNodeClientFactory, - TAddr: NodeAddressable, + TAddr: DerivableFromPublicKey, TSubstateCache: SubstateCache, TSignatureService: VoteSignatureService, { From 1ba5bbb846f95d0072dae0b8835f2377273db527 Mon Sep 17 00:00:00 2001 From: mrnaveira <47919901+mrnaveira@users.noreply.github.com> Date: Sun, 14 Jan 2024 21:39:39 +0000 Subject: [PATCH 5/8] reuse the tari_signature_service --- .../tari_validator_node/src/consensus/mod.rs | 4 +- .../src/consensus/signature_service.rs | 42 ------------------- .../tari_validator_node/src/consensus/spec.rs | 2 +- dan_layer/indexer_lib/src/substate_scanner.rs | 2 + 4 files changed, 4 insertions(+), 46 deletions(-) delete mode 100644 applications/tari_validator_node/src/consensus/signature_service.rs diff --git a/applications/tari_validator_node/src/consensus/mod.rs b/applications/tari_validator_node/src/consensus/mod.rs index c6dd28f8d..2d3becef8 100644 --- a/applications/tari_validator_node/src/consensus/mod.rs +++ b/applications/tari_validator_node/src/consensus/mod.rs @@ -29,15 +29,13 @@ use crate::{ mod handle; mod leader_selection; -mod signature_service; -pub use signature_service::TariSignatureService; mod spec; pub use spec::TariConsensusSpec; mod state_manager; pub use handle::*; use sqlite_message_logger::SqliteMessageLogger; -use tari_dan_app_utilities::keypair::RistrettoKeypair; +use tari_dan_app_utilities::{keypair::RistrettoKeypair, signature_service::TariSignatureService}; use tari_dan_common_types::PeerAddress; use crate::p2p::services::message_dispatcher::OutboundMessaging; diff --git a/applications/tari_validator_node/src/consensus/signature_service.rs b/applications/tari_validator_node/src/consensus/signature_service.rs deleted file mode 100644 index 87bcb2937..000000000 --- a/applications/tari_validator_node/src/consensus/signature_service.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2023 The Tari Project -// SPDX-License-Identifier: BSD-3-Clause - -use rand::rngs::OsRng; -use tari_common_types::types::{FixedHash, PublicKey}; -use tari_consensus::traits::{ValidatorSignatureService, VoteSignatureService}; -use tari_dan_app_utilities::keypair::RistrettoKeypair; -use tari_dan_storage::consensus_models::{BlockId, QuorumDecision, ValidatorSchnorrSignature, ValidatorSignature}; - -#[derive(Debug, Clone)] -pub struct TariSignatureService { - keypair: RistrettoKeypair, -} - -impl TariSignatureService { - pub fn new(keypair: RistrettoKeypair) -> Self { - Self { keypair } - } -} - -impl ValidatorSignatureService for TariSignatureService { - fn sign>(&self, message: M) -> ValidatorSchnorrSignature { - ValidatorSchnorrSignature::sign(self.keypair.secret_key(), message, &mut OsRng).unwrap() - } - - fn public_key(&self) -> &PublicKey { - self.keypair.public_key() - } -} - -impl VoteSignatureService for TariSignatureService { - fn verify( - &self, - signature: &ValidatorSignature, - leaf_hash: &FixedHash, - block_id: &BlockId, - decision: &QuorumDecision, - ) -> bool { - let challenge = self.create_challenge(leaf_hash, block_id, decision); - signature.verify(challenge) - } -} diff --git a/applications/tari_validator_node/src/consensus/spec.rs b/applications/tari_validator_node/src/consensus/spec.rs index 330c7fd62..3d4da5f9b 100644 --- a/applications/tari_validator_node/src/consensus/spec.rs +++ b/applications/tari_validator_node/src/consensus/spec.rs @@ -3,13 +3,13 @@ use tari_comms_rpc_state_sync::CommsRpcStateSyncManager; use tari_consensus::traits::ConsensusSpec; +use tari_dan_app_utilities::signature_service::TariSignatureService; use tari_dan_common_types::PeerAddress; use tari_epoch_manager::base_layer::EpochManagerHandle; use tari_state_store_sqlite::SqliteStateStore; use crate::consensus::{ leader_selection::RoundRobinLeaderStrategy, - signature_service::TariSignatureService, state_manager::TariStateManager, }; diff --git a/dan_layer/indexer_lib/src/substate_scanner.rs b/dan_layer/indexer_lib/src/substate_scanner.rs index 29353b8b2..9f8fb10fe 100644 --- a/dan_layer/indexer_lib/src/substate_scanner.rs +++ b/dan_layer/indexer_lib/src/substate_scanner.rs @@ -318,6 +318,8 @@ where .map_err(|e| IndexerError::ValidatorNodeClientError(e.to_string()))?; // validate the qc + // TODO: currently there is no way to check that the QC validates the substate value we receive + // we are only checking that the QC is valid in isolation match &result { SubstateResult::DoesNotExist => (), SubstateResult::Up { quorum_certificates, .. } => self.validate_substate_qcs(&quorum_certificates, shard).await?, From 3010ad42b5dca59087327d51fdc33d107a09aae9 Mon Sep 17 00:00:00 2001 From: mrnaveira <47919901+mrnaveira@users.noreply.github.com> Date: Mon, 15 Jan 2024 07:44:06 +0000 Subject: [PATCH 6/8] fix clippy --- applications/tari_validator_node/src/json_rpc/handlers.rs | 3 +-- dan_layer/consensus/src/block_validations.rs | 4 ++-- dan_layer/indexer_lib/src/substate_scanner.rs | 6 +++--- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/applications/tari_validator_node/src/json_rpc/handlers.rs b/applications/tari_validator_node/src/json_rpc/handlers.rs index 21a8a9948..fdfca9e16 100644 --- a/applications/tari_validator_node/src/json_rpc/handlers.rs +++ b/applications/tari_validator_node/src/json_rpc/handlers.rs @@ -370,7 +370,6 @@ impl JsonRpcHandlers { quorum_certificates: Some(created_qc) .into_iter() .chain(destroyed_qc) - .map(|qc| qc.into()) .collect() } } else { @@ -378,7 +377,7 @@ impl JsonRpcHandlers { status: SubstateStatus::Up, created_by_tx: Some(substate.created_by_transaction), value: Some(substate.into_substate_value()), - quorum_certificates: vec![created_qc.into()], + quorum_certificates: vec![created_qc], } }; diff --git a/dan_layer/consensus/src/block_validations.rs b/dan_layer/consensus/src/block_validations.rs index 2ecd69826..472897528 100644 --- a/dan_layer/consensus/src/block_validations.rs +++ b/dan_layer/consensus/src/block_validations.rs @@ -91,8 +91,8 @@ pub async fn check_quorum_certificate( .get_committee_shard_by_validator_public_key(candidate_block.epoch(), candidate_block.proposed_by()) .await?; - validate_quorum_certificate(&candidate_block.justify(), &committee_shard, vote_signing_service, epoch_manager).await - .map_err(|e| ProposalValidationError::QuorumCertificateValidationError(e))?; + validate_quorum_certificate(candidate_block.justify(), &committee_shard, vote_signing_service, epoch_manager).await + .map_err(ProposalValidationError::QuorumCertificateValidationError)?; Ok(()) } diff --git a/dan_layer/indexer_lib/src/substate_scanner.rs b/dan_layer/indexer_lib/src/substate_scanner.rs index 9f8fb10fe..6c78205bb 100644 --- a/dan_layer/indexer_lib/src/substate_scanner.rs +++ b/dan_layer/indexer_lib/src/substate_scanner.rs @@ -322,15 +322,15 @@ where // we are only checking that the QC is valid in isolation match &result { SubstateResult::DoesNotExist => (), - SubstateResult::Up { quorum_certificates, .. } => self.validate_substate_qcs(&quorum_certificates, shard).await?, - SubstateResult::Down { quorum_certificates, .. } => self.validate_substate_qcs(&quorum_certificates, shard).await?, + SubstateResult::Up { quorum_certificates, .. } => self.validate_substate_qcs(quorum_certificates, shard).await?, + SubstateResult::Down { quorum_certificates, .. } => self.validate_substate_qcs(quorum_certificates, shard).await?, } Ok(result) } /// Validates Quorum Certificates associated with a substate - async fn validate_substate_qcs(&self, qcs: &Vec, shard_id: ShardId) -> Result<(), IndexerError> { + async fn validate_substate_qcs(&self, qcs: &[QuorumCertificate], shard_id: ShardId) -> Result<(), IndexerError> { let qc = qcs.last() .ok_or(IndexerError::MissingQuorumCertificate)?; From 40e0711c9f5de169f7f9813c67c3f81689b662a9 Mon Sep 17 00:00:00 2001 From: mrnaveira <47919901+mrnaveira@users.noreply.github.com> Date: Mon, 15 Jan 2024 07:44:31 +0000 Subject: [PATCH 7/8] fix fmt --- .../src/signature_service.rs | 3 +- .../tari_indexer/src/dry_run/processor.rs | 18 +++++++++--- .../tari_indexer/src/json_rpc/handlers.rs | 14 +++++++-- applications/tari_indexer/src/lib.rs | 3 +- .../tari_indexer/src/substate_manager.rs | 19 +++++++++--- .../src/transaction_manager/mod.rs | 3 +- .../tari_validator_node/src/bootstrap.rs | 5 ++-- .../tari_validator_node/src/consensus/mod.rs | 5 +--- .../tari_validator_node/src/consensus/spec.rs | 5 +--- .../src/dry_run_transaction_processor.rs | 5 ++-- .../src/json_rpc/handlers.rs | 10 ++----- .../src/substate_resolver.rs | 10 +++++-- clients/validator_node_client/src/types.rs | 2 +- dan_layer/consensus/src/block_validations.rs | 13 +++++++-- .../src/quorum_certificate_validations.rs | 29 ++++++++++--------- dan_layer/indexer_lib/src/substate_scanner.rs | 28 +++++++++++------- .../indexer_lib/src/transaction_autofiller.rs | 9 ++++-- dan_layer/validator_node_rpc/src/client.rs | 20 +++++++++---- 18 files changed, 128 insertions(+), 73 deletions(-) diff --git a/applications/tari_dan_app_utilities/src/signature_service.rs b/applications/tari_dan_app_utilities/src/signature_service.rs index 8aa3382f8..025d00951 100644 --- a/applications/tari_dan_app_utilities/src/signature_service.rs +++ b/applications/tari_dan_app_utilities/src/signature_service.rs @@ -23,9 +23,10 @@ use rand::rngs::OsRng; use tari_common_types::types::{FixedHash, PublicKey}; use tari_consensus::traits::{ValidatorSignatureService, VoteSignatureService}; -use crate::keypair::RistrettoKeypair; use tari_dan_storage::consensus_models::{BlockId, QuorumDecision, ValidatorSchnorrSignature, ValidatorSignature}; +use crate::keypair::RistrettoKeypair; + #[derive(Debug, Clone)] pub struct TariSignatureService { keypair: RistrettoKeypair, diff --git a/applications/tari_indexer/src/dry_run/processor.rs b/applications/tari_indexer/src/dry_run/processor.rs index 2cfd89353..fa28564e6 100644 --- a/applications/tari_indexer/src/dry_run/processor.rs +++ b/applications/tari_indexer/src/dry_run/processor.rs @@ -24,8 +24,9 @@ use std::{collections::HashMap, sync::Arc}; use log::info; use tari_dan_app_utilities::{ + signature_service::TariSignatureService, template_manager::implementation::TemplateManager, - transaction_executor::{TariDanTransactionProcessor, TransactionExecutor}, signature_service::TariSignatureService, + transaction_executor::{TariDanTransactionProcessor, TransactionExecutor}, }; use tari_dan_common_types::{Epoch, PeerAddress, ShardId}; use tari_dan_engine::{ @@ -61,8 +62,12 @@ const LOG_TARGET: &str = "tari::indexer::dry_run_transaction_processor"; pub struct DryRunTransactionProcessor { epoch_manager: EpochManagerHandle, client_provider: TariValidatorNodeRpcClientFactory, - transaction_autofiller: - TransactionAutofiller, TariValidatorNodeRpcClientFactory, TSubstateCache, TariSignatureService>, + transaction_autofiller: TransactionAutofiller< + EpochManagerHandle, + TariValidatorNodeRpcClientFactory, + TSubstateCache, + TariSignatureService, + >, template_manager: TemplateManager, } @@ -73,7 +78,12 @@ where TSubstateCache: SubstateCache + 'static epoch_manager: EpochManagerHandle, client_provider: TariValidatorNodeRpcClientFactory, substate_scanner: Arc< - SubstateScanner, TariValidatorNodeRpcClientFactory, TSubstateCache, TariSignatureService>, + SubstateScanner< + EpochManagerHandle, + TariValidatorNodeRpcClientFactory, + TSubstateCache, + TariSignatureService, + >, >, template_manager: TemplateManager, ) -> Self { diff --git a/applications/tari_indexer/src/json_rpc/handlers.rs b/applications/tari_indexer/src/json_rpc/handlers.rs index b86dede7f..d338c4999 100644 --- a/applications/tari_indexer/src/json_rpc/handlers.rs +++ b/applications/tari_indexer/src/json_rpc/handlers.rs @@ -32,7 +32,11 @@ use libp2p::swarm::dial_opts::{DialOpts, PeerCondition}; use log::{error, warn}; use serde_json::{self as json, json, Value}; use tari_base_node_client::{grpc::GrpcBaseNodeClient, types::BaseLayerConsensusConstants, BaseNodeClient}; -use tari_dan_app_utilities::{keypair::RistrettoKeypair, substate_file_cache::SubstateFileCache, signature_service::TariSignatureService}; +use tari_dan_app_utilities::{ + keypair::RistrettoKeypair, + signature_service::TariSignatureService, + substate_file_cache::SubstateFileCache, +}; use tari_dan_common_types::{optional::Optional, public_key_to_peer_id, Epoch, PeerAddress}; use tari_dan_storage::consensus_models::Decision; use tari_epoch_manager::{base_layer::EpochManagerHandle, EpochManagerReader}; @@ -92,8 +96,12 @@ pub struct JsonRpcHandlers { base_node_client: GrpcBaseNodeClient, substate_manager: Arc, epoch_manager: EpochManagerHandle, - transaction_manager: - TransactionManager, TariValidatorNodeRpcClientFactory, SubstateFileCache, TariSignatureService>, + transaction_manager: TransactionManager< + EpochManagerHandle, + TariValidatorNodeRpcClientFactory, + SubstateFileCache, + TariSignatureService, + >, dry_run_transaction_processor: DryRunTransactionProcessor, } diff --git a/applications/tari_indexer/src/lib.rs b/applications/tari_indexer/src/lib.rs index 31b301edb..c73a1ef9b 100644 --- a/applications/tari_indexer/src/lib.rs +++ b/applications/tari_indexer/src/lib.rs @@ -50,7 +50,8 @@ use tari_common::{ use tari_dan_app_utilities::{ consensus_constants::ConsensusConstants, keypair::setup_keypair_prompt, - substate_file_cache::SubstateFileCache, signature_service::TariSignatureService, + signature_service::TariSignatureService, + substate_file_cache::SubstateFileCache, }; use tari_dan_storage::global::DbFactory; use tari_dan_storage_sqlite::SqliteDbFactory; diff --git a/applications/tari_indexer/src/substate_manager.rs b/applications/tari_indexer/src/substate_manager.rs index 711100a56..ec61ccabd 100644 --- a/applications/tari_indexer/src/substate_manager.rs +++ b/applications/tari_indexer/src/substate_manager.rs @@ -27,7 +27,7 @@ use log::info; use serde::{Deserialize, Serialize}; use tari_common_types::types::FixedHash; use tari_crypto::tari_utilities::message_format::MessageFormat; -use tari_dan_app_utilities::{substate_file_cache::SubstateFileCache, signature_service::TariSignatureService}; +use tari_dan_app_utilities::{signature_service::TariSignatureService, substate_file_cache::SubstateFileCache}; use tari_dan_common_types::PeerAddress; use tari_engine_types::{ events::Event, @@ -81,15 +81,26 @@ pub struct EventResponse { } pub struct SubstateManager { - substate_scanner: - Arc, TariValidatorNodeRpcClientFactory, SubstateFileCache, TariSignatureService>>, + substate_scanner: Arc< + SubstateScanner< + EpochManagerHandle, + TariValidatorNodeRpcClientFactory, + SubstateFileCache, + TariSignatureService, + >, + >, substate_store: SqliteSubstateStore, } impl SubstateManager { pub fn new( dan_layer_scanner: Arc< - SubstateScanner, TariValidatorNodeRpcClientFactory, SubstateFileCache, TariSignatureService>, + SubstateScanner< + EpochManagerHandle, + TariValidatorNodeRpcClientFactory, + SubstateFileCache, + TariSignatureService, + >, >, substate_store: SqliteSubstateStore, ) -> Self { diff --git a/applications/tari_indexer/src/transaction_manager/mod.rs b/applications/tari_indexer/src/transaction_manager/mod.rs index 1bce67554..bcbefdc1c 100644 --- a/applications/tari_indexer/src/transaction_manager/mod.rs +++ b/applications/tari_indexer/src/transaction_manager/mod.rs @@ -28,7 +28,8 @@ use log::*; use tari_consensus::traits::VoteSignatureService; use tari_dan_common_types::{ optional::{IsNotFoundError, Optional}, - ShardId, DerivableFromPublicKey, + DerivableFromPublicKey, + ShardId, }; use tari_engine_types::substate::SubstateAddress; use tari_epoch_manager::EpochManagerReader; diff --git a/applications/tari_validator_node/src/bootstrap.rs b/applications/tari_validator_node/src/bootstrap.rs index d88f597fc..94dfa7cdc 100644 --- a/applications/tari_validator_node/src/bootstrap.rs +++ b/applications/tari_validator_node/src/bootstrap.rs @@ -42,10 +42,11 @@ use tari_dan_app_utilities::{ consensus_constants::ConsensusConstants, keypair::RistrettoKeypair, seed_peer::SeedPeer, + signature_service::TariSignatureService, substate_file_cache::SubstateFileCache, template_manager, template_manager::{implementation::TemplateManager, interface::TemplateManagerHandle}, - transaction_executor::TariDanTransactionProcessor, signature_service::TariSignatureService, + transaction_executor::TariDanTransactionProcessor, }; use tari_dan_common_types::{Epoch, NodeAddressable, NodeHeight, PeerAddress, ShardId}; use tari_dan_engine::fees::FeeTable; @@ -258,7 +259,7 @@ pub async fn spawn_services( epoch_manager.clone(), validator_node_client_factory.clone(), substate_cache, - signing_service + signing_service, ); let substate_resolver = TariSubstateResolver::new( state_store.clone(), diff --git a/applications/tari_validator_node/src/consensus/mod.rs b/applications/tari_validator_node/src/consensus/mod.rs index 2d3becef8..8538a36e1 100644 --- a/applications/tari_validator_node/src/consensus/mod.rs +++ b/applications/tari_validator_node/src/consensus/mod.rs @@ -20,10 +20,7 @@ use tokio::{ }; use crate::{ - consensus::{ - leader_selection::RoundRobinLeaderStrategy, - state_manager::TariStateManager, - }, + consensus::{leader_selection::RoundRobinLeaderStrategy, state_manager::TariStateManager}, event_subscription::EventSubscription, }; diff --git a/applications/tari_validator_node/src/consensus/spec.rs b/applications/tari_validator_node/src/consensus/spec.rs index 3d4da5f9b..41badb461 100644 --- a/applications/tari_validator_node/src/consensus/spec.rs +++ b/applications/tari_validator_node/src/consensus/spec.rs @@ -8,10 +8,7 @@ use tari_dan_common_types::PeerAddress; use tari_epoch_manager::base_layer::EpochManagerHandle; use tari_state_store_sqlite::SqliteStateStore; -use crate::consensus::{ - leader_selection::RoundRobinLeaderStrategy, - state_manager::TariStateManager, -}; +use crate::consensus::{leader_selection::RoundRobinLeaderStrategy, state_manager::TariStateManager}; #[derive(Clone)] pub struct TariConsensusSpec; diff --git a/applications/tari_validator_node/src/dry_run_transaction_processor.rs b/applications/tari_validator_node/src/dry_run_transaction_processor.rs index aef5960bc..1ad6190c4 100644 --- a/applications/tari_validator_node/src/dry_run_transaction_processor.rs +++ b/applications/tari_validator_node/src/dry_run_transaction_processor.rs @@ -22,9 +22,10 @@ use log::info; use tari_dan_app_utilities::{ + signature_service::TariSignatureService, substate_file_cache::SubstateFileCache, template_manager::implementation::TemplateManager, - transaction_executor::{TariDanTransactionProcessor, TransactionExecutor, TransactionProcessorError}, signature_service::TariSignatureService, + transaction_executor::{TariDanTransactionProcessor, TransactionExecutor, TransactionProcessorError}, }; use tari_dan_common_types::PeerAddress; use tari_dan_engine::{ @@ -77,7 +78,7 @@ pub struct DryRunTransactionProcessor { EpochManagerHandle, TariValidatorNodeRpcClientFactory, SubstateFileCache, - TariSignatureService + TariSignatureService, >, epoch_manager: EpochManagerHandle, payload_processor: TariDanTransactionProcessor>, diff --git a/applications/tari_validator_node/src/json_rpc/handlers.rs b/applications/tari_validator_node/src/json_rpc/handlers.rs index fdfca9e16..980536f8f 100644 --- a/applications/tari_validator_node/src/json_rpc/handlers.rs +++ b/applications/tari_validator_node/src/json_rpc/handlers.rs @@ -337,10 +337,7 @@ impl JsonRpcHandlers { let data: GetSubstateRequest = value.parse_params()?; let shard_id = ShardId::from_address(&data.address, data.version); - let mut tx = self - .state_store - .create_read_tx() - .map_err(internal_error(answer_id))?; + let mut tx = self.state_store.create_read_tx().map_err(internal_error(answer_id))?; let maybe_substate = SubstateRecord::get(&mut tx, &shard_id) .optional() @@ -367,10 +364,7 @@ impl JsonRpcHandlers { status: SubstateStatus::Down, created_by_tx: Some(substate.created_by_transaction), value: None, - quorum_certificates: Some(created_qc) - .into_iter() - .chain(destroyed_qc) - .collect() + quorum_certificates: Some(created_qc).into_iter().chain(destroyed_qc).collect(), } } else { GetSubstateResponse { diff --git a/applications/tari_validator_node/src/substate_resolver.rs b/applications/tari_validator_node/src/substate_resolver.rs index ceb034b6a..f520ba821 100644 --- a/applications/tari_validator_node/src/substate_resolver.rs +++ b/applications/tari_validator_node/src/substate_resolver.rs @@ -7,7 +7,7 @@ use async_trait::async_trait; use log::*; use tari_common_types::types::PublicKey; use tari_consensus::traits::VoteSignatureService; -use tari_dan_common_types::{Epoch, ShardId, DerivableFromPublicKey}; +use tari_dan_common_types::{DerivableFromPublicKey, Epoch, ShardId}; use tari_dan_engine::{runtime::VirtualSubstates, state_store::memory::MemoryStateStore}; use tari_dan_storage::{consensus_models::SubstateRecord, StateStore, StorageError}; use tari_engine_types::{ @@ -28,7 +28,13 @@ use crate::{ const LOG_TARGET: &str = "tari::dan::substate_resolver"; #[derive(Debug, Clone)] -pub struct TariSubstateResolver { +pub struct TariSubstateResolver< + TStateStore, + TEpochManager, + TValidatorNodeClientFactory, + TSubstateCache, + TSignatureService, +> { store: TStateStore, scanner: SubstateScanner, epoch_manager: TEpochManager, diff --git a/clients/validator_node_client/src/types.rs b/clients/validator_node_client/src/types.rs index e18e1b5d5..cc57b9fd6 100644 --- a/clients/validator_node_client/src/types.rs +++ b/clients/validator_node_client/src/types.rs @@ -27,7 +27,7 @@ use serde::{Deserialize, Serialize}; use tari_common_types::{transaction::TxId, types::PublicKey}; use tari_dan_common_types::{committee::CommitteeShard, shard_bucket::ShardBucket, Epoch, ShardId}; use tari_dan_storage::{ - consensus_models::{Block, BlockId, ExecutedTransaction, QuorumDecision, SubstateRecord, QuorumCertificate}, + consensus_models::{Block, BlockId, ExecutedTransaction, QuorumCertificate, QuorumDecision, SubstateRecord}, global::models::ValidatorNode, Ordering, }; diff --git a/dan_layer/consensus/src/block_validations.rs b/dan_layer/consensus/src/block_validations.rs index 472897528..f3a9e4ca4 100644 --- a/dan_layer/consensus/src/block_validations.rs +++ b/dan_layer/consensus/src/block_validations.rs @@ -7,7 +7,8 @@ use tari_epoch_manager::EpochManagerReader; use crate::{ hotstuff::{HotStuffError, ProposalValidationError}, - traits::{ConsensusSpec, LeaderStrategy}, quorum_certificate_validations::validate_quorum_certificate, + quorum_certificate_validations::validate_quorum_certificate, + traits::{ConsensusSpec, LeaderStrategy}, }; pub fn check_hash_and_height(candidate_block: &Block) -> Result<(), ProposalValidationError> { @@ -91,8 +92,14 @@ pub async fn check_quorum_certificate( .get_committee_shard_by_validator_public_key(candidate_block.epoch(), candidate_block.proposed_by()) .await?; - validate_quorum_certificate(candidate_block.justify(), &committee_shard, vote_signing_service, epoch_manager).await - .map_err(ProposalValidationError::QuorumCertificateValidationError)?; + validate_quorum_certificate( + candidate_block.justify(), + &committee_shard, + vote_signing_service, + epoch_manager, + ) + .await + .map_err(ProposalValidationError::QuorumCertificateValidationError)?; Ok(()) } diff --git a/dan_layer/consensus/src/quorum_certificate_validations.rs b/dan_layer/consensus/src/quorum_certificate_validations.rs index baf37541e..53eb51d05 100644 --- a/dan_layer/consensus/src/quorum_certificate_validations.rs +++ b/dan_layer/consensus/src/quorum_certificate_validations.rs @@ -20,11 +20,11 @@ // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -use crate::traits::VoteSignatureService; -use tari_dan_common_types::{committee::CommitteeShard, NodeHeight, DerivableFromPublicKey}; +use tari_dan_common_types::{committee::CommitteeShard, DerivableFromPublicKey, NodeHeight}; use tari_dan_storage::consensus_models::QuorumCertificate; -use tari_epoch_manager::{EpochManagerReader, EpochManagerError}; +use tari_epoch_manager::{EpochManagerError, EpochManagerReader}; +use crate::traits::VoteSignatureService; #[derive(Debug, thiserror::Error)] pub enum QuorumCertificateValidationError { @@ -48,12 +48,14 @@ pub enum QuorumCertificateValidationError { /// Validates Quorum Certificates in isolation pub async fn validate_quorum_certificate< TAddr: DerivableFromPublicKey, - TEpochManager: EpochManagerReader, - TSignatureService: VoteSignatureService> - (qc: &QuorumCertificate, committee_shard: &CommitteeShard, + TEpochManager: EpochManagerReader, + TSignatureService: VoteSignatureService, +>( + qc: &QuorumCertificate, + committee_shard: &CommitteeShard, vote_signing_service: &TSignatureService, epoch_manager: &TEpochManager, -) -> Result<(), QuorumCertificateValidationError> { +) -> Result<(), QuorumCertificateValidationError> { // ignore genesis block. if qc.epoch().as_u64() == 0 { return Ok(()); @@ -69,12 +71,11 @@ pub async fn validate_quorum_certificate< } // validate the QC's merkle proof - let merkle_root = epoch_manager - .get_validator_node_merkle_root(qc.epoch()) - .await?; + let merkle_root = epoch_manager.get_validator_node_merkle_root(qc.epoch()).await?; let proof = qc.merged_proof().clone(); let vns_bytes = vns.iter().map(|hash| hash.to_vec()).collect(); - let is_proof_valid = proof.verify_consume(&merkle_root, vns_bytes) + let is_proof_valid = proof + .verify_consume(&merkle_root, vns_bytes) .map_err(|_| QuorumCertificateValidationError::InvalidMerkleProof)?; if !is_proof_valid { return Err(QuorumCertificateValidationError::InvalidMerkleProof); @@ -89,11 +90,11 @@ pub async fn validate_quorum_certificate< } // validate that enough committee members have signed the QC - let num_signatures_in_qc = u32::try_from(qc.signatures().len()) - .map_err(|_| QuorumCertificateValidationError::MalformedCertificate)?; + let num_signatures_in_qc = + u32::try_from(qc.signatures().len()).map_err(|_| QuorumCertificateValidationError::MalformedCertificate)?; if committee_shard.quorum_threshold() > num_signatures_in_qc { return Err(QuorumCertificateValidationError::QuorumWasNotReached); } - + Ok(()) } diff --git a/dan_layer/indexer_lib/src/substate_scanner.rs b/dan_layer/indexer_lib/src/substate_scanner.rs index 6c78205bb..e8a089802 100644 --- a/dan_layer/indexer_lib/src/substate_scanner.rs +++ b/dan_layer/indexer_lib/src/substate_scanner.rs @@ -22,8 +22,9 @@ use log::*; use rand::{prelude::*, rngs::OsRng}; -use tari_consensus::{traits::VoteSignatureService, quorum_certificate_validations::validate_quorum_certificate}; -use tari_dan_common_types::{ShardId, DerivableFromPublicKey}; +use tari_consensus::{quorum_certificate_validations::validate_quorum_certificate, traits::VoteSignatureService}; +use tari_dan_common_types::{DerivableFromPublicKey, ShardId}; +use tari_dan_storage::consensus_models::QuorumCertificate; use tari_engine_types::{ events::Event, substate::{SubstateAddress, SubstateValue}, @@ -36,7 +37,7 @@ use tari_template_lib::{ }; use tari_transaction::TransactionId; use tari_validator_node_rpc::client::{SubstateResult, ValidatorNodeClientFactory, ValidatorNodeRpcClient}; -use tari_dan_storage::consensus_models::QuorumCertificate; + use crate::{ error::IndexerError, substate_cache::{SubstateCache, SubstateCacheEntry}, @@ -53,7 +54,8 @@ pub struct SubstateScanner SubstateScanner +impl + SubstateScanner where TAddr: DerivableFromPublicKey, TEpochManager: EpochManagerReader, @@ -71,7 +73,7 @@ where committee_provider, validator_node_client_factory, substate_cache, - signing_service + signing_service, } } @@ -322,8 +324,12 @@ where // we are only checking that the QC is valid in isolation match &result { SubstateResult::DoesNotExist => (), - SubstateResult::Up { quorum_certificates, .. } => self.validate_substate_qcs(quorum_certificates, shard).await?, - SubstateResult::Down { quorum_certificates, .. } => self.validate_substate_qcs(quorum_certificates, shard).await?, + SubstateResult::Up { + quorum_certificates, .. + } => self.validate_substate_qcs(quorum_certificates, shard).await?, + SubstateResult::Down { + quorum_certificates, .. + } => self.validate_substate_qcs(quorum_certificates, shard).await?, } Ok(result) @@ -331,13 +337,13 @@ where /// Validates Quorum Certificates associated with a substate async fn validate_substate_qcs(&self, qcs: &[QuorumCertificate], shard_id: ShardId) -> Result<(), IndexerError> { - let qc = qcs.last() - .ok_or(IndexerError::MissingQuorumCertificate)?; + let qc = qcs.last().ok_or(IndexerError::MissingQuorumCertificate)?; - let committee_shard = self.committee_provider + let committee_shard = self + .committee_provider .get_committee_shard(qc.epoch(), shard_id) .await?; - + validate_quorum_certificate(qc, &committee_shard, &self.signing_service, &self.committee_provider).await?; Ok(()) diff --git a/dan_layer/indexer_lib/src/transaction_autofiller.rs b/dan_layer/indexer_lib/src/transaction_autofiller.rs index 8afc2fcf7..bb638c054 100644 --- a/dan_layer/indexer_lib/src/transaction_autofiller.rs +++ b/dan_layer/indexer_lib/src/transaction_autofiller.rs @@ -5,7 +5,7 @@ use std::{collections::HashMap, sync::Arc}; use log::*; use tari_consensus::traits::VoteSignatureService; -use tari_dan_common_types::{ShardId, DerivableFromPublicKey}; +use tari_dan_common_types::{DerivableFromPublicKey, ShardId}; use tari_engine_types::{ indexed_value::IndexedValueError, substate::{Substate, SubstateAddress}, @@ -38,7 +38,8 @@ pub struct TransactionAutofiller>, } -impl TransactionAutofiller +impl + TransactionAutofiller where TEpochManager: EpochManagerReader + 'static, TVnClient: ValidatorNodeClientFactory + 'static, @@ -46,7 +47,9 @@ where TSubstateCache: SubstateCache + 'static, TSignatureService: VoteSignatureService + Send + Sync + 'static, { - pub fn new(substate_scanner: Arc>) -> Self { + pub fn new( + substate_scanner: Arc>, + ) -> Self { Self { substate_scanner } } diff --git a/dan_layer/validator_node_rpc/src/client.rs b/dan_layer/validator_node_rpc/src/client.rs index a8d96b6c4..1de70e713 100644 --- a/dan_layer/validator_node_rpc/src/client.rs +++ b/dan_layer/validator_node_rpc/src/client.rs @@ -146,17 +146,22 @@ impl ValidatorNodeRpcClient for TariValidatorNodeRpcClient { })?; let substate = SubstateValue::from_bytes(&resp.substate) .map_err(|e| ValidatorNodeRpcClientError::InvalidResponse(anyhow!(e)))?; - let quorum_certificates = resp.quorum_certificates + let quorum_certificates = resp + .quorum_certificates .into_iter() .map(|qc| qc.try_into()) .collect::>() - .map_err(|_| ValidatorNodeRpcClientError::InvalidResponse(anyhow!("Node returned invalid quorum certificates")))?; + .map_err(|_| { + ValidatorNodeRpcClientError::InvalidResponse(anyhow!( + "Node returned invalid quorum certificates" + )) + })?; Ok(SubstateResult::Up { substate: Substate::new(resp.version, substate), address: SubstateAddress::from_bytes(&resp.address) .map_err(|e| ValidatorNodeRpcClientError::InvalidResponse(anyhow!(e)))?, created_by_tx: tx_hash, - quorum_certificates + quorum_certificates, }) }, SubstateStatus::Down => { @@ -170,11 +175,16 @@ impl ValidatorNodeRpcClient for TariValidatorNodeRpcClient { "Node returned an invalid or empty destroyed transaction hash" )) })?; - let quorum_certificates = resp.quorum_certificates + let quorum_certificates = resp + .quorum_certificates .into_iter() .map(|qc| qc.try_into()) .collect::>() - .map_err(|_| ValidatorNodeRpcClientError::InvalidResponse(anyhow!("Node returned invalid quorum certificates")))?; + .map_err(|_| { + ValidatorNodeRpcClientError::InvalidResponse(anyhow!( + "Node returned invalid quorum certificates" + )) + })?; Ok(SubstateResult::Down { address: SubstateAddress::from_bytes(&resp.address) .map_err(|e| ValidatorNodeRpcClientError::InvalidResponse(anyhow!(e)))?, From 6f5dca6c718eb5bbfce8b9a71beb8e1db50efb02 Mon Sep 17 00:00:00 2001 From: mrnaveira <47919901+mrnaveira@users.noreply.github.com> Date: Tue, 30 Jan 2024 15:48:32 +0000 Subject: [PATCH 8/8] fix fmt --- .../tari_indexer/src/dry_run/processor.rs | 10 ++++++++-- applications/tari_indexer/src/lib.rs | 2 +- .../tari_validator_node/src/bootstrap.rs | 2 +- .../tari_validator_node/src/consensus/spec.rs | 5 +---- clients/validator_node_client/src/types.rs | 10 +++++++++- dan_layer/consensus/src/block_validations.rs | 10 +++++----- dan_layer/consensus/src/hotstuff/error.rs | 7 ++++--- dan_layer/indexer_lib/src/substate_scanner.rs | 17 ++++++++++++++--- 8 files changed, 43 insertions(+), 20 deletions(-) diff --git a/applications/tari_indexer/src/dry_run/processor.rs b/applications/tari_indexer/src/dry_run/processor.rs index 5049b78da..f38d3aa95 100644 --- a/applications/tari_indexer/src/dry_run/processor.rs +++ b/applications/tari_indexer/src/dry_run/processor.rs @@ -71,8 +71,14 @@ pub struct DryRunTransactionProcessor { TariSignatureService, >, template_manager: TemplateManager, - substate_scanner: - Arc, TariValidatorNodeRpcClientFactory, TSubstateCache, TariSignatureService>>, + substate_scanner: Arc< + SubstateScanner< + EpochManagerHandle, + TariValidatorNodeRpcClientFactory, + TSubstateCache, + TariSignatureService, + >, + >, network: Network, } diff --git a/applications/tari_indexer/src/lib.rs b/applications/tari_indexer/src/lib.rs index 2e8dac154..890a87713 100644 --- a/applications/tari_indexer/src/lib.rs +++ b/applications/tari_indexer/src/lib.rs @@ -111,7 +111,7 @@ pub async fn run_indexer(config: ApplicationConfig, mut shutdown_signal: Shutdow services.validator_node_client_factory.clone(), substate_cache, signing_service, - config.network + config.network, )); let substate_manager = Arc::new(SubstateManager::new( diff --git a/applications/tari_validator_node/src/bootstrap.rs b/applications/tari_validator_node/src/bootstrap.rs index ca74db75c..0cb6ac777 100644 --- a/applications/tari_validator_node/src/bootstrap.rs +++ b/applications/tari_validator_node/src/bootstrap.rs @@ -271,7 +271,7 @@ pub async fn spawn_services( validator_node_client_factory.clone(), substate_cache, signing_service, - config.network + config.network, ); let substate_resolver = TariSubstateResolver::new( state_store.clone(), diff --git a/applications/tari_validator_node/src/consensus/spec.rs b/applications/tari_validator_node/src/consensus/spec.rs index 8b8685354..94cd049ad 100644 --- a/applications/tari_validator_node/src/consensus/spec.rs +++ b/applications/tari_validator_node/src/consensus/spec.rs @@ -10,10 +10,7 @@ use tari_rpc_state_sync::RpcStateSyncManager; use tari_state_store_sqlite::SqliteStateStore; use crate::{ - consensus::{ - leader_selection::RoundRobinLeaderStrategy, - state_manager::TariStateManager, - }, + consensus::{leader_selection::RoundRobinLeaderStrategy, state_manager::TariStateManager}, p2p::services::messaging::{ConsensusInboundMessaging, ConsensusOutboundMessaging}, }; diff --git a/clients/validator_node_client/src/types.rs b/clients/validator_node_client/src/types.rs index 14f5afca2..a82609b0c 100644 --- a/clients/validator_node_client/src/types.rs +++ b/clients/validator_node_client/src/types.rs @@ -27,7 +27,15 @@ use serde::{Deserialize, Serialize}; use tari_common_types::{transaction::TxId, types::PublicKey}; use tari_dan_common_types::{committee::CommitteeShard, shard::Shard, Epoch, SubstateAddress}; use tari_dan_storage::{ - consensus_models::{Block, BlockId, Decision, ExecutedTransaction, QuorumCertificate, QuorumDecision, SubstateRecord}, + consensus_models::{ + Block, + BlockId, + Decision, + ExecutedTransaction, + QuorumCertificate, + QuorumDecision, + SubstateRecord, + }, global::models::ValidatorNode, Ordering, }; diff --git a/dan_layer/consensus/src/block_validations.rs b/dan_layer/consensus/src/block_validations.rs index 301c89536..60dd6212f 100644 --- a/dan_layer/consensus/src/block_validations.rs +++ b/dan_layer/consensus/src/block_validations.rs @@ -7,7 +7,9 @@ use tari_dan_storage::consensus_models::Block; use tari_epoch_manager::EpochManagerReader; use crate::{ - hotstuff::{HotStuffError, ProposalValidationError}, quorum_certificate_validations::validate_quorum_certificate, traits::{ConsensusSpec, LeaderStrategy} + hotstuff::{HotStuffError, ProposalValidationError}, + quorum_certificate_validations::validate_quorum_certificate, + traits::{ConsensusSpec, LeaderStrategy}, }; pub fn check_network(candidate_block: &Block, network: Network) -> Result<(), ProposalValidationError> { @@ -99,9 +101,7 @@ pub async fn check_quorum_certificate( } let committee_shard = epoch_manager - .get_committee_shard_by_validator_public_key( - candidate_block.epoch(), candidate_block.proposed_by(), - ) + .get_committee_shard_by_validator_public_key(candidate_block.epoch(), candidate_block.proposed_by()) .await?; validate_quorum_certificate( @@ -109,7 +109,7 @@ pub async fn check_quorum_certificate( &committee_shard, vote_signing_service, epoch_manager, - candidate_block.network() + candidate_block.network(), ) .await .map_err(ProposalValidationError::QuorumCertificateValidationError)?; diff --git a/dan_layer/consensus/src/hotstuff/error.rs b/dan_layer/consensus/src/hotstuff/error.rs index d2f30dcf2..bddcabaf6 100644 --- a/dan_layer/consensus/src/hotstuff/error.rs +++ b/dan_layer/consensus/src/hotstuff/error.rs @@ -10,9 +10,10 @@ use tari_epoch_manager::EpochManagerError; use tari_mmr::BalancedBinaryMerkleProofError; use tari_transaction::TransactionId; -use crate::quorum_certificate_validations::QuorumCertificateValidationError; - -use crate::traits::{InboundMessagingError, OutboundMessagingError}; +use crate::{ + quorum_certificate_validations::QuorumCertificateValidationError, + traits::{InboundMessagingError, OutboundMessagingError}, +}; #[derive(Debug, thiserror::Error)] pub enum HotStuffError { diff --git a/dan_layer/indexer_lib/src/substate_scanner.rs b/dan_layer/indexer_lib/src/substate_scanner.rs index db2c55313..b32122c7f 100644 --- a/dan_layer/indexer_lib/src/substate_scanner.rs +++ b/dan_layer/indexer_lib/src/substate_scanner.rs @@ -22,8 +22,8 @@ use log::*; use rand::{prelude::*, rngs::OsRng}; -use tari_consensus::{quorum_certificate_validations::validate_quorum_certificate, traits::VoteSignatureService}; use tari_common::configuration::Network; +use tari_consensus::{quorum_certificate_validations::validate_quorum_certificate, traits::VoteSignatureService}; use tari_dan_common_types::{DerivableFromPublicKey, SubstateAddress}; use tari_dan_storage::consensus_models::QuorumCertificate; use tari_engine_types::{ @@ -347,7 +347,11 @@ where } /// Validates Quorum Certificates associated with a substate - async fn validate_substate_qcs(&self, qcs: &[QuorumCertificate], shard_id: SubstateAddress) -> Result<(), IndexerError> { + async fn validate_substate_qcs( + &self, + qcs: &[QuorumCertificate], + shard_id: SubstateAddress, + ) -> Result<(), IndexerError> { let qc = qcs.last().ok_or(IndexerError::MissingQuorumCertificate)?; let committee_shard = self @@ -355,7 +359,14 @@ where .get_committee_shard(qc.epoch(), shard_id) .await?; - validate_quorum_certificate(qc, &committee_shard, &self.signing_service, &self.committee_provider, self.network).await?; + validate_quorum_certificate( + qc, + &committee_shard, + &self.signing_service, + &self.committee_provider, + self.network, + ) + .await?; Ok(()) }