Skip to content

Commit

Permalink
feat(applying): check tx ttl
Browse files Browse the repository at this point in the history
  • Loading branch information
MaicoLeberle committed Nov 21, 2023
1 parent bc6a30d commit 801f86c
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 14 deletions.
4 changes: 3 additions & 1 deletion pallas-applying/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@ pub fn validate(metx: &MultiEraTx, utxos: &UTxOs, env: &Environment) -> Validati
Environment {
prot_params: MultiEraProtParams::Byron(bpp),
prot_magic,
..
},
) => validate_byron_tx(mtxp, utxos, bpp, prot_magic),
(
AlonzoCompatible(shelley_minted_tx, Era::Shelley),
Environment {
prot_params: MultiEraProtParams::Shelley(spp),
prot_magic,
block_slot,
},
) => validate_shelley_tx(shelley_minted_tx, utxos, spp, prot_magic),
) => validate_shelley_tx(shelley_minted_tx, utxos, spp, prot_magic, block_slot),
// TODO: implement the rest of the eras.
_ => Ok(()),
}
Expand Down
17 changes: 16 additions & 1 deletion pallas-applying/src/shelley.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ pub fn validate_shelley_tx(
utxos: &UTxOs,
_prot_pps: &ShelleyProtParams,
_prot_magic: &u32,
block_slot: &u64,
) -> ValidationResult {
let tx_body: &TransactionBody = &mtx.transaction_body;
check_ins_not_empty(tx_body)?;
check_ins_in_utxos(tx_body, utxos)
check_ins_in_utxos(tx_body, utxos)?;
check_ttl(tx_body, block_slot)
}

fn check_ins_not_empty(tx_body: &TransactionBody) -> ValidationResult {
Expand All @@ -31,3 +33,16 @@ fn check_ins_in_utxos(tx_body: &TransactionBody, utxos: &UTxOs) -> ValidationRes
}
Ok(())
}

fn check_ttl(tx_body: &TransactionBody, block_slot: &u64) -> ValidationResult {
match tx_body.ttl {
Some(ttl) => {
if ttl < *block_slot {
Err(ValidationError::TTLExceeded)
} else {
Ok(())
}
}
None => Err(ValidationError::AlonzoCompatibleNotShelley),
}
}
25 changes: 14 additions & 11 deletions pallas-applying/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub enum MultiEraProtParams {
pub struct Environment {
pub prot_params: MultiEraProtParams,
pub prot_magic: u32,
pub block_slot: u64,
}

#[non_exhaustive]
Expand All @@ -39,17 +40,19 @@ pub enum SigningTag {
#[derive(Debug)]
#[non_exhaustive]
pub enum ValidationError {
InputMissingInUTxO,
TxInsEmpty,
TxOutsEmpty,
OutputWithoutLovelace,
UnknownTxSize,
UnableToComputeFees,
FeesBelowMin,
MaxTxSizeExceeded,
UnableToProcessWitnesses,
MissingWitness,
WrongSignature,
InputMissingInUTxO, // >= Byron
TxInsEmpty, // >= Byron
TxOutsEmpty, // >= Byron
OutputWithoutLovelace, // == Byron
UnknownTxSize, // >= Byron
UnableToComputeFees, // >= Byron
FeesBelowMin, // >= Byron
MaxTxSizeExceeded, // >= Byron
UnableToProcessWitnesses, // >= Byron
MissingWitness, // >= Byron
WrongSignature, // >= Byron
TTLExceeded, // >= Shelley
AlonzoCompatibleNotShelley, // == Shelley
}

pub type ValidationResult = Result<(), ValidationError>;
10 changes: 10 additions & 0 deletions pallas-applying/tests/byron.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ mod byron_tests {
max_tx_size: 4096,
}),
prot_magic: 764824073,
block_slot: 6341,
};
match validate(&metx, &utxos, &env) {
Ok(()) => (),
Expand All @@ -91,6 +92,7 @@ mod byron_tests {
max_tx_size: 4096,
}),
prot_magic: 764824073,
block_slot: 3241381,
};
match validate(&metx, &utxos, &env) {
Ok(()) => (),
Expand Down Expand Up @@ -125,6 +127,7 @@ mod byron_tests {
max_tx_size: 4096,
}),
prot_magic: 764824073,
block_slot: 3241381,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "Inputs set should not be empty."),
Expand Down Expand Up @@ -162,6 +165,7 @@ mod byron_tests {
max_tx_size: 4096,
}),
prot_magic: 764824073,
block_slot: 3241381,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "Outputs set should not be empty."),
Expand All @@ -186,6 +190,7 @@ mod byron_tests {
max_tx_size: 4096,
}),
prot_magic: 764824073,
block_slot: 3241381,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "All inputs must be within the UTxO set."),
Expand Down Expand Up @@ -230,6 +235,7 @@ mod byron_tests {
max_tx_size: 4096,
}),
prot_magic: 764824073,
block_slot: 3241381,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "All outputs must contain lovelace."),
Expand Down Expand Up @@ -258,6 +264,7 @@ mod byron_tests {
max_tx_size: 4096,
}),
prot_magic: 764824073,
block_slot: 3241381,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "Fees should not be below minimum."),
Expand Down Expand Up @@ -286,6 +293,7 @@ mod byron_tests {
max_tx_size: 0,
}),
prot_magic: 764824073,
block_slot: 3241381,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "Transaction size cannot exceed protocol limit."),
Expand Down Expand Up @@ -322,6 +330,7 @@ mod byron_tests {
max_tx_size: 4096,
}),
prot_magic: 764824073,
block_slot: 3241381,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "All inputs must have a witness signature."),
Expand Down Expand Up @@ -367,6 +376,7 @@ mod byron_tests {
max_tx_size: 4096,
}),
prot_magic: 764824073,
block_slot: 3241381,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "Witness signature should verify the transaction."),
Expand Down
66 changes: 65 additions & 1 deletion pallas-applying/tests/shelley.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use pallas_primitives::alonzo::{
use pallas_traverse::{Era, MultiEraInput, MultiEraOutput, MultiEraTx};

#[cfg(test)]
mod byron_tests {
mod shelley_tests {
use super::*;

fn cbor_to_bytes(input: &str) -> Vec<u8> {
Expand Down Expand Up @@ -62,6 +62,7 @@ mod byron_tests {
let env: Environment = Environment {
prot_params: MultiEraProtParams::Shelley(ShelleyProtParams),
prot_magic: 764824073,
block_slot: 5281340,
};
let utxos: UTxOs = mk_utxo_for_single_input_tx(
&mtx.transaction_body,
Expand Down Expand Up @@ -100,6 +101,7 @@ mod byron_tests {
let env: Environment = Environment {
prot_params: MultiEraProtParams::Shelley(ShelleyProtParams),
prot_magic: 764824073,
block_slot: 5281340,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "Inputs set should not be empty."),
Expand All @@ -119,6 +121,7 @@ mod byron_tests {
let env: Environment = Environment {
prot_params: MultiEraProtParams::Shelley(ShelleyProtParams),
prot_magic: 764824073,
block_slot: 5281340,
};
let utxos: UTxOs = UTxOs::new();
match validate(&metx, &utxos, &env) {
Expand All @@ -129,6 +132,67 @@ mod byron_tests {
},
}
}

#[test]
// Time-to-live is removed.
fn missing_ttl() {
let cbor_bytes: Vec<u8> = cbor_to_bytes(include_str!("../../test_data/shelley1.tx"));
let mut mtx: MintedTx = minted_tx_from_cbor(&cbor_bytes);
let utxos: UTxOs = mk_utxo_for_single_input_tx(
&mtx.transaction_body,
String::from(include_str!("../../test_data/shelley1.address")),
Value::Coin(2332267427205),
None,
);
let mut tx_body: TransactionBody = (*mtx.transaction_body).clone();
tx_body.ttl = None;
let mut tx_buf: Vec<u8> = Vec::new();
match encode(tx_body, &mut tx_buf) {
Ok(_) => (),
Err(err) => assert!(false, "Unable to encode Tx ({:?}).", err),
};
mtx.transaction_body =
Decode::decode(&mut Decoder::new(&tx_buf.as_slice()), &mut ()).unwrap();
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Shelley);
let env: Environment = Environment {
prot_params: MultiEraProtParams::Shelley(ShelleyProtParams),
prot_magic: 764824073,
block_slot: 5281340,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "TTL must always be present in Shelley transactions."),
Err(err) => match err {
ValidationError::AlonzoCompatibleNotShelley => (),
_ => assert!(false, "Unexpected error ({:?}).", err),
},
}
}

#[test]
// Block slot is after transaction's time-to-live.
fn ttl_exceeded() {
let cbor_bytes: Vec<u8> = cbor_to_bytes(include_str!("../../test_data/shelley1.tx"));
let mtx: MintedTx = minted_tx_from_cbor(&cbor_bytes);
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Shelley);
let env: Environment = Environment {
prot_params: MultiEraProtParams::Shelley(ShelleyProtParams),
prot_magic: 764824073,
block_slot: 9999999,
};
let utxos: UTxOs = mk_utxo_for_single_input_tx(
&mtx.transaction_body,
String::from(include_str!("../../test_data/shelley1.address")),
Value::Coin(2332267427205),
None,
);
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "TTL cannot be exceeded."),
Err(err) => match err {
ValidationError::TTLExceeded => (),
_ => assert!(false, "Unexpected error ({:?}).", err),
},
}
}
}

// Helper functions.
Expand Down

0 comments on commit 801f86c

Please sign in to comment.