Skip to content

Commit

Permalink
feat(applying): check tx size
Browse files Browse the repository at this point in the history
  • Loading branch information
MaicoLeberle committed Jan 3, 2024
1 parent 31b0eed commit 9a60c46
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 27 deletions.
21 changes: 8 additions & 13 deletions pallas-applying/src/alonzo.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
//! Utilities required for Shelley-era transaction validation.
use crate::utils::{
add_minted_value, add_values, empty_value, get_lovelace_from_alonzo_value,
get_network_id_value, values_are_equal,
add_minted_value, add_values, empty_value, get_alonzo_comp_tx_size,
get_lovelace_from_alonzo_value, get_network_id_value, values_are_equal,
AlonzoError::*,
AlonzoProtParams, FeePolicy, UTxOs,
ValidationError::{self, *},
ValidationResult,
};
use pallas_addresses::{Address, ShelleyAddress, ShelleyPaymentPart};
use pallas_codec::{minicbor::encode, utils::KeepRaw};
use pallas_codec::utils::KeepRaw;
use pallas_primitives::{
alonzo::{
MintedTx, MintedWitnessSet, NativeScript, PlutusData, PlutusScript, Redeemer,
Expand All @@ -27,7 +27,7 @@ pub fn validate_alonzo_tx(
network_id: &u8,
) -> ValidationResult {
let tx_body: &TransactionBody = &mtx.transaction_body;
let size: &u64 = &get_tx_size(tx_body)?;
let size: &u64 = &get_alonzo_comp_tx_size(tx_body).ok_or(Alonzo(UnknownTxSize))?;
check_ins_not_empty(tx_body)?;
check_ins_and_collateral_in_utxos(tx_body, utxos)?;
check_tx_validity_interval(tx_body, mtx, block_slot)?;
Expand All @@ -45,14 +45,6 @@ pub fn validate_alonzo_tx(
check_minting(tx_body, mtx)
}

fn get_tx_size(tx_body: &TransactionBody) -> Result<u64, ValidationError> {
let mut buff: Vec<u8> = Vec::new();
match encode(tx_body, &mut buff) {
Ok(()) => Ok(buff.len() as u64),
Err(_) => Err(Alonzo(UnknownTxSize)),
}
}

// The set of transaction inputs is not empty.
fn check_ins_not_empty(tx_body: &TransactionBody) -> ValidationResult {
if tx_body.inputs.is_empty() {
Expand Down Expand Up @@ -370,7 +362,10 @@ fn check_tx_network_id(tx_body: &TransactionBody, network_id: &u8) -> Validation
}

// The transaction size does not exceed the protocol limit.
fn check_tx_size(_size: &u64, _prot_pps: &AlonzoProtParams) -> ValidationResult {
fn check_tx_size(size: &u64, prot_pps: &AlonzoProtParams) -> ValidationResult {
if *size > prot_pps.max_tx_size {
return Err(Alonzo(MaxTxSizeExceeded));
}
Ok(())
}

Expand Down
17 changes: 5 additions & 12 deletions pallas-applying/src/shelley_ma.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//! Utilities required for ShelleyMA-era transaction validation.
use crate::utils::{
add_minted_value, add_values, empty_value, values_are_equal, FeePolicy,
add_minted_value, add_values, empty_value, get_alonzo_comp_tx_size, values_are_equal,
FeePolicy,
ShelleyMAError::*,
ShelleyProtParams, UTxOs,
ValidationError::{self, *},
Expand Down Expand Up @@ -32,11 +33,11 @@ pub fn validate_shelley_ma_tx(
era: &Era,
) -> ValidationResult {
let tx_body: &TransactionBody = &mtx.transaction_body;
let size: &u64 = &get_tx_size(tx_body)?;
let size: &u64 = &get_alonzo_comp_tx_size(tx_body).ok_or(ShelleyMA(UnknownTxSize))?;
check_ins_not_empty(tx_body)?;
check_ins_in_utxos(tx_body, utxos)?;
check_ttl(tx_body, block_slot)?;
check_size(size, prot_pps)?;
check_tx_size(size, prot_pps)?;
check_min_lovelace(tx_body, prot_pps, era)?;
check_preservation_of_value(tx_body, utxos, era)?;
check_fees(tx_body, size, prot_pps)?;
Expand All @@ -46,14 +47,6 @@ pub fn validate_shelley_ma_tx(
check_minting(tx_body, mtx)
}

fn get_tx_size(tx_body: &TransactionBody) -> Result<u64, ValidationError> {
let mut buff: Vec<u8> = Vec::new();
match encode(tx_body, &mut buff) {
Ok(()) => Ok(buff.len() as u64),
Err(_) => Err(ShelleyMA(UnknownTxSize)),
}
}

fn extract_auxiliary_data<'a>(mtx: &'a MintedTx) -> Option<&'a [u8]> {
Option::<KeepRaw<AuxiliaryData>>::from((mtx.auxiliary_data).clone())
.as_ref()
Expand Down Expand Up @@ -89,7 +82,7 @@ fn check_ttl(tx_body: &TransactionBody, block_slot: &u64) -> ValidationResult {
}
}

fn check_size(size: &u64, prot_pps: &ShelleyProtParams) -> ValidationResult {
fn check_tx_size(size: &u64, prot_pps: &ShelleyProtParams) -> ValidationResult {
if *size > prot_pps.max_tx_size {
return Err(ShelleyMA(MaxTxSizeExceeded));
}
Expand Down
14 changes: 12 additions & 2 deletions pallas-applying/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,24 @@ pub mod environment;
pub mod validation;

pub use environment::*;
use pallas_codec::utils::KeyValuePairs;
use pallas_primitives::alonzo::{AssetName, Coin, Multiasset, NetworkId, PolicyId, Value};
use pallas_codec::{minicbor::encode, utils::KeyValuePairs};
use pallas_primitives::alonzo::{
AssetName, Coin, Multiasset, NetworkId, PolicyId, TransactionBody, Value,
};
use pallas_traverse::{MultiEraInput, MultiEraOutput};
use std::collections::HashMap;
pub use validation::*;

pub type UTxOs<'b> = HashMap<MultiEraInput<'b>, MultiEraOutput<'b>>;

pub fn get_alonzo_comp_tx_size(tx_body: &TransactionBody) -> Option<u64> {
let mut buff: Vec<u8> = Vec::new();
match encode(tx_body, &mut buff) {
Ok(()) => Some(buff.len() as u64),
Err(_) => None,
}
}

pub fn empty_value() -> Value {
Value::Multiasset(0, Multiasset::<Coin>::from(Vec::new()))
}
Expand Down
1 change: 1 addition & 0 deletions pallas-applying/src/utils/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ pub enum AlonzoError {
TxWrongNetworkID,
RedeemerMissing,
TxExUnitsExceeded,
MaxTxSizeExceeded,
}

pub type ValidationResult = Result<(), ValidationError>;
49 changes: 49 additions & 0 deletions pallas-applying/tests/alonzo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1331,4 +1331,53 @@ mod alonzo_tests {
},
}
}

#[test]
// Same as successful_mainnet_tx, except that the Environment with which
// validation is called demands the transaction to be smaller than it
// actually is.
fn max_tx_size_exceeded() {
let cbor_bytes: Vec<u8> = cbor_to_bytes(include_str!("../../test_data/alonzo1.tx"));
let mtx: MintedTx = minted_tx_from_cbor(&cbor_bytes);
let metx: MultiEraTx = MultiEraTx::from_alonzo_compatible(&mtx, Era::Alonzo);
let utxos: UTxOs = mk_utxo_for_alonzo_compatible_tx(
&mtx.transaction_body,
&[(
String::from(include_str!("../../test_data/alonzo1.address")),
Value::Coin(1549646822),
None,
)],
);
let env: Environment = Environment {
prot_params: MultiEraProtParams::Alonzo(AlonzoProtParams {
fee_policy: FeePolicy {
summand: 155381,
multiplier: 44,
},
max_tx_size: 158, // 1 byte less than the size of the transaction.
languages: vec![Language::PlutusV1, Language::PlutusV2],
max_block_ex_mem: 50000000,
max_block_ex_steps: 40000000000,
max_tx_ex_mem: 10000000,
max_tx_ex_steps: 10000000000,
max_val_size: 5000,
collateral_percent: 150,
max_collateral_inputs: 3,
coints_per_utxo_word: 34482,
}),
prot_magic: 764824073,
block_slot: 44237276,
network_id: 1,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(
false,
"Transaction size should not exceed the maximum allowed by the protocol parameter"
),
Err(err) => match err {
Alonzo(MaxTxSizeExceeded) => (),
_ => assert!(false, "Unexpected error ({:?})", err),
},
}
}
}

0 comments on commit 9a60c46

Please sign in to comment.