Skip to content

Commit

Permalink
fmt
Browse files Browse the repository at this point in the history
  • Loading branch information
iljakuklic committed May 13, 2024
1 parent 312439e commit 8dea4e5
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 43 deletions.
2 changes: 1 addition & 1 deletion chainstate/tx-verifier/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ pub mod transaction_verifier;

pub use transaction_verifier::{
check_transaction::{check_transaction, CheckTransactionError},
input_check::{BlockVerificationContext, TransactionVerificationContext},
error,
flush::flush_to_storage,
input_check::{BlockVerificationContext, TransactionVerificationContext},
storage::{
TransactionVerifierStorageError, TransactionVerifierStorageMut,
TransactionVerifierStorageRef,
Expand Down
113 changes: 71 additions & 42 deletions chainstate/tx-verifier/src/transaction_verifier/input_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use common::{
chain::{
block::timestamp::BlockTimestamp,
signature::{verify_signature, Signable, Transactable},
ChainConfig, GenBlock, TxInput, TxOutput,
ChainConfig, GenBlock, TxInput, TxOutput, UtxoOutPoint,
},
primitives::{BlockHeight, Id},
};
Expand All @@ -33,9 +33,7 @@ use super::{

pub struct BlockVerificationContext<'a> {
chain_config: &'a ChainConfig,
// TODO(PR): remove dest getter?
destination_getter: SignatureDestinationGetter<'a>,
// TODO(PR): Remove this?
spending_time: BlockTimestamp,
spending_height: BlockHeight,
tip: Id<GenBlock>,
Expand Down Expand Up @@ -97,23 +95,30 @@ impl<'a> BlockVerificationContext<'a> {
}
}

enum InputSpendingInfo {
Utxo {
timestamp: BlockTimestamp,
height: BlockHeight,
},
struct UtxoInputSpendingInfo {
timestamp: BlockTimestamp,
height: BlockHeight,
}

// TODO Add support for accounts
enum InputSpendingInfo {
Utxo(UtxoInputSpendingInfo),
Account,
AccountCommand,
}

// TODO(PR): Create a lazy version
impl InputSpendingInfo {
fn as_utxo(&self) -> Option<&UtxoInputSpendingInfo> {
match self {
Self::Utxo(info) => Some(info),
Self::AccountCommand | Self::Account => None,
}
}
}

pub struct TransactionVerificationContext<'a, T> {
block_ctx: &'a BlockVerificationContext<'a>,
transactable: &'a T,
spent_outputs: Vec<Option<TxOutput>>,
// TODO(PR): move this info into the utxo itself? Maybe not... will not work with mempool
spent_infos: Vec<InputSpendingInfo>,
}

Expand All @@ -136,7 +141,6 @@ impl<'a, T: Signable + Transactable> TransactionVerificationContext<'a, T> {
ConnectTransactionError::MissingOutputOrSpent(outpoint.clone()),
)?;

// TODO(PR) Move this information into Utxo
let (height, timestamp) = match utxo.source() {
utxo::UtxoSource::Blockchain(height) => {
let block_index_getter = |db_tx: &S, _cc: &ChainConfig, id: &Id<GenBlock>| {
Expand All @@ -163,8 +167,8 @@ impl<'a, T: Signable + Transactable> TransactionVerificationContext<'a, T> {
}
};

let spending_info = InputSpendingInfo::Utxo { timestamp, height };
(Some(utxo.take_output()), spending_info)
let info = UtxoInputSpendingInfo { timestamp, height };
(Some(utxo.take_output()), InputSpendingInfo::Utxo(info))
}
TxInput::Account(..) => (None, InputSpendingInfo::Account),
TxInput::AccountCommand(..) => (None, InputSpendingInfo::AccountCommand),
Expand All @@ -185,7 +189,7 @@ impl<'a, T: Signable + Transactable> TransactionVerificationContext<'a, T> {
self.transactable.inputs().unwrap_or(&[])
}

pub fn try_for_each_input<E>(
fn try_for_each_input<E>(
&self,
mut func: impl FnMut(InputVerificationContext<T>) -> Result<(), E>,
) -> Result<(), E> {
Expand All @@ -202,62 +206,87 @@ impl<'a, T: Signable + Transactable> TransactionVerificationContext<'a, T> {
}
}

pub struct InputVerificationContext<'a, T> {
struct InputVerificationContext<'a, T> {
transaction_ctx: &'a TransactionVerificationContext<'a, T>,
input_index: usize,
info: InputVerificationInfo<'a>,
}

enum InputVerificationInfo<'a> {
Utxo(UtxoInputVerificationInfo<'a>),
Account,
AccountCommand,
}

struct UtxoInputVerificationInfo<'a> {
output: &'a TxOutput,
spending_info: &'a UtxoInputSpendingInfo,
outpoint: &'a UtxoOutPoint,
}

impl<'a, T: Signable + Transactable> InputVerificationContext<'a, T> {
fn new(transaction_ctx: &'a TransactionVerificationContext<'a, T>, input_index: usize) -> Self {
assert!(input_index < transaction_ctx.spent_infos.len());

let info = match &transaction_ctx.inputs()[input_index] {
TxInput::Utxo(outpoint) => {
let output = &transaction_ctx.spent_outputs[input_index]
.as_ref()
.expect("Already checked on construction");
let spending_info = (&transaction_ctx.spent_infos[input_index])
.as_utxo()
.expect("Already checked on construction");
let info = UtxoInputVerificationInfo {
output,
spending_info,
outpoint,
};
InputVerificationInfo::Utxo(info)
}
TxInput::Account(_outpoint) => InputVerificationInfo::Account,
TxInput::AccountCommand(_nonce, _command) => InputVerificationInfo::AccountCommand,
};

Self {
transaction_ctx,
input_index,
info,
}
}

fn input(&self) -> &TxInput {
&self.transaction_ctx.inputs()[self.input_index]
}

fn spent_output(&self) -> Option<&TxOutput> {
self.transaction_ctx.spent_outputs[self.input_index].as_ref()
}

fn spent_info(&self) -> &InputSpendingInfo {
&self.transaction_ctx.spent_infos[self.input_index]
}

fn verify_input(&self) -> Result<(), ConnectTransactionError> {
self.check_timelock()?;
self.check_signatures()?;
Ok(())
}

fn check_timelock(&self) -> Result<(), ConnectTransactionError> {
if let Some(timelock) = self.spent_output().and_then(|o| o.timelock()) {
let (source_block_time, source_block_height) = match self.spent_info() {
InputSpendingInfo::Utxo { timestamp, height } => (timestamp, height),
InputSpendingInfo::Account | InputSpendingInfo::AccountCommand => {
panic!("already checked TODO(PR)")
}
};

super::timelock_check::check_timelock(
source_block_height,
source_block_time,
timelock,
&self.transaction_ctx.block_ctx.spending_height,
&self.transaction_ctx.block_ctx.spending_time,
self.input().utxo_outpoint().expect("already checked"),
)?;
match &self.info {
InputVerificationInfo::Utxo(info) => {
let timelock = match info.output.timelock() {
Some(timelock) => timelock,
None => return Ok(()),
};
super::timelock_check::check_timelock(
&info.spending_info.height,
&info.spending_info.timestamp,
timelock,
&self.transaction_ctx.block_ctx.spending_height,
&self.transaction_ctx.block_ctx.spending_time,
&info.outpoint,
)
}
InputVerificationInfo::Account => Ok(()),
InputVerificationInfo::AccountCommand => Ok(()),
}
Ok(())
}

fn check_signatures(&self) -> Result<(), ConnectTransactionError> {
let block_ctx = self.transaction_ctx.block_ctx;
// TODO(PR) this should not be necessary
let spent_inputs =
self.transaction_ctx.spent_outputs.iter().map(|o| o.as_ref()).collect_vec();
verify_signature(
Expand Down

0 comments on commit 8dea4e5

Please sign in to comment.