feat(applying): validate all inputs in UTxO set (#324)

This commit is contained in:
Maico Leberle 2023-11-07 18:29:23 -03:00 committed by GitHub
parent eb4f39d78c
commit ac4aef4eaa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 45 additions and 3 deletions

View file

@ -1,18 +1,19 @@
//! Utilities required for Byron-era transaction validation. //! Utilities required for Byron-era transaction validation.
use crate::types::{ByronProtParams, UTxOs, ValidationError, ValidationResult}; use crate::types::{ByronProtParams, MultiEraInput, UTxOs, ValidationError, ValidationResult};
use pallas_primitives::byron::{MintedTxPayload, Tx}; use pallas_primitives::byron::{MintedTxPayload, Tx};
// TODO: implement missing validation rules. // TODO: implement missing validation rules.
pub fn validate_byron_tx( pub fn validate_byron_tx(
mtxp: &MintedTxPayload, mtxp: &MintedTxPayload,
_utxos: &UTxOs, utxos: &UTxOs,
_prot_pps: &ByronProtParams, _prot_pps: &ByronProtParams,
) -> ValidationResult { ) -> ValidationResult {
let tx: &Tx = &mtxp.transaction; let tx: &Tx = &mtxp.transaction;
check_ins_not_empty(tx)?; check_ins_not_empty(tx)?;
check_outs_not_empty(tx) check_outs_not_empty(tx)?;
check_ins_in_utxos(tx, utxos)
} }
fn check_ins_not_empty(tx: &Tx) -> ValidationResult { fn check_ins_not_empty(tx: &Tx) -> ValidationResult {
@ -28,3 +29,12 @@ fn check_outs_not_empty(tx: &Tx) -> ValidationResult {
} }
Ok(()) Ok(())
} }
fn check_ins_in_utxos(tx: &Tx, utxos: &UTxOs) -> ValidationResult {
for input in tx.inputs.iter() {
if !(utxos.contains_key(&MultiEraInput::from_byron(input))) {
return Err(ValidationError::InputMissingInUTxO);
}
}
Ok(())
}

View file

@ -21,6 +21,7 @@ pub enum MultiEraProtParams<'b> {
#[derive(Debug)] #[derive(Debug)]
#[non_exhaustive] #[non_exhaustive]
pub enum ValidationError { pub enum ValidationError {
InputMissingInUTxO,
TxInsEmpty, TxInsEmpty,
TxOutsEmpty, TxOutsEmpty,
} }

View file

@ -117,6 +117,37 @@ mod byron_tests {
}, },
} }
} }
#[test]
// The UTxO set does not contain an entry for the single input to this transaction. This
// represents the situation where a transaction tries to spend a non-existent UTxO (e.g., one
// which has already been spent).
fn unfound_utxo() {
let protocol_params: ByronProtParams = ByronProtParams;
let mut tx_ins: ByronTxIns = empty_tx_ins();
let tx_in: ByronTxIn = new_tx_in(rand_tx_id(), 3);
add_byron_tx_in(&mut tx_ins, &tx_in);
let mut tx_outs: ByronTxOuts = new_tx_outs();
let tx_out_addr: Address = new_addr(rand_addr_payload(), 0);
let tx_out: ByronTxOut = new_tx_out(tx_out_addr, 99091);
add_tx_out(&mut tx_outs, &tx_out);
// Note: utxos is empty, hence the only input to this transaction will not be found, for
// which an error should be raised.
let utxos: UTxOs = new_utxos();
let validation_result = mk_byron_tx_and_validate(
&new_tx(tx_ins, tx_outs, empty_attributes()),
&empty_witnesses(),
&utxos,
&protocol_params,
);
match validation_result {
Ok(()) => assert!(false, "All inputs must be within the UTxO set."),
Err(err) => match err {
ValidationError::InputMissingInUTxO => (),
_ => assert!(false, "Unexpected error ({:?}).", err),
},
}
}
} }
// Types aliases. // Types aliases.