Skip to content

Commit

Permalink
update to Arc<Transaction> checkpoint..
Browse files Browse the repository at this point in the history
  • Loading branch information
D-Stacks committed Nov 23, 2024
1 parent 821c7f2 commit f2935b5
Show file tree
Hide file tree
Showing 21 changed files with 141 additions and 88 deletions.
2 changes: 1 addition & 1 deletion consensus/core/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ pub trait ConsensusApi: Send + Sync {
unimplemented!()
}

fn calc_transaction_hash_merkle_root(&self, txs: &[Transaction], pov_daa_score: u64) -> Hash {
fn calc_transaction_hash_merkle_root(&self, txs: &[Arc<Transaction>], pov_daa_score: u64) -> Hash {
unimplemented!()
}

Expand Down
30 changes: 21 additions & 9 deletions consensus/core/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
BlueWorkType,
};
use kaspa_hashes::Hash;
use kaspa_utils::mem_size::MemSizeEstimator;
use kaspa_utils::{arc::ArcExtensions, mem_size::MemSizeEstimator};
use std::sync::Arc;

/// A mutable block structure where header and transactions within can still be mutated.
Expand All @@ -25,7 +25,19 @@ impl MutableBlock {
}

pub fn to_immutable(self) -> Block {
Block::new(self.header, self.transactions)
Block::new(self.header, self.transactions.into_iter().map(Arc::new).collect())
}
}

impl From<Block> for MutableBlock {
fn from(block: Block) -> Self {
Self { header: block.header.unwrap_or_clone(), transactions: block.transactions.iter().map(|tx| (**tx).clone()).collect() }
}
}

impl From<MutableBlock> for Block {
fn from(mutable_block: MutableBlock) -> Self {
mutable_block.to_immutable()
}
}

Expand All @@ -35,15 +47,15 @@ impl MutableBlock {
#[derive(Debug, Clone)]
pub struct Block {
pub header: Arc<Header>,
pub transactions: Arc<Vec<Transaction>>,
pub transactions: Arc<Vec<Arc<Transaction>>>,
}

impl Block {
pub fn new(header: Header, txs: Vec<Transaction>) -> Self {
pub fn new(header: Header, txs: Vec<Arc<Transaction>>) -> Self {
Self { header: Arc::new(header), transactions: Arc::new(txs) }
}

pub fn from_arcs(header: Arc<Header>, transactions: Arc<Vec<Transaction>>) -> Self {
pub fn from_arcs(header: Arc<Header>, transactions: Arc<Vec<Arc<Transaction>>>) -> Self {
Self { header, transactions }
}

Expand Down Expand Up @@ -79,7 +91,7 @@ impl MemSizeEstimator for Block {
size_of::<Self>()
+ self.header.estimate_mem_bytes()
+ size_of::<Vec<Transaction>>()
+ self.transactions.iter().map(Transaction::estimate_mem_bytes).sum::<usize>()
+ self.transactions.iter().map(|tx| tx.estimate_mem_bytes()).sum::<usize>()
}
}

Expand All @@ -88,7 +100,7 @@ pub trait TemplateTransactionSelector {
/// Expected to return a batch of transactions which were not previously selected.
/// The batch will typically contain sufficient transactions to fill the block
/// mass (along with the previously unrejected txs), or will drain the selector
fn select_transactions(&mut self) -> Vec<Transaction>;
fn select_transactions(&mut self) -> Vec<Arc<Transaction>>;

/// Should be used to report invalid transactions obtained from the *most recent*
/// `select_transactions` call. Implementors should use this call to internally
Expand All @@ -114,7 +126,7 @@ pub enum TemplateBuildMode {
/// A block template for miners.
#[derive(Debug, Clone)]
pub struct BlockTemplate {
pub block: MutableBlock,
pub block: Block,
pub miner_data: MinerData,
pub coinbase_has_red_reward: bool,
pub selected_parent_timestamp: u64,
Expand All @@ -126,7 +138,7 @@ pub struct BlockTemplate {

impl BlockTemplate {
pub fn new(
block: MutableBlock,
block: Block,
miner_data: MinerData,
coinbase_has_red_reward: bool,
selected_parent_timestamp: u64,
Expand Down
8 changes: 5 additions & 3 deletions consensus/core/src/config/genesis.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::sync::Arc;

use crate::{block::Block, header::Header, subnets::SUBNETWORK_ID_COINBASE, tx::Transaction};
use kaspa_hashes::{Hash, ZERO_HASH};
use kaspa_muhash::EMPTY_MUHASH;
Expand All @@ -17,8 +19,8 @@ pub struct GenesisBlock {
}

impl GenesisBlock {
pub fn build_genesis_transactions(&self) -> Vec<Transaction> {
vec![Transaction::new(0, Vec::new(), Vec::new(), 0, SUBNETWORK_ID_COINBASE, 0, self.coinbase_payload.to_vec())]
pub fn build_genesis_transactions(&self) -> Vec<Arc<Transaction>> {
vec![Arc::new(Transaction::new(0, Vec::new(), Vec::new(), 0, SUBNETWORK_ID_COINBASE, 0, self.coinbase_payload.to_vec()))]
}
}

Expand Down Expand Up @@ -231,7 +233,7 @@ mod tests {
fn test_genesis_hashes() {
[GENESIS, TESTNET_GENESIS, TESTNET11_GENESIS, SIMNET_GENESIS, DEVNET_GENESIS].into_iter().for_each(|genesis| {
let block: Block = (&genesis).into();
assert_hashes_eq(calc_hash_merkle_root(block.transactions.iter(), false), block.header.hash_merkle_root);
assert_hashes_eq(calc_hash_merkle_root(block.transactions.iter().map(|tx| &(**tx)), false), block.header.hash_merkle_root);
assert_hashes_eq(block.hash(), genesis.hash);
});
}
Expand Down
4 changes: 2 additions & 2 deletions consensus/src/consensus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -742,9 +742,9 @@ impl ConsensusApi for Consensus {
self.services.coinbase_manager.modify_coinbase_payload(payload, miner_data)
}

fn calc_transaction_hash_merkle_root(&self, txs: &[Transaction], pov_daa_score: u64) -> Hash {
fn calc_transaction_hash_merkle_root(&self, txs: &[Arc<Transaction>], pov_daa_score: u64) -> Hash {
let storage_mass_activated = self.config.storage_mass_activation.is_active(pov_daa_score);
calc_hash_merkle_root(txs.iter(), storage_mass_activated)
calc_hash_merkle_root(txs.iter().map(|tx| &**tx), storage_mass_activated)
}

fn validate_pruning_proof(
Expand Down
11 changes: 5 additions & 6 deletions consensus/src/consensus/test_consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,10 @@ impl TestConsensus {
&self,
hash: Hash,
parents: Vec<Hash>,
txs: Vec<Transaction>,
txs: Vec<Arc<Transaction>>,
) -> impl Future<Output = BlockProcessResult<BlockStatus>> {
let miner_data = MinerData::new(ScriptPublicKey::from_vec(0, vec![]), vec![]);
self.validate_and_insert_block(self.build_utxo_valid_block_with_parents(hash, parents, miner_data, txs).to_immutable())
self.validate_and_insert_block(self.build_utxo_valid_block_with_parents(hash, parents, miner_data, txs.clone()).to_immutable())
.virtual_state_task
}

Expand All @@ -164,11 +164,10 @@ impl TestConsensus {
hash: Hash,
parents: Vec<Hash>,
miner_data: MinerData,
txs: Vec<Transaction>,
txs: Vec<Arc<Transaction>>,
) -> MutableBlock {
let mut template = self.block_builder.build_block_template_with_parents(parents, miner_data, txs).unwrap();
template.block.header.hash = hash;
template.block
let template = self.block_builder.build_block_template_with_parents(parents, miner_data, txs).unwrap();
MutableBlock::new((*template.block.header).clone(), template.block.transactions.iter().map(|tx| (**tx).clone()).collect())
}

pub fn build_block_with_parents_and_transactions(
Expand Down
33 changes: 19 additions & 14 deletions consensus/src/model/stores/block_transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,16 @@ impl AsRef<[u8]> for BlockTransactionFullAccessKey {
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
struct BlockBody(Arc<Vec<Transaction>>);
struct BlockBody(Arc<Vec<Arc<Transaction>>>);

pub trait BlockTransactionsStoreReader {
fn get(&self, block_hash: Hash) -> Result<Arc<Vec<Transaction>>, StoreError>;
fn get_at_index(&self, block_hash: Hash, index: TransactionIndexType) -> Result<Transaction, StoreError>;
fn get(&self, block_hash: Hash) -> Result<Arc<Vec<Arc<Transaction>>>, StoreError>;
fn get_at_index(&self, block_hash: Hash, index: TransactionIndexType) -> Result<Arc<Transaction>, StoreError>;
}

pub trait BlockTransactionsStore: BlockTransactionsStoreReader {
// This is append only
fn insert(&self, hash: Hash, transactions: Arc<Vec<Transaction>>) -> Result<(), StoreError>;
fn insert(&self, hash: Hash, transactions: Arc<Vec<Arc<Transaction>>>) -> Result<(), StoreError>;
fn delete(&self, hash: Hash) -> Result<(), StoreError>;
}

Expand All @@ -83,7 +83,7 @@ impl MemSizeEstimator for BlockBody {
#[derive(Clone)]
pub struct DbBlockTransactionsStore {
db: Arc<DB>,
access: CachedDbAccess<BlockTransactionFullAccessKey, Transaction>,
access: CachedDbAccess<BlockTransactionFullAccessKey, Arc<Transaction>>,
cache: Cache<Hash, BlockBody>,
}

Expand All @@ -104,7 +104,12 @@ impl DbBlockTransactionsStore {
Ok(self.cache.contains_key(&hash) || self.access.has_bucket(hash.as_bytes().as_ref())?)
}

pub fn insert_batch(&self, batch: &mut WriteBatch, hash: Hash, transactions: Arc<Vec<Transaction>>) -> Result<(), StoreError> {
pub fn insert_batch(
&self,
batch: &mut WriteBatch,
hash: Hash,
transactions: Arc<Vec<Arc<Transaction>>>,
) -> Result<(), StoreError> {
if self.cache.contains_key(&hash) || self.access.has_bucket(hash.as_bytes().as_ref())? {
return Err(StoreError::HashAlreadyExists(hash));
}
Expand All @@ -127,7 +132,7 @@ impl DbBlockTransactionsStore {
}

impl BlockTransactionsStoreReader for DbBlockTransactionsStore {
fn get(&self, hash: Hash) -> Result<Arc<Vec<Transaction>>, StoreError> {
fn get(&self, hash: Hash) -> Result<Arc<Vec<Arc<Transaction>>>, StoreError> {
self.cache
.get(&hash)
.map(|block_transactions| block_transactions.0.clone())
Expand All @@ -139,22 +144,22 @@ impl BlockTransactionsStoreReader for DbBlockTransactionsStore {
}
}

fn get_at_index(&self, block_hash: Hash, index: TransactionIndexType) -> Result<Transaction, StoreError> {
if let Some(block_transactions) = self.cache.get(&block_hash) {
return Ok(block_transactions.0[index as usize].clone());
fn get_at_index(&self, block_hash: Hash, index: TransactionIndexType) -> Result<Arc<Transaction>, StoreError> {
Ok(if let Some(block_transactions) = self.cache.get(&block_hash) {
block_transactions.0[index as usize].clone()
} else {
self.access.read(BlockTransactionFullAccessKey::new(&block_hash, index))
}
self.access.read(BlockTransactionFullAccessKey::new(&block_hash, index))?
})
}
}

impl BlockTransactionsStore for DbBlockTransactionsStore {
fn insert(&self, hash: Hash, transactions: Arc<Vec<Transaction>>) -> Result<(), StoreError> {
fn insert(&self, hash: Hash, transactions: Arc<Vec<Arc<Transaction>>>) -> Result<(), StoreError> {
if self.access.has_bucket(hash.as_bytes().as_ref())? {
return Err(StoreError::HashAlreadyExists(hash));
}
self.cache.insert(hash, BlockBody(transactions.clone()));
self.access.write_many_without_cache(
self.access.write_many(
DirectDbWriter::new(&self.db),
&mut transactions
.iter()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl BlockBodyProcessor {
}

fn check_hash_merkle_root(block: &Block, storage_mass_activated: bool) -> BlockProcessResult<()> {
let calculated = calc_hash_merkle_root(block.transactions.iter(), storage_mass_activated);
let calculated = calc_hash_merkle_root(block.transactions.iter().map(|tx| &**tx), storage_mass_activated);
if calculated != block.header.hash_merkle_root {
return Err(RuleError::BadMerkleRoot(block.header.hash_merkle_root, calculated));
}
Expand Down
2 changes: 1 addition & 1 deletion consensus/src/pipeline/body_processor/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ impl BlockBodyProcessor {
Ok(mass)
}

fn commit_body(self: &Arc<BlockBodyProcessor>, hash: Hash, parents: &[Hash], transactions: Arc<Vec<Transaction>>) {
fn commit_body(self: &Arc<BlockBodyProcessor>, hash: Hash, parents: &[Hash], transactions: Arc<Vec<Arc<Transaction>>>) {
let mut batch = WriteBatch::default();

// This is an append only store so it requires no lock.
Expand Down
16 changes: 8 additions & 8 deletions consensus/src/pipeline/virtual_processor/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ use crate::{
use kaspa_consensus_core::{
acceptance_data::AcceptanceData,
api::args::{TransactionValidationArgs, TransactionValidationBatchArgs},
block::{BlockTemplate, MutableBlock, TemplateBuildMode, TemplateTransactionSelector},
block::{Block, BlockTemplate, MutableBlock, TemplateBuildMode, TemplateTransactionSelector},
blockstatus::BlockStatus::{StatusDisqualifiedFromChain, StatusUTXOValid},
coinbase::MinerData,
config::{genesis::GenesisBlock, params::ForkActivation},
Expand Down Expand Up @@ -83,7 +83,7 @@ use super::errors::{PruningImportError, PruningImportResult};
use crossbeam_channel::{Receiver as CrossbeamReceiver, Sender as CrossbeamSender};
use itertools::Itertools;
use kaspa_consensus_core::tx::ValidatedTransaction;
use kaspa_utils::binary_heap::BinaryHeapExtensions;
use kaspa_utils::{arc::ArcExtensions, binary_heap::BinaryHeapExtensions};
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
use rand::{seq::SliceRandom, Rng};
use rayon::{
Expand Down Expand Up @@ -879,7 +879,7 @@ impl VirtualStateProcessor {

fn validate_block_template_transactions_in_parallel<V: UtxoView + Sync>(
&self,
txs: &[Transaction],
txs: &[Arc<Transaction>],
virtual_state: &VirtualState,
utxo_view: &V,
) -> Vec<TxResult<u64>> {
Expand Down Expand Up @@ -977,7 +977,7 @@ impl VirtualStateProcessor {

pub(crate) fn validate_block_template_transactions(
&self,
txs: &[Transaction],
txs: &[Arc<Transaction>],
virtual_state: &VirtualState,
utxo_view: &impl UtxoView,
) -> Result<(), RuleError> {
Expand All @@ -999,7 +999,7 @@ impl VirtualStateProcessor {
&self,
virtual_state: Arc<VirtualState>,
miner_data: MinerData,
mut txs: Vec<Transaction>,
mut txs: Vec<Arc<Transaction>>,
calculated_fees: Vec<u64>,
) -> Result<BlockTemplate, RuleError> {
// [`calc_block_parents`] can use deep blocks below the pruning point for this calculation, so we
Expand All @@ -1018,13 +1018,13 @@ impl VirtualStateProcessor {
&virtual_state.mergeset_non_daa,
)
.unwrap();
txs.insert(0, coinbase.tx);
txs.insert(0, Arc::new(coinbase.tx));
let version = BLOCK_VERSION;
let parents_by_level = self.parents_manager.calc_block_parents(pruning_info.pruning_point, &virtual_state.parents);

// Hash according to hardfork activation
let storage_mass_activated = self.storage_mass_activation.is_active(virtual_state.daa_score);
let hash_merkle_root = calc_hash_merkle_root(txs.iter(), storage_mass_activated);
let hash_merkle_root = calc_hash_merkle_root(txs.iter().map(|tx| &**tx), storage_mass_activated);

let accepted_id_merkle_root = kaspa_merkle::calc_merkle_root(virtual_state.accepted_tx_ids.iter().copied());
let utxo_commitment = virtual_state.multiset.clone().finalize();
Expand All @@ -1048,7 +1048,7 @@ impl VirtualStateProcessor {
let selected_parent_timestamp = self.headers_store.get_timestamp(selected_parent_hash).unwrap();
let selected_parent_daa_score = self.headers_store.get_daa_score(selected_parent_hash).unwrap();
Ok(BlockTemplate::new(
MutableBlock::new(header, txs),
Block::new(header, txs),
miner_data,
coinbase.has_red_reward,
selected_parent_timestamp,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl TestBlockBuilder {
&self,
parents: Vec<Hash>,
miner_data: MinerData,
txs: Vec<Transaction>,
txs: Vec<Arc<Transaction>>,
) -> Result<BlockTemplate, RuleError> {
//
// In the context of this method "pov virtual" is the virtual block which has `parents` as tips and not the actual virtual
Expand Down
18 changes: 10 additions & 8 deletions consensus/src/pipeline/virtual_processor/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ use kaspa_consensus_core::{
BlockHashSet,
};
use kaspa_hashes::Hash;
use std::{collections::VecDeque, thread::JoinHandle};
use std::{collections::VecDeque, sync::Arc, thread::JoinHandle};

struct OnetimeTxSelector {
txs: Option<Vec<Transaction>>,
txs: Option<Vec<Arc<Transaction>>>,
}

impl OnetimeTxSelector {
fn new(txs: Vec<Transaction>) -> Self {
fn new(txs: Vec<Arc<Transaction>>) -> Self {
Self { txs: Some(txs) }
}
}

impl TemplateTransactionSelector for OnetimeTxSelector {
fn select_transactions(&mut self) -> Vec<Transaction> {
fn select_transactions(&mut self) -> Vec<Arc<Transaction>> {
self.txs.take().unwrap()
}

Expand Down Expand Up @@ -85,7 +85,7 @@ impl TestContext {
self.current_tips.clear();
while let Some(t) = self.current_templates.pop_front() {
self.current_tips.insert(t.block.header.hash);
self.validate_and_insert_block(t.block.to_immutable()).await;
self.validate_and_insert_block(t.block).await;
}
self
}
Expand All @@ -110,9 +110,11 @@ impl TestContext {
TemplateBuildMode::Standard,
)
.unwrap();
t.block.header.timestamp = timestamp;
t.block.header.nonce = nonce;
t.block.header.finalize();
let mut mutable_block = MutableBlock::from(t.block);
mutable_block.header.timestamp = timestamp;
mutable_block.header.nonce = nonce;
mutable_block.header.finalize();
t.block = mutable_block.into();
t
}

Expand Down
Loading

0 comments on commit f2935b5

Please sign in to comment.