Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suggested refactor for determining lock time type prior the call #9

Open
wants to merge 1 commit into
base: optimize-window-cache-building-for-ibd
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ use super::BlockBodyProcessor;
use crate::{
errors::{BlockProcessResult, RuleError},
model::stores::{ghostdag::GhostdagStoreReader, statuses::StatusesStoreReader},
processes::window::WindowManager,
processes::{
transaction_validator::{
tx_validation_not_utxo_related::{LockTimeArg, LockTimeType},
TransactionValidator,
},
window::WindowManager,
},
};
use kaspa_consensus_core::block::Block;
use kaspa_database::prelude::StoreResultExtensions;
Expand All @@ -19,19 +25,21 @@ impl BlockBodyProcessor {
}

fn check_block_transactions_in_context(self: &Arc<Self>, block: &Block) -> BlockProcessResult<()> {
// TODO: this is somewhat expensive during ibd, as it incurs cache misses.
let pmt_res =
Lazy::new(|| match self.window_manager.calc_past_median_time(&self.ghostdag_store.get_data(block.hash()).unwrap()) {
Ok((pmt, _)) => Ok(pmt),
Err(e) => Err(e),
});

for tx in block.transactions.iter() {
// quick check to avoid the expensive Lazy eval during ibd (in most cases).
if tx.lock_time != 0 {
if let Err(e) = self.transaction_validator.utxo_free_tx_validation(tx, block.header.daa_score, (*pmt_res).clone()?) {
return Err(RuleError::TxInContextFailed(tx.id(), e));
};
let lock_time_arg = match TransactionValidator::get_lock_time_type(tx) {
LockTimeType::Finalized => LockTimeArg::Finalized,
LockTimeType::DaaScore => LockTimeArg::DaaScore(block.header.daa_score),
// We only evaluate the pmt calculation when actually needed
LockTimeType::Time => LockTimeArg::MedianTime((*pmt_res).clone()?),
};
if let Err(e) = self.transaction_validator.utxo_free_tx_validation(tx, lock_time_arg) {
return Err(RuleError::TxInContextFailed(tx.id(), e));
};
}
Ok(())
Expand Down
4 changes: 2 additions & 2 deletions consensus/src/pipeline/virtual_processor/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,7 @@ impl VirtualStateProcessor {
args: &TransactionValidationArgs,
) -> TxResult<()> {
self.transaction_validator.validate_tx_in_isolation(&mutable_tx.tx)?;
self.transaction_validator.utxo_free_tx_validation(&mutable_tx.tx, virtual_daa_score, virtual_past_median_time)?;
self.transaction_validator.utxo_free_tx_validation_with_args(&mutable_tx.tx, virtual_daa_score, virtual_past_median_time)?;
self.validate_mempool_transaction_in_utxo_context(mutable_tx, virtual_utxo_view, virtual_daa_score, args)?;
Ok(())
}
Expand Down Expand Up @@ -891,7 +891,7 @@ impl VirtualStateProcessor {
// No need to validate the transaction in isolation since we rely on the mining manager to submit transactions
// which were previously validated through `validate_mempool_transaction_and_populate`, hence we only perform
// in-context validations
self.transaction_validator.utxo_free_tx_validation(tx, virtual_state.daa_score, virtual_state.past_median_time)?;
self.transaction_validator.utxo_free_tx_validation_with_args(tx, virtual_state.daa_score, virtual_state.past_median_time)?;
let ValidatedTransaction { calculated_fee, .. } =
self.validate_transaction_in_utxo_context(tx, utxo_view, virtual_state.daa_score, TxValidationFlags::Full)?;
Ok(calculated_fee)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,57 @@ use super::{
TransactionValidator,
};

pub(crate) enum LockTimeType {
Finalized,
DaaScore,
Time,
}

pub(crate) enum LockTimeArg {
Finalized,
DaaScore(u64),
MedianTime(u64),
}

impl TransactionValidator {
pub fn utxo_free_tx_validation(&self, tx: &Transaction, ctx_daa_score: u64, ctx_block_time: u64) -> TxResult<()> {
self.check_tx_is_finalized(tx, ctx_daa_score, ctx_block_time)
pub(crate) fn utxo_free_tx_validation_with_args(&self, tx: &Transaction, ctx_daa_score: u64, ctx_block_time: u64) -> TxResult<()> {
self.utxo_free_tx_validation(
tx,
match Self::get_lock_time_type(tx) {
LockTimeType::Finalized => LockTimeArg::Finalized,
LockTimeType::DaaScore => LockTimeArg::DaaScore(ctx_daa_score),
LockTimeType::Time => LockTimeArg::MedianTime(ctx_block_time),
},
)
}

fn check_tx_is_finalized(&self, tx: &Transaction, ctx_daa_score: u64, ctx_block_time: u64) -> TxResult<()> {
// Lock time of zero means the transaction is finalized.
if tx.lock_time == 0 {
return Ok(());
pub(crate) fn utxo_free_tx_validation(&self, tx: &Transaction, lock_time_arg: LockTimeArg) -> TxResult<()> {
self.check_tx_is_finalized(tx, lock_time_arg)
}

pub(crate) fn get_lock_time_type(tx: &Transaction) -> LockTimeType {
match tx.lock_time {
// Lock time of zero means the transaction is finalized.
0 => LockTimeType::Finalized,

// The lock time field of a transaction is either a block DAA score at
// which the transaction is finalized or a timestamp depending on if the
// value is before the LOCK_TIME_THRESHOLD. When it is under the
// threshold it is a DAA score
t if t < LOCK_TIME_THRESHOLD => LockTimeType::DaaScore,

// ..and when equal or above the threshold it represents time
_t => LockTimeType::Time,
}
}

fn check_tx_is_finalized(&self, tx: &Transaction, lock_time_arg: LockTimeArg) -> TxResult<()> {
let block_time_or_daa_score = match lock_time_arg {
LockTimeArg::Finalized => return Ok(()),
LockTimeArg::DaaScore(ctx_daa_score) => ctx_daa_score,
LockTimeArg::MedianTime(ctx_block_time) => ctx_block_time,
};

// The lock time field of a transaction is either a block DAA score at
// which the transaction is finalized or a timestamp depending on if the
// value is before the LOCK_TIME_THRESHOLD. When it is under the
// threshold it is a DAA score.
let block_time_or_daa_score = if tx.lock_time < LOCK_TIME_THRESHOLD { ctx_daa_score } else { ctx_block_time };
if tx.lock_time < block_time_or_daa_score {
return Ok(());
}
Expand Down