diff --git a/pallas-applying/src/shelley.rs b/pallas-applying/src/shelley.rs index e38bc425b..73d4b3901 100644 --- a/pallas-applying/src/shelley.rs +++ b/pallas-applying/src/shelley.rs @@ -1,15 +1,23 @@ //! Utilities required for Shelley-era transaction validation. -use crate::types::{ShelleyProtParams, UTxOs, ValidationResult}; +use crate::types::{ShelleyProtParams, UTxOs, ValidationError, ValidationResult}; -use pallas_primitives::alonzo::MintedTx; +use pallas_primitives::alonzo::{MintedTx, TransactionBody}; // TODO: implement each of the validation rules. pub fn validate_shelley_tx( - _mtxp: &MintedTx, + mtx: &MintedTx, _utxos: &UTxOs, _prot_pps: &ShelleyProtParams, _prot_magic: &u32, ) -> ValidationResult { + let tx_body: &TransactionBody = &mtx.transaction_body; + check_ins_not_empty(tx_body) +} + +fn check_ins_not_empty(tx_body: &TransactionBody) -> ValidationResult { + if tx_body.inputs.is_empty() { + return Err(ValidationError::TxInsEmpty); + } Ok(()) } diff --git a/pallas-applying/tests/shelley.rs b/pallas-applying/tests/shelley.rs index 0be1ddde1..5fae102b6 100644 --- a/pallas-applying/tests/shelley.rs +++ b/pallas-applying/tests/shelley.rs @@ -1,7 +1,12 @@ use pallas_applying::{ - types::{Environment, MultiEraProtParams, ShelleyProtParams}, + types::{Environment, MultiEraProtParams, ShelleyProtParams, ValidationError}, validate, UTxOs, }; +use pallas_codec::minicbor::{ + decode::{Decode, Decoder}, + encode, +}; +use pallas_primitives::alonzo::{MintedTx, TransactionBody}; use pallas_traverse::{Era, MultiEraTx}; #[cfg(test)] @@ -12,14 +17,15 @@ mod byron_tests { hex::decode(input).unwrap() } - fn tx_from_cbor<'a>(tx_cbor: &'a Vec) -> MultiEraTx<'a> { - MultiEraTx::decode_for_era(Era::Shelley, &tx_cbor[..]).unwrap() + fn minted_tx_from_cbor<'a>(tx_cbor: &'a Vec) -> MintedTx<'a> { + pallas_codec::minicbor::decode::(&tx_cbor[..]).unwrap() } #[test] fn successful_mainnet_tx() { let cbor_bytes: Vec = cbor_to_bytes(include_str!("../../test_data/shelley1.tx")); - let metx: MultiEraTx = tx_from_cbor(&cbor_bytes); + 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, @@ -30,4 +36,34 @@ mod byron_tests { Err(err) => assert!(false, "Unexpected error ({:?}).", err), } } + + #[test] + // Identical to sucessful_mainnet_tx, except that all inputs are removed. + fn empty_ins() { + let cbor_bytes: Vec = cbor_to_bytes(include_str!("../../test_data/shelley1.tx")); + let mut mtx: MintedTx = minted_tx_from_cbor(&cbor_bytes); + // Clear the set of inputs in the transaction. + let mut tx_body: TransactionBody = (*mtx.transaction_body).clone(); + tx_body.inputs = Vec::new(); + let mut tx_buf: Vec = 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, + }; + let utxos: UTxOs = UTxOs::new(); + match validate(&metx, &utxos, &env) { + Ok(()) => assert!(false, "Inputs set should not be empty."), + Err(err) => match err { + ValidationError::TxInsEmpty => (), + _ => assert!(false, "Unexpected error ({:?}).", err), + }, + } + } }