Skip to content

Commit

Permalink
Add stateful checks for chain ID and expiry height
Browse files Browse the repository at this point in the history
  • Loading branch information
plaidfinch committed May 3, 2024
1 parent db773d8 commit 68f7627
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 1 deletion.
9 changes: 8 additions & 1 deletion crates/core/app/src/action_handler/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ use super::AppActionHandler;
mod stateful;
mod stateless;

use self::stateful::{claimed_anchor_is_valid, fee_greater_than_base_fee, fmd_parameters_valid};
use self::stateful::{
chain_id_is_correct, claimed_anchor_is_valid, expiry_height_is_valid,
fee_greater_than_base_fee, fmd_parameters_valid,
};
use stateless::{
check_memo_exists_if_outputs_absent_if_not, num_clues_equal_to_num_outputs,
valid_binding_signature,
Expand Down Expand Up @@ -58,6 +61,10 @@ impl AppActionHandler for Transaction {

// TODO: these could be pushed into the action checks and run concurrently if needed

// SAFETY: chain ID never changes during a transaction execution.
chain_id_is_correct(state.clone(), self).await?;
// SAFETY: height never changes during a transaction execution.
expiry_height_is_valid(state.clone(), self).await?;
// SAFETY: anchors are historical data and cannot change during transaction execution.
claimed_anchor_is_valid(state.clone(), self).await?;
// SAFETY: FMD parameters cannot change during transaction execution.
Expand Down
42 changes: 42 additions & 0 deletions crates/core/app/src/action_handler/transaction/stateful.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,50 @@ use penumbra_shielded_pool::fmd;
use penumbra_transaction::gas::GasCost;
use penumbra_transaction::Transaction;

use crate::app::StateReadExt;

const FMD_GRACE_PERIOD_BLOCKS: u64 = 10;

pub async fn chain_id_is_correct<S: StateRead>(state: S, transaction: &Transaction) -> Result<()> {
let chain_id = state.get_chain_id().await?;
let tx_chain_id = &transaction.transaction_body.transaction_parameters.chain_id;

// The chain ID in the transaction must exactly match the current chain ID.
ensure!(
*tx_chain_id == chain_id,
"transaction chain ID '{}' must match the current chain ID '{}'",
tx_chain_id,
chain_id
);
Ok(())
}

pub async fn expiry_height_is_valid<S: StateRead>(
state: S,
transaction: &Transaction,
) -> Result<()> {
let current_height = state.get_block_height().await?;
let expiry_height = transaction
.transaction_body
.transaction_parameters
.expiry_height;

// A zero expiry height means that the transaction is valid indefinitely.
if expiry_height == 0 {
return Ok(());
}

// Otherwise, the expiry height must be greater than or equal to the current block height.
ensure!(
expiry_height >= current_height,
"transaction expiry height '{}' must be greater than or equal to the current block height '{}'",
expiry_height,
current_height
);

Ok(())
}

pub async fn fmd_parameters_valid<S: StateRead>(state: S, transaction: &Transaction) -> Result<()> {
let previous_fmd_parameters = state
.get_previous_fmd_parameters()
Expand Down

0 comments on commit 68f7627

Please sign in to comment.