From d436226255ee95a137ab8c411c1734c088b63970 Mon Sep 17 00:00:00 2001 From: Stan Bondi Date: Fri, 27 Dec 2024 16:16:11 +0200 Subject: [PATCH] fixes for global transaction, added new consensus test --- .../src/base_layer_scanner.rs | 3 + .../implementation/manager.rs | 24 ++--- .../implementation/service.rs | 7 +- .../src/template_manager/interface/handle.rs | 3 + .../src/template_manager/interface/types.rs | 2 + .../tari_validator_node/src/bootstrap.rs | 1 - .../tari_validator_node/src/dan_node.rs | 4 +- .../src/p2p/services/mempool/gossip.rs | 58 ++++++------ .../src/p2p/services/mempool/initializer.rs | 4 +- .../src/p2p/services/mempool/service.rs | 5 +- dan_layer/common_types/src/committee.rs | 7 ++ dan_layer/common_types/src/lock_intent.rs | 4 + dan_layer/common_types/src/num_preshards.rs | 51 ++++++++++ .../src/services/template_provider.rs | 8 -- .../common_types/src/substate_address.rs | 16 ++++ .../src/hotstuff/block_change_set.rs | 6 +- .../hotstuff/foreign_proposal_processor.rs | 6 +- .../consensus/src/hotstuff/on_propose.rs | 11 ++- .../on_ready_to_vote_on_local_block.rs | 12 +-- .../src/hotstuff/on_receive_local_proposal.rs | 42 +++------ .../hotstuff/on_receive_new_transaction.rs | 9 +- .../hotstuff/transaction_manager/manager.rs | 3 +- .../hotstuff/transaction_manager/prepared.rs | 4 +- dan_layer/consensus_tests/fixtures/state.wasm | Bin 0 -> 368204 bytes dan_layer/consensus_tests/src/consensus.rs | 87 +++++++++++++++++- dan_layer/consensus_tests/src/dummy_blocks.rs | 6 +- .../consensus_tests/src/eviction_proof.rs | 4 +- .../consensus_tests/src/support/fixtures.rs | 14 ++- .../src/support/transaction.rs | 66 ++++++++----- dan_layer/engine_types/src/instruction.rs | 9 ++ dan_layer/engine_types/src/substate.rs | 4 + .../up.sql | 45 ++++----- dan_layer/state_store_sqlite/src/schema.rs | 1 + .../src/sql_models/transaction_pool.rs | 2 + dan_layer/state_store_sqlite/src/writer.rs | 2 + dan_layer/state_store_sqlite/tests/tests.rs | 9 +- .../src/consensus_models/block_diff.rs | 3 +- .../storage/src/consensus_models/evidence.rs | 19 ++-- .../storage/src/consensus_models/no_vote.rs | 6 +- .../src/consensus_models/transaction_pool.rs | 44 +++++++-- dan_layer/storage/src/global/template_db.rs | 2 + dan_layer/storage/src/state_store/mod.rs | 1 + .../2022-06-20-091532_initial/up.sql | 29 +++--- .../down.sql | 8 -- .../up.sql | 6 -- .../src/global/backend_adapter.rs | 4 + .../src/global/models/template.rs | 10 +- dan_layer/storage_sqlite/src/global/schema.rs | 9 +- .../src/package_builder.rs | 14 --- 49 files changed, 452 insertions(+), 242 deletions(-) create mode 100755 dan_layer/consensus_tests/fixtures/state.wasm delete mode 100644 dan_layer/storage_sqlite/migrations/2024-12-06-134951_templates_on_chain_updates/down.sql delete mode 100644 dan_layer/storage_sqlite/migrations/2024-12-06-134951_templates_on_chain_updates/up.sql diff --git a/applications/tari_dan_app_utilities/src/base_layer_scanner.rs b/applications/tari_dan_app_utilities/src/base_layer_scanner.rs index 9d407a121..02ef8be6f 100644 --- a/applications/tari_dan_app_utilities/src/base_layer_scanner.rs +++ b/applications/tari_dan_app_utilities/src/base_layer_scanner.rs @@ -475,6 +475,8 @@ impl BaseLayerScanner { target: LOG_TARGET, "🌠 new template found with address {} at height {}", template_address, block_info.height ); + let consensus_constants = self.epoch_manager.get_base_layer_consensus_constants().await?; + let epoch = consensus_constants.height_to_epoch(block_info.height); self.template_manager .add_template( registration.author_public_key, @@ -484,6 +486,7 @@ impl BaseLayerScanner { registration.binary_sha, ), Some(template_name), + epoch, ) .await?; diff --git a/applications/tari_dan_app_utilities/src/template_manager/implementation/manager.rs b/applications/tari_dan_app_utilities/src/template_manager/implementation/manager.rs index f65504c63..aab37f575 100644 --- a/applications/tari_dan_app_utilities/src/template_manager/implementation/manager.rs +++ b/applications/tari_dan_app_utilities/src/template_manager/implementation/manager.rs @@ -26,7 +26,12 @@ use chrono::Utc; use log::*; use tari_common_types::types::{FixedHash, PublicKey}; use tari_crypto::tari_utilities::ByteArray; -use tari_dan_common_types::{optional::Optional, services::template_provider::TemplateProvider, NodeAddressable}; +use tari_dan_common_types::{ + optional::Optional, + services::template_provider::TemplateProvider, + Epoch, + NodeAddressable, +}; use tari_dan_engine::{ flow::FlowFactory, function_definitions::FlowFunctionDefinition, @@ -192,6 +197,7 @@ impl TemplateManager { template: TemplateExecutable, template_name: Option, template_status: Option, + epoch: Epoch, ) -> Result<(), TemplateManagerError> { enum TemplateHash { Hash(Hash), @@ -244,6 +250,7 @@ impl TemplateManager { flow_json, manifest, url: template_url, + epoch, }; let mut tx = self.global_db.create_transaction()?; @@ -326,21 +333,6 @@ impl TemplateProvider for Templa Ok(Some(loaded)) } - - fn add_wasm_template( - &self, - author_public_key: PublicKey, - template_address: tari_engine_types::TemplateAddress, - template: &[u8], - ) -> Result<(), Self::Error> { - self.add_template( - author_public_key, - template_address, - TemplateExecutable::CompiledWasm(template.to_vec()), - None, - Some(TemplateStatus::Active), - ) - } } impl Clone for TemplateManager { diff --git a/applications/tari_dan_app_utilities/src/template_manager/implementation/service.rs b/applications/tari_dan_app_utilities/src/template_manager/implementation/service.rs index b588968cb..aa20b249b 100644 --- a/applications/tari_dan_app_utilities/src/template_manager/implementation/service.rs +++ b/applications/tari_dan_app_utilities/src/template_manager/implementation/service.rs @@ -25,7 +25,7 @@ use log::*; use tari_common_types::types::PublicKey; -use tari_dan_common_types::{services::template_provider::TemplateProvider, NodeAddressable}; +use tari_dan_common_types::{services::template_provider::TemplateProvider, Epoch, NodeAddressable}; use tari_dan_engine::function_definitions::FlowFunctionDefinition; use tari_dan_storage::global::{DbTemplateType, DbTemplateUpdate, TemplateStatus}; use tari_engine_types::calculate_template_binary_hash; @@ -124,11 +124,12 @@ impl TemplateManagerService { template_address, template, template_name, + epoch, reply, } => { handle( reply, - self.handle_add_template(author_public_key, template_address, template, template_name) + self.handle_add_template(author_public_key, template_address, template, template_name, epoch) .await, ); }, @@ -243,6 +244,7 @@ impl TemplateManagerService { template_address: tari_engine_types::TemplateAddress, template: TemplateExecutable, template_name: Option, + epoch: Epoch, ) -> Result<(), TemplateManagerError> { let template_status = if matches!(template, TemplateExecutable::DownloadableWasm(_, _)) { TemplateStatus::New @@ -255,6 +257,7 @@ impl TemplateManagerService { template.clone(), template_name, Some(template_status), + epoch, )?; // TODO: remove when we remove support for base layer template registration diff --git a/applications/tari_dan_app_utilities/src/template_manager/interface/handle.rs b/applications/tari_dan_app_utilities/src/template_manager/interface/handle.rs index a62244a56..651cbd161 100644 --- a/applications/tari_dan_app_utilities/src/template_manager/interface/handle.rs +++ b/applications/tari_dan_app_utilities/src/template_manager/interface/handle.rs @@ -21,6 +21,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use tari_common_types::types::PublicKey; +use tari_dan_common_types::Epoch; use tari_template_lib::models::TemplateAddress; use tari_validator_node_client::types::TemplateAbi; use tokio::sync::{mpsc, oneshot}; @@ -70,6 +71,7 @@ impl TemplateManagerHandle { template_address: TemplateAddress, template: TemplateExecutable, template_name: Option, + epoch: Epoch, ) -> Result<(), TemplateManagerError> { let (tx, rx) = oneshot::channel(); self.request_tx @@ -78,6 +80,7 @@ impl TemplateManagerHandle { template_address, template, template_name, + epoch, reply: tx, }) .await diff --git a/applications/tari_dan_app_utilities/src/template_manager/interface/types.rs b/applications/tari_dan_app_utilities/src/template_manager/interface/types.rs index 08f3a60dd..13c1b427b 100644 --- a/applications/tari_dan_app_utilities/src/template_manager/interface/types.rs +++ b/applications/tari_dan_app_utilities/src/template_manager/interface/types.rs @@ -22,6 +22,7 @@ use reqwest::Url; use tari_common_types::types::{FixedHash, PublicKey}; +use tari_dan_common_types::Epoch; use tari_dan_storage::global::{DbTemplate, DbTemplateType}; use tari_template_lib::models::TemplateAddress; use tari_validator_node_client::types::TemplateAbi; @@ -91,6 +92,7 @@ pub enum TemplateManagerRequest { template_address: tari_engine_types::TemplateAddress, template: TemplateExecutable, template_name: Option, + epoch: Epoch, reply: oneshot::Sender>, }, GetTemplate { diff --git a/applications/tari_validator_node/src/bootstrap.rs b/applications/tari_validator_node/src/bootstrap.rs index d7c07d807..a9637b174 100644 --- a/applications/tari_validator_node/src/bootstrap.rs +++ b/applications/tari_validator_node/src/bootstrap.rs @@ -336,7 +336,6 @@ pub async fn spawn_services( handles.push(consensus_join_handle); let (mempool, join_handle) = mempool::spawn( - consensus_constants.num_preshards, epoch_manager.clone(), create_mempool_transaction_validator(template_manager.clone()), state_store.clone(), diff --git a/applications/tari_validator_node/src/dan_node.rs b/applications/tari_validator_node/src/dan_node.rs index 1a2d2b631..d451853d4 100644 --- a/applications/tari_validator_node/src/dan_node.rs +++ b/applications/tari_validator_node/src/dan_node.rs @@ -94,7 +94,6 @@ impl DanNode { .services .state_store .with_read_tx(|tx| block.get_committing_transactions(tx))?; - let templates = transactions .into_iter() .filter_map(|record| { @@ -115,6 +114,7 @@ impl DanNode { }) }); + let epoch = self.services.consensus_handle.current_epoch(); // adding templates to template manager let mut template_counter = 0; for (author_pub_key, template_address, template) in templates { @@ -127,7 +127,7 @@ impl DanNode { if let Err(err) = self .services .template_manager - .add_template(author_pub_key, template_address, template, None) + .add_template(author_pub_key, template_address, template, None, epoch) .await { error!(target: LOG_TARGET, "🚨Failed to add template: {}", err); diff --git a/applications/tari_validator_node/src/p2p/services/mempool/gossip.rs b/applications/tari_validator_node/src/p2p/services/mempool/gossip.rs index d106611b0..603ec7948 100644 --- a/applications/tari_validator_node/src/p2p/services/mempool/gossip.rs +++ b/applications/tari_validator_node/src/p2p/services/mempool/gossip.rs @@ -5,7 +5,7 @@ use std::{collections::HashSet, iter}; use libp2p::{gossipsub, PeerId}; use log::*; -use tari_dan_common_types::{Epoch, NumPreshards, PeerAddress, ShardGroup, ToSubstateAddress}; +use tari_dan_common_types::{Epoch, PeerAddress, ShardGroup, ToSubstateAddress}; use tari_dan_p2p::{proto, DanMessage, NewTransactionMessage, TariMessagingSpec}; use tari_epoch_manager::{base_layer::EpochManagerHandle, EpochManagerReader}; use tari_networking::{NetworkingHandle, NetworkingService}; @@ -47,7 +47,6 @@ impl MempoolGossipCodec { #[derive(Debug)] pub(super) struct MempoolGossip { - num_preshards: NumPreshards, epoch_manager: EpochManagerHandle, is_subscribed: Option, networking: NetworkingHandle, @@ -57,13 +56,11 @@ pub(super) struct MempoolGossip { impl MempoolGossip { pub fn new( - num_preshards: NumPreshards, epoch_manager: EpochManagerHandle, networking: NetworkingHandle, rx_gossip: mpsc::UnboundedReceiver<(PeerId, gossipsub::Message)>, ) -> Self { Self { - num_preshards, epoch_manager, is_subscribed: None, networking, @@ -143,28 +140,37 @@ impl MempoolGossip { exclude_shard_group: Option, ) -> Result<(), MempoolError> { let n = self.epoch_manager.get_num_committees(epoch).await?; - let committee_shard = self.epoch_manager.get_local_committee_info(epoch).await?; - let local_shard_group = committee_shard.shard_group(); - let shard_groups = msg - .transaction - .all_inputs_iter() - .map(|s| { - s.or_zero_version() - .to_substate_address() - .to_shard_group(self.num_preshards, n) - }) - .chain(iter::once( - msg.transaction - .id() - .to_substate_address() - .to_shard_group(self.num_preshards, n), - )) - .filter(|sg| exclude_shard_group.as_ref() != Some(sg) && sg != &local_shard_group) - .collect::>(); - // If the only shard group involved is the excluded one. - if shard_groups.is_empty() { - return Ok(()); - } + let committee_info = self.epoch_manager.get_local_committee_info(epoch).await?; + let local_shard_group = committee_info.shard_group(); + let shard_groups = if msg.transaction.is_global() { + Box::new( + committee_info + .all_shard_groups_iter() + .filter(|sg| exclude_shard_group.as_ref() != Some(sg) && sg != &local_shard_group), + ) + } else { + let shard_groups = msg + .transaction + .all_inputs_iter() + .map(|s| { + s.or_zero_version() + .to_substate_address() + .to_shard_group(committee_info.num_preshards(), n) + }) + .chain(iter::once( + msg.transaction + .id() + .to_substate_address() + .to_shard_group(committee_info.num_preshards(), n), + )) + .filter(|sg| exclude_shard_group.as_ref() != Some(sg) && sg != &local_shard_group) + .collect::>(); + // If the only shard group involved is the excluded one. + if shard_groups.is_empty() { + return Ok(()); + } + Box::new(shard_groups.into_iter()) as Box + Send> + }; let msg = self .codec diff --git a/applications/tari_validator_node/src/p2p/services/mempool/initializer.rs b/applications/tari_validator_node/src/p2p/services/mempool/initializer.rs index 2bb4d622e..b28753b9e 100644 --- a/applications/tari_validator_node/src/p2p/services/mempool/initializer.rs +++ b/applications/tari_validator_node/src/p2p/services/mempool/initializer.rs @@ -22,7 +22,7 @@ use libp2p::{gossipsub, PeerId}; use log::*; -use tari_dan_common_types::{NumPreshards, PeerAddress}; +use tari_dan_common_types::PeerAddress; use tari_dan_p2p::TariMessagingSpec; use tari_epoch_manager::base_layer::EpochManagerHandle; use tari_networking::NetworkingHandle; @@ -42,7 +42,6 @@ use crate::{ const LOG_TARGET: &str = "tari::dan::validator_node::mempool"; pub fn spawn( - num_preshards: NumPreshards, epoch_manager: EpochManagerHandle, transaction_validator: TValidator, state_store: SqliteStateStore, @@ -61,7 +60,6 @@ where #[cfg(feature = "metrics")] let metrics = PrometheusMempoolMetrics::new(metrics_registry); let mempool = MempoolService::new( - num_preshards, rx_mempool_request, epoch_manager, transaction_validator, diff --git a/applications/tari_validator_node/src/p2p/services/mempool/service.rs b/applications/tari_validator_node/src/p2p/services/mempool/service.rs index d0a4d3c7a..813145657 100644 --- a/applications/tari_validator_node/src/p2p/services/mempool/service.rs +++ b/applications/tari_validator_node/src/p2p/services/mempool/service.rs @@ -25,7 +25,7 @@ use std::{collections::HashSet, fmt::Display, iter}; use libp2p::{gossipsub, PeerId}; use log::*; use tari_consensus::hotstuff::HotstuffEvent; -use tari_dan_common_types::{optional::Optional, NumPreshards, PeerAddress, ShardGroup, ToSubstateAddress}; +use tari_dan_common_types::{optional::Optional, PeerAddress, ShardGroup, ToSubstateAddress}; use tari_dan_p2p::{DanMessage, NewTransactionMessage, TariMessagingSpec}; use tari_dan_storage::{consensus_models::TransactionRecord, StateStore}; use tari_engine_types::commit_result::RejectReason; @@ -67,7 +67,6 @@ impl MempoolService where TValidator: Validator { pub(super) fn new( - num_preshards: NumPreshards, mempool_requests: mpsc::Receiver, epoch_manager: EpochManagerHandle, before_execute_validator: TValidator, @@ -78,7 +77,7 @@ where TValidator: Validator Self { Self { - gossip: MempoolGossip::new(num_preshards, epoch_manager.clone(), networking, rx_gossip), + gossip: MempoolGossip::new(epoch_manager.clone(), networking, rx_gossip), transactions: Default::default(), mempool_requests, epoch_manager, diff --git a/dan_layer/common_types/src/committee.rs b/dan_layer/common_types/src/committee.rs index 606e03e75..a9a2e7ced 100644 --- a/dan_layer/common_types/src/committee.rs +++ b/dan_layer/common_types/src/committee.rs @@ -232,6 +232,9 @@ impl CommitteeInfo { } pub fn includes_substate_id(&self, substate_id: &SubstateId) -> bool { + if substate_id.is_global() { + return true; + } // version doesnt affect shard let addr = SubstateAddress::from_substate_id(substate_id, 0); let shard = addr.to_shard(self.num_shards); @@ -265,6 +268,10 @@ impl CommitteeInfo { .into_iter() .filter(|substate_address| self.includes_substate_address(substate_address.borrow())) } + + pub fn all_shard_groups_iter(&self) -> impl Iterator { + self.num_shards.all_shard_groups_iter(self.num_committees) + } } #[derive(Debug, Clone, Serialize)] diff --git a/dan_layer/common_types/src/lock_intent.rs b/dan_layer/common_types/src/lock_intent.rs index ad302cb75..e8453b916 100644 --- a/dan_layer/common_types/src/lock_intent.rs +++ b/dan_layer/common_types/src/lock_intent.rs @@ -51,6 +51,10 @@ impl SubstateLockType { pub fn is_output(&self) -> bool { matches!(self, Self::Output) } + + pub fn is_input(&self) -> bool { + !self.is_output() + } } impl fmt::Display for SubstateLockType { diff --git a/dan_layer/common_types/src/num_preshards.rs b/dan_layer/common_types/src/num_preshards.rs index b5835a071..61b2e9eb0 100644 --- a/dan_layer/common_types/src/num_preshards.rs +++ b/dan_layer/common_types/src/num_preshards.rs @@ -5,6 +5,8 @@ use std::{error::Error, fmt::Display}; use serde::{Deserialize, Serialize}; +use crate::ShardGroup; + #[cfg_attr( feature = "ts", derive(ts_rs::TS), @@ -33,6 +35,27 @@ impl NumPreshards { pub fn is_one(self) -> bool { self == Self::P1 } + + pub fn all_shard_groups_iter(&self, num_committees: u32) -> impl Iterator { + let num_shards = self.as_u32(); + let num_shards_per_committee = num_shards / num_committees; + let mut remainder = num_shards % num_committees; + let mut start = 0; + let mut end = num_shards_per_committee - 1; + std::iter::from_fn(move || { + if start >= num_shards { + return None; + } + if remainder > 0 { + end += 1; + remainder -= 1; + } + let group = ShardGroup::new(start, end); + start = end + 1; + end = start + num_shards_per_committee - 1; + Some(group) + }) + } } impl TryFrom for NumPreshards { @@ -76,3 +99,31 @@ impl Display for InvalidNumPreshards { write!(f, "{} is not a valid number of pre-shards", self.0) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_calculates_all_shard_groups() { + let num_preshards = NumPreshards::P256; + let num_committees = 3; + let groups: Vec<_> = num_preshards.all_shard_groups_iter(num_committees).collect(); + assert_eq!(groups.len(), 3); + assert_eq!(groups[0], ShardGroup::new(0, 85)); + assert_eq!(groups[0].len(), 86); + assert_eq!(groups[1], ShardGroup::new(86, 170)); + assert_eq!(groups[1].len(), 85); + assert_eq!(groups[2], ShardGroup::new(171, 255)); + assert_eq!(groups[2].len(), 85); + } + + #[test] + fn total_shard_group_lengths_equal_num_preshards() { + let num_preshards = NumPreshards::P256; + let num_committees = 234; + let groups: Vec<_> = num_preshards.all_shard_groups_iter(num_committees).collect(); + let total_length = groups.iter().map(|g| g.len()).sum::(); + assert_eq!(total_length, num_preshards.as_u32() as usize); + } +} diff --git a/dan_layer/common_types/src/services/template_provider.rs b/dan_layer/common_types/src/services/template_provider.rs index 684092e6c..629bdbfab 100644 --- a/dan_layer/common_types/src/services/template_provider.rs +++ b/dan_layer/common_types/src/services/template_provider.rs @@ -1,7 +1,6 @@ // Copyright 2022 The Tari Project // SPDX-License-Identifier: BSD-3-Clause -use tari_common_types::types::PublicKey; use tari_engine_types::TemplateAddress; pub trait TemplateProvider: Send + Sync + Clone + 'static { @@ -9,11 +8,4 @@ pub trait TemplateProvider: Send + Sync + Clone + 'static { type Error: std::error::Error + Sync + Send + 'static; fn get_template_module(&self, id: &TemplateAddress) -> Result, Self::Error>; - - fn add_wasm_template( - &self, - author_public_key: PublicKey, - template_address: TemplateAddress, - template: &[u8], - ) -> Result<(), Self::Error>; } diff --git a/dan_layer/common_types/src/substate_address.rs b/dan_layer/common_types/src/substate_address.rs index 6a780b57a..43bc23632 100644 --- a/dan_layer/common_types/src/substate_address.rs +++ b/dan_layer/common_types/src/substate_address.rs @@ -600,6 +600,22 @@ mod tests { } } + #[test] + fn it_matches_num_preshard_all_shard_iter() { + const NUM_COMMITTEES: u32 = 11; + let groups = (0..NUM_COMMITTEES).map(|i| { + address_at(i * (256 / NUM_COMMITTEES + 1), 256).to_shard_group(NumPreshards::P256, NUM_COMMITTEES) + }); + let mut iter = NumPreshards::P256.all_shard_groups_iter(NUM_COMMITTEES); + let mut total_length = 0; + for (i, group) in groups.enumerate() { + assert_eq!(iter.next(), Some(group), "Failed at {group} (i={i})"); + total_length += group.len(); + } + assert_eq!(iter.next(), None); + assert_eq!(total_length, 256); + } + #[test] fn it_returns_the_correct_shard_group_for_odd_num_committees() { // All shard groups except the last have 3 shards each diff --git a/dan_layer/consensus/src/hotstuff/block_change_set.rs b/dan_layer/consensus/src/hotstuff/block_change_set.rs index 1ab74c8a4..5104420da 100644 --- a/dan_layer/consensus/src/hotstuff/block_change_set.rs +++ b/dan_layer/consensus/src/hotstuff/block_change_set.rs @@ -24,7 +24,6 @@ use tari_dan_storage::{ LockedBlock, NoVoteReason, PendingShardStateTreeDiff, - QuorumCertificate, QuorumDecision, SubstateChange, SubstateLock, @@ -59,9 +58,8 @@ const MEM_MAX_PROPOSED_UTXO_MINTS_SIZE: usize = 1000; #[derive(Debug, Clone)] pub struct BlockDecision { pub quorum_decision: Option, - /// Contains newly-locked non-dummy blocks and the QC that justifies each block i.e. typically the parent block's - /// QC - pub locked_blocks: Vec<(Block, QuorumCertificate)>, + /// Contains newly-locked non-dummy blocks + pub locked_blocks: Vec, pub finalized_transactions: Vec>, pub end_of_epoch: Option, pub high_qc: HighQc, diff --git a/dan_layer/consensus/src/hotstuff/foreign_proposal_processor.rs b/dan_layer/consensus/src/hotstuff/foreign_proposal_processor.rs index dc21104d2..88df8fe52 100644 --- a/dan_layer/consensus/src/hotstuff/foreign_proposal_processor.rs +++ b/dan_layer/consensus/src/hotstuff/foreign_proposal_processor.rs @@ -187,7 +187,7 @@ pub fn process_foreign_block( tx_rec.current_stage() ); } - } else if tx_rec.current_stage().is_local_prepared() && tx_rec.evidence().all_inputs_prepared() { + } else if tx_rec.current_stage().is_local_prepared() && tx_rec.evidence().all_shard_groups_prepared() { // If all shards are complete, and we've already received our LocalPrepared, we can set out // LocalPrepared transaction as ready to propose ACCEPT. If we have not received // the local LocalPrepared, the transition will happen when we receive the local @@ -209,7 +209,7 @@ pub fn process_foreign_block( tx_rec.transaction_id(), tx_rec.current_decision(), tx_rec.current_stage(), - tx_rec.evidence().all_inputs_prepared() + tx_rec.evidence().all_shard_groups_prepared() ); // Update the evidence proposed_block_change_set.set_next_transaction_update(tx_rec)?; @@ -363,7 +363,7 @@ pub fn process_foreign_block( tx_rec.transaction_id(), tx_rec.current_decision(), tx_rec.current_stage(), - tx_rec.evidence().all_addresses_accepted() + tx_rec.evidence().all_objects_accepted() ); // Still need to update the evidence proposed_block_change_set.set_next_transaction_update(tx_rec)?; diff --git a/dan_layer/consensus/src/hotstuff/on_propose.rs b/dan_layer/consensus/src/hotstuff/on_propose.rs index e670f6772..7f49c3ddc 100644 --- a/dan_layer/consensus/src/hotstuff/on_propose.rs +++ b/dan_layer/consensus/src/hotstuff/on_propose.rs @@ -247,7 +247,7 @@ where TConsensusSpec: ConsensusSpec if local_committee_info.num_shard_group_members() <= 1 { info!( target: LOG_TARGET, - "🌿 Only member of local committee. No need to multicast proposal {leaf_block}", + "🌿 This node is the only member of the local committee. No need to multicast proposal {leaf_block}", ); } else { let committee = self @@ -816,6 +816,11 @@ where TConsensusSpec: ConsensusSpec tx_rec .evidence_mut() .update(&multishard.to_initial_evidence(local_committee_info)); + if true { + for shard_group in local_committee_info.all_shard_groups_iter() { + tx_rec.evidence_mut().add_shard_group(shard_group); + } + } } }, Decision::Abort(reason) => { @@ -868,9 +873,7 @@ where TConsensusSpec: ConsensusSpec .resulting_outputs() .iter() .filter(|o| { - o.substate_id().is_transaction_receipt() || - o.substate_id().is_published_template() || - local_committee_info.includes_substate_address(&o.to_substate_address()) + o.substate_id().is_transaction_receipt() || local_committee_info.includes_substate_id(o.substate_id()) }) .map(|output| SubstateRequirementLockIntent::from(output.clone())); let lock_status = substate_store.try_lock_all(*tx_rec.transaction_id(), local_outputs, false)?; diff --git a/dan_layer/consensus/src/hotstuff/on_ready_to_vote_on_local_block.rs b/dan_layer/consensus/src/hotstuff/on_ready_to_vote_on_local_block.rs index 7d326ce1c..6590fb847 100644 --- a/dan_layer/consensus/src/hotstuff/on_ready_to_vote_on_local_block.rs +++ b/dan_layer/consensus/src/hotstuff/on_ready_to_vote_on_local_block.rs @@ -149,9 +149,9 @@ where TConsensusSpec: ConsensusSpec // Update nodes let high_qc = valid_block.block().update_nodes( tx, - |tx, _prev_locked, block, justify_qc| { + |tx, _prev_locked, block, _justify_qc| { if !block.is_dummy() { - locked_blocks.push((block.clone(), justify_qc.clone())); + locked_blocks.push(block.clone()); } self.on_lock_block(tx, block) }, @@ -987,14 +987,14 @@ where TConsensusSpec: ConsensusSpec })); } - if !tx_rec.evidence().all_inputs_prepared() { + if !tx_rec.evidence().all_shard_groups_prepared() { warn!( target: LOG_TARGET, - "❌ NO VOTE: AllPrepare disagreement for transaction {} in block {}. Leader proposed that all inputs are justified, but not all inputs are justified", + "❌ NO VOTE: AllPrepare disagreement for transaction {} in block {}. Leader proposed that all shard groups have prepared, but this is not the case", tx_rec.transaction_id(), block, ); - return Ok(Some(NoVoteReason::NotAllInputsPrepared)); + return Ok(Some(NoVoteReason::NotAllShardGroupsPrepared)); } let maybe_execution = if tx_rec.current_decision().is_commit() { @@ -1029,7 +1029,7 @@ where TConsensusSpec: ConsensusSpec // Lock all local outputs let local_outputs = execution.resulting_outputs().iter().filter(|o| { o.substate_id().is_transaction_receipt() || - local_committee_info.includes_substate_address(&o.to_substate_address()) + local_committee_info.includes_substate_id(o.substate_id()) }); let lock_status = substate_store.try_lock_all(*tx_rec.transaction_id(), local_outputs, false)?; if let Some(err) = lock_status.failures().first() { diff --git a/dan_layer/consensus/src/hotstuff/on_receive_local_proposal.rs b/dan_layer/consensus/src/hotstuff/on_receive_local_proposal.rs index 5ce3eeae3..04776f4aa 100644 --- a/dan_layer/consensus/src/hotstuff/on_receive_local_proposal.rs +++ b/dan_layer/consensus/src/hotstuff/on_receive_local_proposal.rs @@ -16,16 +16,7 @@ use tari_dan_common_types::{ ShardGroup, }; use tari_dan_storage::{ - consensus_models::{ - Block, - HighQc, - LastSentVote, - QuorumCertificate, - QuorumDecision, - TransactionPool, - ValidBlock, - Vote, - }, + consensus_models::{Block, HighQc, LastSentVote, QuorumDecision, TransactionPool, ValidBlock, Vote}, StateStore, StateStoreWriteTransaction, }; @@ -507,11 +498,7 @@ impl OnReceiveLocalProposalHandler, - ) { + fn propose_newly_locked_blocks(&mut self, local_committee_info: CommitteeInfo, blocks: Vec) { if blocks.is_empty() { return; } @@ -881,7 +868,7 @@ async fn propose_newly_locked_blocks_task( outbound_messaging: TConsensusSpec::OutboundMessaging, num_preshards: NumPreshards, local_committee_info: CommitteeInfo, - blocks: Vec<(Block, QuorumCertificate)>, + blocks: Vec, ) { let _timer = TraceTimer::debug(LOG_TARGET, "propose_newly_locked_blocks_task").with_iterations(blocks.len()); if let Err(err) = propose_newly_locked_blocks_task_inner::( @@ -902,16 +889,15 @@ async fn propose_newly_locked_blocks_task_inner( mut outbound_messaging: TConsensusSpec::OutboundMessaging, num_preshards: NumPreshards, local_committee_info: &CommitteeInfo, - blocks: Vec<(Block, QuorumCertificate)>, + blocks: Vec, ) -> Result<(), HotStuffError> { - for (block, justify_qc) in blocks.into_iter().rev() { + for block in blocks.into_iter().rev() { broadcast_foreign_proposal_if_required::( &mut outbound_messaging, &epoch_manager, num_preshards, local_committee_info, block, - justify_qc, ) .await?; } @@ -924,7 +910,6 @@ async fn broadcast_foreign_proposal_if_required( num_preshards: NumPreshards, local_committee_info: &CommitteeInfo, block: Block, - justify_qc: QuorumCertificate, ) -> Result<(), HotStuffError> { let num_committees = epoch_manager.get_num_committees(block.epoch()).await?; @@ -939,25 +924,28 @@ async fn broadcast_foreign_proposal_if_required( .filter(|atom| !atom.evidence.is_committee_output_only(local_committee_info)) .or_else(|| c.local_accept()) }) - .flat_map(|p| p.evidence.shard_groups_iter().copied()) + .flat_map(|p| { + debug!( + target: LOG_TARGET, + "🌐 FOREIGN PROPOSE: atom {p}", + ); + p.evidence.shard_groups_iter().copied() + }) .filter(|shard_group| local_shard_group != *shard_group) .collect::>(); if non_local_shard_groups.is_empty() { debug!( target: LOG_TARGET, - "🌐 No foreign shards involved for new locked block {}", + "🌐 No foreign shards apply to new locked block {}", block, ); return Ok(()); } info!( target: LOG_TARGET, - "🌐 BROADCASTING new locked block {} to {} foreign shard groups. justify: {} ({}), parent: {}", - block, + "🌐 FOREIGN PROPOSE: new locked block to {} foreign shard groups. {}", non_local_shard_groups.len(), - justify_qc.block_id(), - justify_qc.block_height(), - block.parent() + block, ); for shard_group in non_local_shard_groups { diff --git a/dan_layer/consensus/src/hotstuff/on_receive_new_transaction.rs b/dan_layer/consensus/src/hotstuff/on_receive_new_transaction.rs index fb907147f..0954b16a8 100644 --- a/dan_layer/consensus/src/hotstuff/on_receive_new_transaction.rs +++ b/dan_layer/consensus/src/hotstuff/on_receive_new_transaction.rs @@ -153,8 +153,13 @@ where TConsensusSpec: ConsensusSpec transaction: &TransactionRecord, is_ready: bool, ) -> Result<(), HotStuffError> { - self.transaction_pool - .insert_new(tx, *transaction.id(), transaction.current_decision(), is_ready)?; + self.transaction_pool.insert_new( + tx, + *transaction.id(), + transaction.current_decision(), + is_ready, + transaction.transaction().is_global(), + )?; Ok(()) } } diff --git a/dan_layer/consensus/src/hotstuff/transaction_manager/manager.rs b/dan_layer/consensus/src/hotstuff/transaction_manager/manager.rs index d7dcf92e7..cd9ca027f 100644 --- a/dan_layer/consensus/src/hotstuff/transaction_manager/manager.rs +++ b/dan_layer/consensus/src/hotstuff/transaction_manager/manager.rs @@ -223,7 +223,7 @@ impl> ))); } - if non_local_inputs.is_empty() { + if !transaction.transaction.is_global() && non_local_inputs.is_empty() { // CASE: All inputs are local and we can execute the transaction. // Outputs may or may not be local let local_inputs = store.get_many(local_versions.iter().map(|(req, v)| (req.clone(), *v)))?; @@ -305,6 +305,7 @@ impl> warn!(target: LOG_TARGET, "⚠️ PREPARE: Hard conflict when locking inputs: {err}"); transaction.set_abort_reason(RejectReason::FailedToLockInputs(err.to_string())); } + // CASE: Multishard transaction, not executed Ok(PreparedTransaction::new_multishard( transaction.into_execution(), diff --git a/dan_layer/consensus/src/hotstuff/transaction_manager/prepared.rs b/dan_layer/consensus/src/hotstuff/transaction_manager/prepared.rs index 609d959bb..94bfb2f2f 100644 --- a/dan_layer/consensus/src/hotstuff/transaction_manager/prepared.rs +++ b/dan_layer/consensus/src/hotstuff/transaction_manager/prepared.rs @@ -132,8 +132,8 @@ impl MultiShardPreparedTransaction { outputs, ); - // Add foreign involved shard groups without adding any substates (because we do not know the pledged version - // yet) + // Add foreign involved shard groups without adding any substates (because we do not know the pledged + // version yet) self.foreign_inputs() .iter() .map(|r| { diff --git a/dan_layer/consensus_tests/fixtures/state.wasm b/dan_layer/consensus_tests/fixtures/state.wasm new file mode 100755 index 0000000000000000000000000000000000000000..c7d0d4dc95c825b519ef9a3a4a9ea8426c900f78 GIT binary patch literal 368204 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Š!I^U+C0AF0F&4D7gB0;6?? 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 NodeHeight(30) { + panic!("Not all transaction committed after {} blocks", leaf.height); + } + } + + test.assert_all_validators_at_same_height().await; + test.assert_all_validators_committed(); + + // Assert all LocalOnly + let template_substate = test + .get_validator(&TestAddress::new("1")) + .state_store + .with_read_tx(|tx| SubstateRecord::get(tx, &VersionedSubstateId::new(template_id, 0).to_substate_address())) + .unwrap(); + let binary = template_substate + .substate_value + .into_template() + .expect("Expected template substate") + .binary; + assert_eq!(binary, wasm, "Template binary does not match"); + + test.assert_clean_shutdown().await; +} + // mod dump_data { // use super::*; // use std::fs::File; diff --git a/dan_layer/consensus_tests/src/dummy_blocks.rs b/dan_layer/consensus_tests/src/dummy_blocks.rs index 041e06b4c..39d7ff981 100644 --- a/dan_layer/consensus_tests/src/dummy_blocks.rs +++ b/dan_layer/consensus_tests/src/dummy_blocks.rs @@ -12,7 +12,7 @@ use tari_crypto::{keys::PublicKey as _, tari_utilities::ByteArray}; use tari_dan_common_types::{committee::Committee, DerivableFromPublicKey, Epoch, NodeHeight, PeerAddress, ShardGroup}; use tari_dan_storage::consensus_models::Block; -use crate::support::{load_fixture, RoundRobinLeaderStrategy}; +use crate::support::{load_json_fixture, RoundRobinLeaderStrategy}; #[test] fn dummy_blocks() { @@ -74,9 +74,9 @@ fn public_key_from_seed(seed: u8) -> PublicKey { #[test] fn last_matches_generated_using_real_data() { - let candidate = load_fixture::("block_with_dummies.json"); + let candidate = load_json_fixture::("block_with_dummies.json"); - let committee = load_fixture::("committee.json"); + let committee = load_json_fixture::("committee.json"); let committee: Vec<(PeerAddress, PublicKey)> = serde_json::from_value(committee["members"].clone()).unwrap(); let committee = Committee::new(committee); diff --git a/dan_layer/consensus_tests/src/eviction_proof.rs b/dan_layer/consensus_tests/src/eviction_proof.rs index ae604dd3e..275707839 100644 --- a/dan_layer/consensus_tests/src/eviction_proof.rs +++ b/dan_layer/consensus_tests/src/eviction_proof.rs @@ -4,11 +4,11 @@ use tari_consensus::hotstuff::eviction_proof::convert_block_to_sidechain_block_header; use tari_dan_storage::consensus_models::Block; -use crate::support::load_fixture; +use crate::support::load_json_fixture; #[test] fn it_produces_a_summarized_header_that_hashes_to_the_original() { - let block = load_fixture::("block.json"); + let block = load_json_fixture::("block.json"); let sidechain_block = convert_block_to_sidechain_block_header(block.header()); assert_eq!(sidechain_block.extra_data_hash, block.header().create_extra_data_hash()); assert_eq!( diff --git a/dan_layer/consensus_tests/src/support/fixtures.rs b/dan_layer/consensus_tests/src/support/fixtures.rs index 408a76994..b10672912 100644 --- a/dan_layer/consensus_tests/src/support/fixtures.rs +++ b/dan_layer/consensus_tests/src/support/fixtures.rs @@ -1,12 +1,24 @@ // Copyright 2024 The Tari Project // SPDX-License-Identifier: BSD-3-Clause +use std::io::Read; + use serde::de::DeserializeOwned; -pub fn load_fixture(name: &str) -> T { +pub fn load_json_fixture(name: &str) -> T { let path = format!("fixtures/{name}"); let file = std::fs::File::open(&path).unwrap_or_else(|_| { panic!("Could not open fixture file at path: {path}"); }); serde_json::from_reader(file).unwrap() } + +pub fn load_binary_fixture(name: &str) -> Vec { + let path = format!("fixtures/{name}"); + let mut file = std::fs::File::open(&path).unwrap_or_else(|_| { + panic!("Could not open fixture file at path: {path}"); + }); + let mut buffer = Vec::new(); + file.read_to_end(&mut buffer).unwrap(); + buffer +} diff --git a/dan_layer/consensus_tests/src/support/transaction.rs b/dan_layer/consensus_tests/src/support/transaction.rs index 6263af0b3..d22dfad68 100644 --- a/dan_layer/consensus_tests/src/support/transaction.rs +++ b/dan_layer/consensus_tests/src/support/transaction.rs @@ -10,6 +10,7 @@ use tari_engine_types::{ commit_result::{ExecuteResult, FinalizeResult, RejectReason, TransactionResult}, component::{ComponentBody, ComponentHeader}, fees::{FeeBreakdown, FeeReceipt}, + published_template::PublishedTemplate, substate::{Substate, SubstateDiff, SubstateId}, transaction_receipt::{TransactionReceipt, TransactionReceiptAddress}, }; @@ -45,31 +46,48 @@ pub fn create_execution_result_for_transaction( if output.substate_id().is_transaction_receipt() { continue; } - assert!( - output.substate_id().is_component(), - "create_execution_result_for_transaction: Test harness only supports generating component outputs. \ - Got {output}" - ); - // Generate consistent state for the component by simply using the ID - let state = tari_bor::to_value(output.versioned_substate_id()).unwrap(); - diff.up( - output.versioned_substate_id().substate_id.clone(), - Substate::new(output.versioned_substate_id().version, ComponentHeader { - template_address: Default::default(), - module_name: "Test".to_string(), - owner_key: Default::default(), - owner_rule: Default::default(), - access_rules: Default::default(), - entity_id: output - .versioned_substate_id() - .substate_id - .as_component_address() - .unwrap() - .entity_id(), - body: ComponentBody { state }, - }), - ) + match output.substate_id() { + SubstateId::Component(_) => { + // Generate consistent state for the component by simply using the ID + let state = tari_bor::to_value(output.versioned_substate_id()).unwrap(); + diff.up( + output.versioned_substate_id().substate_id.clone(), + Substate::new(output.versioned_substate_id().version, ComponentHeader { + template_address: Default::default(), + module_name: "Test".to_string(), + owner_key: Default::default(), + owner_rule: Default::default(), + access_rules: Default::default(), + entity_id: output + .versioned_substate_id() + .substate_id + .as_component_address() + .unwrap() + .entity_id(), + body: ComponentBody { state }, + }), + ); + }, + SubstateId::Template(_) => { + let binary = transaction + .instructions() + .iter() + .find_map(|i| i.published_template_binary()) + .expect("No publish template instruction found in transaction") + .to_vec(); + diff.up( + output.versioned_substate_id().substate_id.clone(), + Substate::new(output.versioned_substate_id().version, PublishedTemplate { binary }), + ); + }, + _ => { + panic!( + "create_execution_result_for_transaction: Test harness only supports generating component and \ + template outputs. Got {output}" + ); + }, + } } // We MUST create the transaction receipt diff.up( diff --git a/dan_layer/engine_types/src/instruction.rs b/dan_layer/engine_types/src/instruction.rs index e8ed1f79d..af8b3b861 100644 --- a/dan_layer/engine_types/src/instruction.rs +++ b/dan_layer/engine_types/src/instruction.rs @@ -72,6 +72,15 @@ pub enum Instruction { }, } +impl Instruction { + pub fn published_template_binary(&self) -> Option<&[u8]> { + match self { + Self::PublishTemplate { binary } => Some(binary), + _ => None, + } + } +} + impl Display for Instruction { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { diff --git a/dan_layer/engine_types/src/substate.rs b/dan_layer/engine_types/src/substate.rs index 30e96bc72..fa47aed5c 100644 --- a/dan_layer/engine_types/src/substate.rs +++ b/dan_layer/engine_types/src/substate.rs @@ -284,6 +284,10 @@ impl SubstateId { matches!(self, Self::Template(_)) } + pub fn is_global(&self) -> bool { + self.is_published_template() + } + pub fn is_read_only(&self) -> bool { matches!(self, Self::TransactionReceipt(_) | Self::Resource(_)) } diff --git a/dan_layer/state_store_sqlite/migrations/2023-06-08-091819_create_state_store/up.sql b/dan_layer/state_store_sqlite/migrations/2023-06-08-091819_create_state_store/up.sql index b3a842441..e927531a6 100644 --- a/dan_layer/state_store_sqlite/migrations/2023-06-08-091819_create_state_store/up.sql +++ b/dan_layer/state_store_sqlite/migrations/2023-06-08-091819_create_state_store/up.sql @@ -272,28 +272,28 @@ CREATE INDEX locked_block_idx_epoch ON locked_block (epoch); create table transactions ( - id integer not null primary key AUTOINCREMENT, - network integer not NULL, - transaction_id text not null, - fee_instructions text not NULL, - instructions text not NULL, - inputs text not NULL, - filled_inputs text not NULL, - resolved_inputs text NULL, - resulting_outputs text NULL, - signatures text not NULL, - seal_signature text not NULL, - is_seal_signer_authorized boolean not NULL, - result text NULL, - execution_time_ms bigint NULL, - final_decision text NULL, - finalized_at timestamp NULL, - outcome TEXT NULL, - abort_details text NULL, - min_epoch BIGINT NULL, - max_epoch BIGINT NULL, - schema_version BIGINT NOT NULL, - created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP + id integer not null primary key AUTOINCREMENT, + network integer not NULL, + transaction_id text not null, + fee_instructions text not NULL, + instructions text not NULL, + inputs text not NULL, + filled_inputs text not NULL, + resolved_inputs text NULL, + resulting_outputs text NULL, + signatures text not NULL, + seal_signature text not NULL, + is_seal_signer_authorized boolean not NULL, + result text NULL, + execution_time_ms bigint NULL, + final_decision text NULL, + finalized_at timestamp NULL, + outcome TEXT NULL, + abort_details text NULL, + min_epoch BIGINT NULL, + max_epoch BIGINT NULL, + schema_version BIGINT NOT NULL, + created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ); create unique index transactions_uniq_idx_id on transactions (transaction_id); @@ -343,6 +343,7 @@ create table transaction_pool pending_stage text null, is_ready boolean not null, confirm_stage text null, + is_global boolean not NULL, updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (transaction_id) REFERENCES transactions (transaction_id) diff --git a/dan_layer/state_store_sqlite/src/schema.rs b/dan_layer/state_store_sqlite/src/schema.rs index 56c091f38..f51769f85 100644 --- a/dan_layer/state_store_sqlite/src/schema.rs +++ b/dan_layer/state_store_sqlite/src/schema.rs @@ -452,6 +452,7 @@ diesel::table! { pending_stage -> Nullable, is_ready -> Bool, confirm_stage -> Nullable, + is_global -> Bool, updated_at -> Timestamp, created_at -> Timestamp, } diff --git a/dan_layer/state_store_sqlite/src/sql_models/transaction_pool.rs b/dan_layer/state_store_sqlite/src/sql_models/transaction_pool.rs index a5aa9818f..2fb43a56e 100644 --- a/dan_layer/state_store_sqlite/src/sql_models/transaction_pool.rs +++ b/dan_layer/state_store_sqlite/src/sql_models/transaction_pool.rs @@ -31,6 +31,7 @@ pub struct TransactionPoolRecord { pub is_ready: bool, #[allow(dead_code)] pub confirm_stage: Option, + pub is_global: bool, #[allow(dead_code)] pub updated_at: PrimitiveDateTime, #[allow(dead_code)] @@ -72,6 +73,7 @@ impl TransactionPoolRecord { Ok(consensus_models::TransactionPoolRecord::load( deserialize_hex_try_from(&self.transaction_id)?, evidence, + self.is_global, transaction_fee as u64, leader_fee, parse_from_string(&self.stage)?, diff --git a/dan_layer/state_store_sqlite/src/writer.rs b/dan_layer/state_store_sqlite/src/writer.rs index b37efa5c3..3be0699b1 100644 --- a/dan_layer/state_store_sqlite/src/writer.rs +++ b/dan_layer/state_store_sqlite/src/writer.rs @@ -1047,6 +1047,7 @@ impl<'tx, TAddr: NodeAddressable + 'tx> StateStoreWriteTransaction for SqliteSta tx_id: TransactionId, decision: Decision, is_ready: bool, + is_global: bool, ) -> Result<(), StorageError> { use crate::schema::transaction_pool; @@ -1055,6 +1056,7 @@ impl<'tx, TAddr: NodeAddressable + 'tx> StateStoreWriteTransaction for SqliteSta transaction_pool::original_decision.eq(decision.to_string()), transaction_pool::stage.eq(TransactionPoolStage::New.to_string()), transaction_pool::is_ready.eq(is_ready), + transaction_pool::is_global.eq(is_global), ); diesel::insert_into(transaction_pool::table) diff --git a/dan_layer/state_store_sqlite/tests/tests.rs b/dan_layer/state_store_sqlite/tests/tests.rs index 91e951f3f..6b0330541 100644 --- a/dan_layer/state_store_sqlite/tests/tests.rs +++ b/dan_layer/state_store_sqlite/tests/tests.rs @@ -72,9 +72,12 @@ mod confirm_all_transitions { .unwrap(); block1.insert(&mut tx).unwrap(); - tx.transaction_pool_insert_new(atom1.id, atom1.decision, true).unwrap(); - tx.transaction_pool_insert_new(atom2.id, atom2.decision, true).unwrap(); - tx.transaction_pool_insert_new(atom3.id, atom3.decision, true).unwrap(); + tx.transaction_pool_insert_new(atom1.id, atom1.decision, true, false) + .unwrap(); + tx.transaction_pool_insert_new(atom2.id, atom2.decision, true, false) + .unwrap(); + tx.transaction_pool_insert_new(atom3.id, atom3.decision, true, false) + .unwrap(); let block_id = *block1.id(); let transactions = tx.transaction_pool_get_all().unwrap(); diff --git a/dan_layer/storage/src/consensus_models/block_diff.rs b/dan_layer/storage/src/consensus_models/block_diff.rs index 9f3ddcede..8eb5eebb0 100644 --- a/dan_layer/storage/src/consensus_models/block_diff.rs +++ b/dan_layer/storage/src/consensus_models/block_diff.rs @@ -44,9 +44,8 @@ impl BlockDiff { .into_iter() // Commit all substates included in this shard. Every involved validator commits the transaction receipt. .filter(|change| - change.versioned_substate_id().substate_id.is_published_template() || change.versioned_substate_id().substate_id.is_transaction_receipt() || - info.includes_substate_address(&change.to_substate_address()) + info.includes_substate_id(change.versioned_substate_id().substate_id()) ) .collect(), } diff --git a/dan_layer/storage/src/consensus_models/evidence.rs b/dan_layer/storage/src/consensus_models/evidence.rs index 5a39597eb..c8b5a1994 100644 --- a/dan_layer/storage/src/consensus_models/evidence.rs +++ b/dan_layer/storage/src/consensus_models/evidence.rs @@ -65,23 +65,24 @@ impl Evidence { Evidence { evidence } } - pub fn all_addresses_accepted(&self) -> bool { + pub fn all_objects_accepted(&self) -> bool { // CASE: all inputs and outputs are accept justified. If they have been accept justified, they have implicitly // been prepare justified. This may happen if the local node is only involved in outputs (and therefore // sequences using the LocalAccept foreign proposal) self.evidence.values().all(|e| e.is_accept_justified()) } - pub fn all_inputs_prepared(&self) -> bool { + pub fn all_shard_groups_prepared(&self) -> bool { self.evidence .values() + // .filter(|e| { + // // CASE: we only require input shard groups to prepare + // e.substates().values().any(|e| e.is_input()) + // }) // CASE: we use prepare OR accept because inputs can only be accept justified if they were prepared. Prepared // may be implicit (null) if the local node is only involved in outputs (and therefore sequences using the LocalAccept // foreign proposal) - .all(|e| { - e.is_prepare_justified() || e.is_accept_justified() - - }) + .all(|e| e.is_prepare_justified() || e.is_accept_justified()) } /// Returns true if all substates in the given shard group are output locks. @@ -234,13 +235,11 @@ impl ShardGroupEvidence { } pub fn is_prepare_justified(&self) -> bool { - // No substates means that we have no pledges yet, so we cannot count this as justified - !self.substates.is_empty() && self.prepare_qc.is_some() + self.prepare_qc.is_some() } pub fn is_accept_justified(&self) -> bool { - // No substates means that we have no pledges yet, so we cannot count this as justified - !self.substates.is_empty() && self.accept_qc.is_some() + self.accept_qc.is_some() } pub fn substates(&self) -> &IndexMap { diff --git a/dan_layer/storage/src/consensus_models/no_vote.rs b/dan_layer/storage/src/consensus_models/no_vote.rs index adc81712b..c8909c0da 100644 --- a/dan_layer/storage/src/consensus_models/no_vote.rs +++ b/dan_layer/storage/src/consensus_models/no_vote.rs @@ -28,8 +28,8 @@ pub enum NoVoteReason { LocalOnlyProposedForMultiShard, #[error("Multi shard proposed for local only")] MultiShardProposedForLocalOnly, - #[error("Not all inputs prepared")] - NotAllInputsPrepared, + #[error("Not all shard groups are prepared")] + NotAllShardGroupsPrepared, #[error("Foreign proposal command in block missing")] ForeignProposalCommandInBlockMissing, #[error("Foreign proposal already proposed")] @@ -74,7 +74,7 @@ impl NoVoteReason { Self::NoLeaderFee => "NoLeaderFee", Self::LocalOnlyProposedForMultiShard => "LocalOnlyProposedForMultiShard", Self::MultiShardProposedForLocalOnly => "MultiShardProposedForLocalOnly", - Self::NotAllInputsPrepared => "NotAllInputsPrepared", + Self::NotAllShardGroupsPrepared => "NotAllShardGroupsPrepared", Self::ForeignProposalCommandInBlockMissing => "ForeignProposalCommandInBlockMissing", Self::ForeignProposalAlreadyProposed => "ForeignProposalAlreadyProposed", Self::ForeignProposalNotReceived => "ForeignProposalNotReceived", diff --git a/dan_layer/storage/src/consensus_models/transaction_pool.rs b/dan_layer/storage/src/consensus_models/transaction_pool.rs index cc6630d21..54781f408 100644 --- a/dan_layer/storage/src/consensus_models/transaction_pool.rs +++ b/dan_layer/storage/src/consensus_models/transaction_pool.rs @@ -86,8 +86,9 @@ impl TransactionPool { tx_id: TransactionId, decision: Decision, is_ready: bool, + is_global: bool, ) -> Result<(), TransactionPoolError> { - tx.transaction_pool_insert_new(tx_id, decision, is_ready)?; + tx.transaction_pool_insert_new(tx_id, decision, is_ready, is_global)?; Ok(()) } @@ -98,7 +99,12 @@ impl TransactionPool { ) -> Result<(), TransactionPoolError> { // TODO(perf) for (transaction, is_ready) in transactions { - tx.transaction_pool_insert_new(*transaction.id(), transaction.current_decision(), is_ready)?; + tx.transaction_pool_insert_new( + *transaction.id(), + transaction.current_decision(), + is_ready, + transaction.transaction().is_global(), + )?; } Ok(()) } @@ -332,6 +338,7 @@ pub struct TransactionPoolRecord { #[cfg_attr(feature = "ts", ts(type = "string"))] transaction_id: TransactionId, evidence: Evidence, + is_global: bool, #[cfg_attr(feature = "ts", ts(type = "number"))] transaction_fee: u64, leader_fee: Option, @@ -347,6 +354,7 @@ impl TransactionPoolRecord { pub fn load( id: TransactionId, evidence: Evidence, + is_global: bool, transaction_fee: u64, leader_fee: Option, stage: TransactionPoolStage, @@ -359,6 +367,7 @@ impl TransactionPoolRecord { Self { transaction_id: id, evidence, + is_global, transaction_fee, leader_fee, stage, @@ -381,12 +390,12 @@ impl TransactionPoolRecord { match next_stage { TransactionPoolStage::New => self.is_ready, TransactionPoolStage::Prepared => true, - TransactionPoolStage::LocalPrepared => self.evidence.all_inputs_prepared(), + TransactionPoolStage::LocalPrepared => self.evidence.all_shard_groups_prepared(), TransactionPoolStage::AllPrepared | TransactionPoolStage::SomePrepared => true, TransactionPoolStage::LocalAccepted => match self.current_decision() { - Decision::Commit => self.evidence.all_addresses_accepted(), + Decision::Commit => self.evidence.all_objects_accepted(), // If we have decided to abort, we can continue if all input addresses are justified - Decision::Abort(_) => self.evidence.all_inputs_prepared(), + Decision::Abort(_) => self.evidence.all_shard_groups_prepared(), }, TransactionPoolStage::AllAccepted | TransactionPoolStage::SomeAccepted | @@ -487,6 +496,10 @@ impl TransactionPoolRecord { } } + pub fn is_global(&self) -> bool { + self.is_global + } + pub fn calculate_leader_fee(&self, num_involved_shards: NonZeroU64, exhaust_divisor: u64) -> LeaderFee { let target_burn = self.transaction_fee.checked_div(exhaust_divisor).unwrap_or(0); let block_fee_after_burn = self.transaction_fee - target_burn; @@ -551,11 +564,21 @@ impl TransactionPoolRecord { let involved_locks = execution.resolved_inputs().iter().chain(execution.resulting_outputs()); for lock in involved_locks { - let addr = lock.to_substate_address(); - let shard_group = addr.to_shard_group(num_preshards, num_committees); - self.evidence_mut() - .add_shard_group(shard_group) - .insert(addr, lock.lock_type()); + if lock.versioned_substate_id().substate_id().is_global() { + // If global, all shard groups have this evidence + let addr = lock.to_substate_address(); + for shard_group in num_preshards.all_shard_groups_iter(num_committees) { + self.evidence_mut() + .add_shard_group(shard_group) + .insert(addr, lock.lock_type()); + } + } else { + let addr = lock.to_substate_address(); + let shard_group = addr.to_shard_group(num_preshards, num_committees); + self.evidence_mut() + .add_shard_group(shard_group) + .insert(addr, lock.lock_type()); + } } // Only change the local decision if we haven't already decided to ABORT if self.local_decision().map_or(true, |d| d.is_commit()) { @@ -773,6 +796,7 @@ mod tests { transaction_fee: fee, leader_fee: None, stage: TransactionPoolStage::New, + is_global: false, pending_stage: None, local_decision: None, remote_decision: None, diff --git a/dan_layer/storage/src/global/template_db.rs b/dan_layer/storage/src/global/template_db.rs index 0295fe751..01a886c1c 100644 --- a/dan_layer/storage/src/global/template_db.rs +++ b/dan_layer/storage/src/global/template_db.rs @@ -24,6 +24,7 @@ use std::str::FromStr; use chrono::NaiveDateTime; use tari_common_types::types::FixedHash; +use tari_dan_common_types::Epoch; use tari_engine_types::TemplateAddress; use crate::global::GlobalDbAdapter; @@ -69,6 +70,7 @@ pub struct DbTemplate { pub template_address: TemplateAddress, pub template_name: String, pub expected_hash: FixedHash, + pub epoch: Epoch, pub template_type: DbTemplateType, pub compiled_code: Option>, pub flow_json: Option, diff --git a/dan_layer/storage/src/state_store/mod.rs b/dan_layer/storage/src/state_store/mod.rs index 6e191b136..64af7c6e6 100644 --- a/dan_layer/storage/src/state_store/mod.rs +++ b/dan_layer/storage/src/state_store/mod.rs @@ -463,6 +463,7 @@ pub trait StateStoreWriteTransaction { tx_id: TransactionId, decision: Decision, is_ready: bool, + is_global: bool, ) -> Result<(), StorageError>; fn transaction_pool_add_pending_update( &mut self, diff --git a/dan_layer/storage_sqlite/migrations/2022-06-20-091532_initial/up.sql b/dan_layer/storage_sqlite/migrations/2022-06-20-091532_initial/up.sql index 4c3cb271f..764b911ce 100644 --- a/dan_layer/storage_sqlite/migrations/2022-06-20-091532_initial/up.sql +++ b/dan_layer/storage_sqlite/migrations/2022-06-20-091532_initial/up.sql @@ -52,29 +52,30 @@ CREATE INDEX committees_validator_node_id_epoch_index ON committees (validator_n create table templates ( - id Integer primary key autoincrement not null, + id Integer primary key autoincrement not null, -- template name - template_name text not null, - expected_hash blob not null, + template_name text not null, + expected_hash blob not null, -- the address is the hash of the content - template_address blob not null, + template_address blob not null, -- where to find the template code - url text not null, - -- the block height in which the template was published - height bigint not null, + url text null, + -- the epoch in which the template was published + epoch bigint not null, -- The type of template, used to create an enum in code - template_type text not null, + template_type text not null, + author_public_key blob not null, -- compiled template code as a WASM binary - compiled_code blob null, + compiled_code blob null, -- flow json - flow_json text null, - status VARCHAR(20) NOT NULL DEFAULT 'New', - wasm_path VARCHAR(255) NULL, - manifest text null, - added_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP + flow_json text null, + status VARCHAR(20) NOT NULL DEFAULT 'New', + manifest text null, + added_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ); + -- fetching by the template_address will be a very common operation create unique index templates_template_address_index on templates (template_address); diff --git a/dan_layer/storage_sqlite/migrations/2024-12-06-134951_templates_on_chain_updates/down.sql b/dan_layer/storage_sqlite/migrations/2024-12-06-134951_templates_on_chain_updates/down.sql deleted file mode 100644 index e2cd4e22d..000000000 --- a/dan_layer/storage_sqlite/migrations/2024-12-06-134951_templates_on_chain_updates/down.sql +++ /dev/null @@ -1,8 +0,0 @@ -ALTER TABLE templates DROP COLUMN author_public_key; -ALTER TABLE templates DROP COLUMN url; - -ALTER TABLE templates ADD COLUMN wasm_path VARCHAR(255) NULL; -ALTER TABLE templates ADD COLUMN url TEXT NOT NULL; -ALTER TABLE templates ADD COLUMN height bigint NOT NULL; - - diff --git a/dan_layer/storage_sqlite/migrations/2024-12-06-134951_templates_on_chain_updates/up.sql b/dan_layer/storage_sqlite/migrations/2024-12-06-134951_templates_on_chain_updates/up.sql deleted file mode 100644 index 5b5067905..000000000 --- a/dan_layer/storage_sqlite/migrations/2024-12-06-134951_templates_on_chain_updates/up.sql +++ /dev/null @@ -1,6 +0,0 @@ -ALTER TABLE templates DROP COLUMN wasm_path; -ALTER TABLE templates DROP COLUMN url; -ALTER TABLE templates DROP COLUMN height; - -ALTER TABLE templates ADD COLUMN author_public_key BLOB NOT NULL; -ALTER TABLE templates ADD COLUMN url TEXT NULL; diff --git a/dan_layer/storage_sqlite/src/global/backend_adapter.rs b/dan_layer/storage_sqlite/src/global/backend_adapter.rs index e301954ac..353ca7713 100644 --- a/dan_layer/storage_sqlite/src/global/backend_adapter.rs +++ b/dan_layer/storage_sqlite/src/global/backend_adapter.rs @@ -221,6 +221,7 @@ impl GlobalDbAdapter for SqliteGlobalDbAdapter { expected_hash: t.expected_hash.try_into()?, template_address: t.template_address.try_into()?, template_type: t.template_type.parse().expect("DB template type corrupted"), + epoch: Epoch(t.epoch as u64), compiled_code: t.compiled_code, flow_json: t.flow_json, manifest: t.manifest, @@ -264,6 +265,7 @@ impl GlobalDbAdapter for SqliteGlobalDbAdapter { url: t.url, status: t.status.parse().expect("DB status corrupted"), added_at: t.added_at, + epoch: Epoch(t.epoch as u64), }) }) .collect() @@ -299,6 +301,7 @@ impl GlobalDbAdapter for SqliteGlobalDbAdapter { url: t.url, status: t.status.parse().expect("DB status corrupted"), added_at: t.added_at, + epoch: Epoch(t.epoch as u64), }) }) .collect() @@ -312,6 +315,7 @@ impl GlobalDbAdapter for SqliteGlobalDbAdapter { template_address: item.template_address.to_vec(), template_type: item.template_type.as_str().to_string(), compiled_code: item.compiled_code, + epoch: item.epoch.as_u64() as i64, flow_json: item.flow_json, status: item.status.as_str().to_string(), manifest: item.manifest, diff --git a/dan_layer/storage_sqlite/src/global/models/template.rs b/dan_layer/storage_sqlite/src/global/models/template.rs index d60b174dc..28b19e0a7 100644 --- a/dan_layer/storage_sqlite/src/global/models/template.rs +++ b/dan_layer/storage_sqlite/src/global/models/template.rs @@ -28,16 +28,17 @@ use crate::global::schema::*; #[diesel(table_name = templates)] pub struct TemplateModel { pub id: i32, - pub author_public_key: Vec, - pub template_address: Vec, pub template_name: String, pub expected_hash: Vec, + pub template_address: Vec, + pub url: Option, + pub epoch: i64, pub template_type: String, + pub author_public_key: Vec, pub compiled_code: Option>, pub flow_json: Option, - pub manifest: Option, - pub url: Option, pub status: String, + pub manifest: Option, pub added_at: NaiveDateTime, } @@ -50,6 +51,7 @@ pub struct NewTemplateModel { pub expected_hash: Vec, pub template_type: String, pub compiled_code: Option>, + pub epoch: i64, pub flow_json: Option, pub status: String, pub manifest: Option, diff --git a/dan_layer/storage_sqlite/src/global/schema.rs b/dan_layer/storage_sqlite/src/global/schema.rs index 182f34916..4adcec647 100644 --- a/dan_layer/storage_sqlite/src/global/schema.rs +++ b/dan_layer/storage_sqlite/src/global/schema.rs @@ -52,16 +52,17 @@ diesel::table! { diesel::table! { templates (id) { id -> Integer, - author_public_key -> Binary, - template_address -> Binary, template_name -> Text, expected_hash -> Binary, + template_address -> Binary, + url -> Nullable, + epoch -> BigInt, template_type -> Text, + author_public_key -> Binary, compiled_code -> Nullable, flow_json -> Nullable, - manifest -> Nullable, - url -> Nullable, status -> Text, + manifest -> Nullable, added_at -> Timestamp, } } diff --git a/dan_layer/template_test_tooling/src/package_builder.rs b/dan_layer/template_test_tooling/src/package_builder.rs index 4c171df12..8f99bb6c2 100644 --- a/dan_layer/template_test_tooling/src/package_builder.rs +++ b/dan_layer/template_test_tooling/src/package_builder.rs @@ -7,7 +7,6 @@ use std::{ sync::{Arc, Mutex}, }; -use tari_common_types::types::PublicKey; use tari_dan_common_types::services::template_provider::TemplateProvider; use tari_dan_engine::{ abi::TemplateDef, @@ -110,17 +109,4 @@ impl TemplateProvider for Package { ) -> Result, Self::Error> { Ok(self.templates.lock().unwrap().get(id).cloned()) } - - fn add_wasm_template( - &self, - _author_public_key: PublicKey, - template_address: tari_engine_types::TemplateAddress, - template: &[u8], - ) -> Result<(), Self::Error> { - self.templates - .lock() - .unwrap() - .insert(template_address, WasmModule::load_template_from_code(template)?); - Ok(()) - } }