Skip to content

Commit

Permalink
feat(applying): check min lovelace in outputs
Browse files Browse the repository at this point in the history
  • Loading branch information
MaicoLeberle committed Nov 23, 2023
1 parent 2935d31 commit 8a11369
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 17 deletions.
19 changes: 14 additions & 5 deletions pallas-applying/src/shelley.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use crate::types::{
};
use pallas_addresses::{Address, ShelleyAddress};
use pallas_codec::minicbor::encode;
use pallas_primitives::alonzo::{MintedTx, MintedWitnessSet, TransactionBody};
use pallas_primitives::alonzo::{
MintedTx, MintedWitnessSet, TransactionBody, TransactionOutput, Value,
};
use pallas_traverse::MultiEraInput;

// TODO: implement each of the validation rules.
Expand Down Expand Up @@ -78,10 +80,17 @@ fn check_size(size: &u64, prot_pps: &ShelleyProtParams) -> ValidationResult {
Ok(())
}

fn check_min_lovelace(
_tx_body: &TransactionBody,
_prot_pps: &ShelleyProtParams,
) -> ValidationResult {
fn check_min_lovelace(tx_body: &TransactionBody, prot_pps: &ShelleyProtParams) -> ValidationResult {
for TransactionOutput { amount, .. } in &tx_body.outputs {
match amount {
Value::Coin(lovelace) => {
if *lovelace < prot_pps.min_lovelace {
return Err(Shelley(MinLovelaceUnreached));
}
}
_ => return Err(Shelley(ValueNotShelley)),
}
}
Ok(())
}

Expand Down
3 changes: 3 additions & 0 deletions pallas-applying/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub struct ByronProtParams {
#[derive(Debug, Clone)]
pub struct ShelleyProtParams {
pub max_tx_size: u64,
pub min_lovelace: u64,
}

// TODO: add variants for the other eras.
Expand Down Expand Up @@ -72,6 +73,8 @@ pub enum ShelleyMAError {
AlonzoCompNotShelley,
UnknownTxSize,
MaxTxSizeExceeded,
ValueNotShelley,
MinLovelaceUnreached,
WrongEraOutput,
AddressDecoding,
WrongNetworkID,
Expand Down
75 changes: 63 additions & 12 deletions pallas-applying/tests/shelley.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,10 @@ mod shelley_tests {
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 { max_tx_size: 4096 }),
prot_params: MultiEraProtParams::Shelley(ShelleyProtParams {
max_tx_size: 4096,
min_lovelace: 1000000,
}),
prot_magic: 764824073,
block_slot: 5281340,
network_id: 1,
Expand All @@ -81,7 +84,7 @@ mod shelley_tests {
}

#[test]
// Identical to sucessful_mainnet_tx, except that all inputs are removed.
// All inputs are removed.
fn empty_ins() {
let cbor_bytes: Vec<u8> = cbor_to_bytes(include_str!("../../test_data/shelley1.tx"));
let mut mtx: MintedTx = minted_tx_from_cbor(&cbor_bytes);
Expand All @@ -103,7 +106,10 @@ mod shelley_tests {
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 { max_tx_size: 4096 }),
prot_params: MultiEraProtParams::Shelley(ShelleyProtParams {
max_tx_size: 4096,
min_lovelace: 1000000,
}),
prot_magic: 764824073,
block_slot: 5281340,
network_id: 1,
Expand All @@ -118,13 +124,16 @@ mod shelley_tests {
}

#[test]
// The transaction is valid, but the UTxO set is empty.
// The UTxO set is empty.
fn unfound_utxo() {
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 { max_tx_size: 4096 }),
prot_params: MultiEraProtParams::Shelley(ShelleyProtParams {
max_tx_size: 4096,
min_lovelace: 1000000,
}),
prot_magic: 764824073,
block_slot: 5281340,
network_id: 1,
Expand All @@ -140,7 +149,7 @@ mod shelley_tests {
}

#[test]
// Time-to-live is removed.
// Time-to-live is missing.
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);
Expand All @@ -161,7 +170,10 @@ mod shelley_tests {
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 { max_tx_size: 4096 }),
prot_params: MultiEraProtParams::Shelley(ShelleyProtParams {
max_tx_size: 4096,
min_lovelace: 1000000,
}),
prot_magic: 764824073,
block_slot: 5281340,
network_id: 1,
Expand All @@ -176,13 +188,16 @@ mod shelley_tests {
}

#[test]
// Block slot is after transaction's time-to-live.
// Transaction's time-to-live is before block slot.
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 { max_tx_size: 4096 }),
prot_params: MultiEraProtParams::Shelley(ShelleyProtParams {
max_tx_size: 4096,
min_lovelace: 1000000,
}),
prot_magic: 764824073,
block_slot: 9999999,
network_id: 1,
Expand All @@ -203,13 +218,16 @@ mod shelley_tests {
}

#[test]
// Max tx size is set to 0, and so any transaction exceeds it.
// Transaction size exceeds max limit (namely, 0).
fn max_tx_size_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 { max_tx_size: 0 }),
prot_params: MultiEraProtParams::Shelley(ShelleyProtParams {
max_tx_size: 0,
min_lovelace: 1000000,
}),
prot_magic: 764824073,
block_slot: 5281340,
network_id: 1,
Expand All @@ -229,6 +247,36 @@ mod shelley_tests {
}
}

#[test]
// Min lovelace per UTxO is too high.
fn output_below_min_lovelace() {
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 {
max_tx_size: 4096,
min_lovelace: 1000000000000,
}),
prot_magic: 764824073,
block_slot: 5281340,
network_id: 1,
};
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, "Output amount must be above min lovelace value."),
Err(err) => match err {
Shelley(MinLovelaceUnreached) => (),
_ => assert!(false, "Unexpected error ({:?}).", err),
},
}
}

#[test]
// One of the output's address network ID is changed from the mainnet value to the testnet one.
fn wrong_network_id() {
Expand Down Expand Up @@ -268,7 +316,10 @@ mod shelley_tests {
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 { max_tx_size: 4096 }),
prot_params: MultiEraProtParams::Shelley(ShelleyProtParams {
max_tx_size: 4096,
min_lovelace: 1000000,
}),
prot_magic: 764824073,
block_slot: 5281340,
network_id: 1,
Expand Down

0 comments on commit 8a11369

Please sign in to comment.