Skip to content

Commit

Permalink
feat(applying): check fees
Browse files Browse the repository at this point in the history
  • Loading branch information
MaicoLeberle committed Nov 27, 2023
1 parent d7d637b commit a5eff95
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 75 deletions.
2 changes: 1 addition & 1 deletion pallas-applying/src/byron.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ fn check_fees(tx: &Tx, size: &u64, utxos: &UTxOs, prot_pps: &ByronProtParams) ->
outputs_balance += output.amount
}
let total_balance: u64 = inputs_balance - outputs_balance;
let min_fees: u64 = prot_pps.min_fees_const + prot_pps.min_fees_factor * size;
let min_fees: u64 = prot_pps.fee_policy.summand + prot_pps.fee_policy.multiplier * size;
if total_balance < min_fees {
Err(Byron(FeesBelowMin))
} else {
Expand Down
8 changes: 6 additions & 2 deletions pallas-applying/src/shelley.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Utilities required for Shelley-era transaction validation.
use crate::types::{
FeePolicy,
ShelleyMAError::*,
ShelleyProtParams, UTxOs,
ValidationError::{self, *},
Expand Down Expand Up @@ -32,7 +33,7 @@ pub fn validate_shelley_tx(
check_size(size, prot_pps)?;
check_min_lovelace(tx_body, prot_pps)?;
check_preservation_of_value(tx_body, utxos)?;
check_fees(tx_body, prot_pps)?;
check_fees(tx_body, size, &prot_pps.fee_policy)?;
check_network_id(tx_body, network_id)?;
check_witnesses(tx_body, tx_wits)
}
Expand Down Expand Up @@ -133,7 +134,10 @@ fn get_produced(tx_body: &TransactionBody) -> Result<u64, ValidationError> {
Ok(res)
}

fn check_fees(_tx_body: &TransactionBody, _prot_pps: &ShelleyProtParams) -> ValidationResult {
fn check_fees(tx_body: &TransactionBody, size: &u64, fee_policy: &FeePolicy) -> ValidationResult {
if tx_body.fee < fee_policy.summand + fee_policy.multiplier * size {
return Err(Shelley(FeesBelowMin));
}
Ok(())
}

Expand Down
11 changes: 9 additions & 2 deletions pallas-applying/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,23 @@ pub type UTxOs<'b> = HashMap<MultiEraInput<'b>, MultiEraOutput<'b>>;

#[derive(Debug, Clone)]
pub struct ByronProtParams {
pub min_fees_const: u64,
pub min_fees_factor: u64,
pub fee_policy: FeePolicy,
pub max_tx_size: u64,
}

#[derive(Debug, Clone)]
pub struct ShelleyProtParams {
pub fee_policy: FeePolicy,
pub max_tx_size: u64,
pub min_lovelace: u64,
}

#[derive(Debug, Clone)]
pub struct FeePolicy {
pub summand: u64,
pub multiplier: u64,
}

// TODO: add variants for the other eras.
#[derive(Debug)]
#[non_exhaustive]
Expand Down Expand Up @@ -76,6 +82,7 @@ pub enum ShelleyMAError {
ValueNotShelley,
MinLovelaceUnreached,
PreservationOfValue,
FeesBelowMin,
WrongEraOutput,
AddressDecoding,
WrongNetworkID,
Expand Down
115 changes: 69 additions & 46 deletions pallas-applying/tests/byron.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use std::{borrow::Cow, vec::Vec};

use pallas_applying::{
types::{ByronError::*, ByronProtParams, Environment, MultiEraProtParams, ValidationError::*},
types::{
ByronError::*, ByronProtParams, Environment, FeePolicy, MultiEraProtParams,
ValidationError::*,
},
validate, UTxOs,
};
use pallas_codec::{
Expand Down Expand Up @@ -30,14 +33,14 @@ mod byron_tests {
// Careful: this function assumes tx has exactly one input.
fn mk_utxo_for_single_input_tx<'a>(tx: &Tx, address_payload: String, amount: u64) -> UTxOs<'a> {
let mut tx_ins: Vec<TxIn> = tx.inputs.clone().to_vec();
assert_eq!(tx_ins.len(), 1, "Unexpected number of inputs.");
assert_eq!(tx_ins.len(), 1, "Unexpected number of inputs");
let tx_in: TxIn = tx_ins.pop().unwrap();
let input_tx_out_addr: Address = match hex::decode(address_payload) {
Ok(addr_bytes) => Address {
payload: TagWrap(ByteVec::from(addr_bytes)),
crc: 3430631884,
},
_ => panic!("Unable to decode input address."),
_ => panic!("Unable to decode input address"),
};
let tx_out: TxOut = TxOut {
address: input_tx_out_addr,
Expand All @@ -61,8 +64,10 @@ mod byron_tests {
);
let env: Environment = Environment {
prot_params: MultiEraProtParams::Byron(ByronProtParams {
min_fees_const: 155381,
min_fees_factor: 44,
fee_policy: FeePolicy {
summand: 155381,
multiplier: 44,
},
max_tx_size: 4096,
}),
prot_magic: 764824073,
Expand All @@ -71,7 +76,7 @@ mod byron_tests {
};
match validate(&metx, &utxos, &env) {
Ok(()) => (),
Err(err) => panic!("Unexpected error ({:?}).", err),
Err(err) => panic!("Unexpected error ({:?})", err),
}
}

Expand All @@ -88,8 +93,10 @@ mod byron_tests {
);
let env: Environment = Environment {
prot_params: MultiEraProtParams::Byron(ByronProtParams {
min_fees_const: 155381,
min_fees_factor: 44,
fee_policy: FeePolicy {
summand: 155381,
multiplier: 44,
},
max_tx_size: 4096,
}),
prot_magic: 764824073,
Expand All @@ -98,7 +105,7 @@ mod byron_tests {
};
match validate(&metx, &utxos, &env) {
Ok(()) => (),
Err(err) => panic!("Unexpected error ({:?}).", err),
Err(err) => panic!("Unexpected error ({:?})", err),
}
}

Expand All @@ -118,25 +125,27 @@ mod byron_tests {
let mut tx_buf: Vec<u8> = Vec::new();
match encode(tx, &mut tx_buf) {
Ok(_) => (),
Err(err) => panic!("Unable to encode Tx ({:?}).", err),
Err(err) => panic!("Unable to encode Tx ({:?})", err),
};
mtxp.transaction = Decode::decode(&mut Decoder::new(&tx_buf.as_slice()), &mut ()).unwrap();
let metx: MultiEraTx = MultiEraTx::from_byron(&mtxp);
let env: Environment = Environment {
prot_params: MultiEraProtParams::Byron(ByronProtParams {
min_fees_const: 155381,
min_fees_factor: 44,
fee_policy: FeePolicy {
summand: 155381,
multiplier: 44,
},
max_tx_size: 4096,
}),
prot_magic: 764824073,
block_slot: 3241381,
network_id: 1,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "Inputs set should not be empty."),
Ok(()) => assert!(false, "Inputs set should not be empty"),
Err(err) => match err {
Byron(TxInsEmpty) => (),
_ => panic!("Unexpected error ({:?}).", err),
_ => panic!("Unexpected error ({:?})", err),
},
}
}
Expand All @@ -152,7 +161,7 @@ mod byron_tests {
let mut tx_buf: Vec<u8> = Vec::new();
match encode(tx, &mut tx_buf) {
Ok(_) => (),
Err(err) => panic!("Unable to encode Tx ({:?}).", err),
Err(err) => panic!("Unable to encode Tx ({:?})", err),
};
mtxp.transaction = Decode::decode(&mut Decoder::new(&tx_buf.as_slice()), &mut ()).unwrap();
let metx: MultiEraTx = MultiEraTx::from_byron(&mtxp);
Expand All @@ -163,19 +172,21 @@ mod byron_tests {
);
let env: Environment = Environment {
prot_params: MultiEraProtParams::Byron(ByronProtParams {
min_fees_const: 155381,
min_fees_factor: 44,
fee_policy: FeePolicy {
summand: 155381,
multiplier: 44,
},
max_tx_size: 4096,
}),
prot_magic: 764824073,
block_slot: 3241381,
network_id: 1,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "Outputs set should not be empty."),
Ok(()) => assert!(false, "Outputs set should not be empty"),
Err(err) => match err {
Byron(TxOutsEmpty) => (),
_ => panic!("Unexpected error ({:?}).", err),
_ => panic!("Unexpected error ({:?})", err),
},
}
}
Expand All @@ -189,19 +200,21 @@ mod byron_tests {
let utxos: UTxOs = UTxOs::new();
let env: Environment = Environment {
prot_params: MultiEraProtParams::Byron(ByronProtParams {
min_fees_const: 155381,
min_fees_factor: 44,
fee_policy: FeePolicy {
summand: 155381,
multiplier: 44,
},
max_tx_size: 4096,
}),
prot_magic: 764824073,
block_slot: 3241381,
network_id: 1,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "All inputs must be within the UTxO set."),
Ok(()) => assert!(false, "All inputs must be within the UTxO set"),
Err(err) => match err {
Byron(InputNotInUTxO) => (),
_ => panic!("Unexpected error ({:?}).", err),
_ => panic!("Unexpected error ({:?})", err),
},
}
}
Expand All @@ -223,7 +236,7 @@ mod byron_tests {
let mut tx_buf: Vec<u8> = Vec::new();
match encode(tx, &mut tx_buf) {
Ok(_) => (),
Err(err) => panic!("Unable to encode Tx ({:?}).", err),
Err(err) => panic!("Unable to encode Tx ({:?})", err),
};
mtxp.transaction = Decode::decode(&mut Decoder::new(&tx_buf.as_slice()), &mut ()).unwrap();
let metx: MultiEraTx = MultiEraTx::from_byron(&mtxp);
Expand All @@ -234,19 +247,21 @@ mod byron_tests {
);
let env: Environment = Environment {
prot_params: MultiEraProtParams::Byron(ByronProtParams {
min_fees_const: 155381,
min_fees_factor: 44,
fee_policy: FeePolicy {
summand: 155381,
multiplier: 44,
},
max_tx_size: 4096,
}),
prot_magic: 764824073,
block_slot: 3241381,
network_id: 1,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "All outputs must contain lovelace."),
Ok(()) => assert!(false, "All outputs must contain lovelace"),
Err(err) => match err {
Byron(OutputWithoutLovelace) => (),
_ => panic!("Unexpected error ({:?}).", err),
_ => panic!("Unexpected error ({:?})", err),
},
}
}
Expand All @@ -264,19 +279,21 @@ mod byron_tests {
);
let env: Environment = Environment {
prot_params: MultiEraProtParams::Byron(ByronProtParams {
min_fees_const: 1000,
min_fees_factor: 1000,
fee_policy: FeePolicy {
summand: 1000,
multiplier: 1000,
},
max_tx_size: 4096,
}),
prot_magic: 764824073,
block_slot: 3241381,
network_id: 1,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "Fees should not be below minimum."),
Ok(()) => assert!(false, "Fees should not be below minimum"),
Err(err) => match err {
Byron(FeesBelowMin) => (),
_ => panic!("Unexpected error ({:?}).", err),
_ => panic!("Unexpected error ({:?})", err),
},
}
}
Expand All @@ -294,19 +311,21 @@ mod byron_tests {
);
let env: Environment = Environment {
prot_params: MultiEraProtParams::Byron(ByronProtParams {
min_fees_const: 155381,
min_fees_factor: 44,
fee_policy: FeePolicy {
summand: 155381,
multiplier: 44,
},
max_tx_size: 0,
}),
prot_magic: 764824073,
block_slot: 3241381,
network_id: 1,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "Transaction size cannot exceed protocol limit."),
Ok(()) => assert!(false, "Transaction size cannot exceed protocol limit"),
Err(err) => match err {
Byron(MaxTxSizeExceeded) => (),
_ => panic!("Unexpected error ({:?}).", err),
_ => panic!("Unexpected error ({:?})", err),
},
}
}
Expand All @@ -321,7 +340,7 @@ mod byron_tests {
let mut tx_buf: Vec<u8> = Vec::new();
match encode(new_witnesses, &mut tx_buf) {
Ok(_) => (),
Err(err) => panic!("Unable to encode Tx ({:?}).", err),
Err(err) => panic!("Unable to encode Tx ({:?})", err),
};
mtxp.witness = Decode::decode(&mut Decoder::new(&tx_buf.as_slice()), &mut ()).unwrap();
let metx: MultiEraTx = MultiEraTx::from_byron(&mtxp);
Expand All @@ -332,19 +351,21 @@ mod byron_tests {
);
let env: Environment = Environment {
prot_params: MultiEraProtParams::Byron(ByronProtParams {
min_fees_const: 155381,
min_fees_factor: 44,
fee_policy: FeePolicy {
summand: 155381,
multiplier: 44,
},
max_tx_size: 4096,
}),
prot_magic: 764824073,
block_slot: 3241381,
network_id: 1,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "All inputs must have a witness signature."),
Ok(()) => assert!(false, "All inputs must have a witness signature"),
Err(err) => match err {
Byron(MissingWitness) => (),
_ => panic!("Unexpected error ({:?}).", err),
_ => panic!("Unexpected error ({:?})", err),
},
}
}
Expand All @@ -368,7 +389,7 @@ mod byron_tests {

match encode(new_witnesses, &mut tx_buf) {
Ok(_) => (),
Err(err) => panic!("Unable to encode Tx ({:?}).", err),
Err(err) => panic!("Unable to encode Tx ({:?})", err),
};
mtxp.witness = Decode::decode(&mut Decoder::new(&tx_buf.as_slice()), &mut ()).unwrap();
let metx: MultiEraTx = MultiEraTx::from_byron(&mtxp);
Expand All @@ -379,19 +400,21 @@ mod byron_tests {
);
let env: Environment = Environment {
prot_params: MultiEraProtParams::Byron(ByronProtParams {
min_fees_const: 155381,
min_fees_factor: 44,
fee_policy: FeePolicy {
summand: 155381,
multiplier: 44,
},
max_tx_size: 4096,
}),
prot_magic: 764824073,
block_slot: 3241381,
network_id: 1,
};
match validate(&metx, &utxos, &env) {
Ok(()) => assert!(false, "Witness signature should verify the transaction."),
Ok(()) => assert!(false, "Witness signature should verify the transaction"),
Err(err) => match err {
Byron(WrongSignature) => (),
_ => panic!("Unexpected error ({:?}).", err),
_ => panic!("Unexpected error ({:?})", err),
},
}
}
Expand Down
Loading

0 comments on commit a5eff95

Please sign in to comment.