Skip to content

Commit

Permalink
Merge branch 'grarco/fee-unit-tests' (#2914)
Browse files Browse the repository at this point in the history
* origin/grarco/fee-unit-tests:
  Changelog #2914
  Improves unit tests for fee payment
  • Loading branch information
tzemanovic committed Apr 10, 2024
2 parents 2fa343f + ba6f1c3 commit 60892d9
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 7 deletions.
2 changes: 2 additions & 0 deletions .changelog/unreleased/testing/2914-fee-unit-tests.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Improved unit tests for fee payment.
([\#2914](https://github.com/anoma/namada/pull/2914))
113 changes: 106 additions & 7 deletions crates/apps/src/lib/node/ledger/shell/finalize_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2723,8 +2723,8 @@ mod test_finalize_block {

#[test]
/// Test that the hash of the wrapper transaction is committed to storage
/// even if the wrapper tx fails. The inner transaction hash must instead be
/// removed
/// even if the wrapper tx fails. The inner transaction hash must not be
/// inserted
fn test_commits_hash_if_wrapper_failure() {
let (mut shell, _, _, _) = setup();
let keypair = gen_keypair();
Expand Down Expand Up @@ -2800,19 +2800,110 @@ mod test_finalize_block {
);
}

// Test that the fees are paid even if the inner transaction fails and its
// modifications are dropped
#[test]
fn test_fee_payment_if_invalid_inner_tx() {
let (mut shell, _, _, _) = setup();
let keypair = crate::wallet::defaults::albert_keypair();

let mut wrapper =
Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount_per_gas_unit: DenominatedAmount::native(100.into()),
token: shell.state.in_mem().native_token.clone(),
},
keypair.ref_to(),
Epoch(0),
WRAPPER_GAS_LIMIT.into(),
None,
))));
wrapper.header.chain_id = shell.chain_id.clone();
// Set no code to let the inner tx fail
wrapper.add_section(Section::Signature(Signature::new(
wrapper.sechashes(),
[(0, keypair.clone())].into_iter().collect(),
None,
)));

let fee_amount =
wrapper.header().wrapper().unwrap().get_tx_fee().unwrap();
let fee_amount = namada::token::denom_to_amount(
fee_amount,
&wrapper.header().wrapper().unwrap().fee.token,
&shell.state,
)
.unwrap();
let signer_balance = namada::token::read_balance(
&shell.state,
&shell.state.in_mem().native_token,
&wrapper.header().wrapper().unwrap().fee_payer(),
)
.unwrap();

let processed_tx = ProcessedTx {
tx: wrapper.to_bytes().into(),
result: TxResult {
code: ResultCode::Ok.into(),
info: "".into(),
},
};

let event = &shell
.finalize_block(FinalizeBlock {
txs: vec![processed_tx],
..Default::default()
})
.expect("Test failed")[0];

// Check balance of fee payer
assert_eq!(event.event_type.to_string(), String::from("applied"));
let code = event.attributes.get("code").expect("Test failed").as_str();
assert_eq!(code, String::from(ResultCode::WasmRuntimeError).as_str());

let new_signer_balance = namada::token::read_balance(
&shell.state,
&shell.state.in_mem().native_token,
&wrapper.header().wrapper().unwrap().fee_payer(),
)
.unwrap();
assert_eq!(
new_signer_balance,
signer_balance.checked_sub(fee_amount).unwrap()
)
}

// Test that if the fee payer doesn't have enough funds for fee payment the
// ledger drains their balance. Note that because of the checks in process
// proposal this scenario should never happen
#[test]
fn test_fee_payment_if_insufficient_balance() {
let (mut shell, _, _, _) = setup();
let keypair = gen_keypair();
let native_token = shell.state.in_mem().native_token.clone();

// Credit some tokens for fee payment
let initial_balance = token::Amount::native_whole(1);
namada::token::credit_tokens(
&mut shell.state,
&native_token,
&Address::from(&keypair.to_public()),
initial_balance,
)
.unwrap();
let balance_key = token::storage_key::balance_key(
&native_token,
&Address::from(&keypair.to_public()),
);
let balance: Amount =
shell.state.read(&balance_key).unwrap().unwrap_or_default();
assert_eq!(balance, initial_balance);

let mut wrapper =
Tx::from_type(TxType::Wrapper(Box::new(WrapperTx::new(
Fee {
amount_per_gas_unit: DenominatedAmount::native(100.into()),
token: shell.state.in_mem().native_token.clone(),
token: native_token.clone(),
},
keypair.ref_to(),
Epoch(0),
Expand All @@ -2830,6 +2921,18 @@ mod test_finalize_block {
None,
)));

// Check that the fees are higher than the initial balance of the fee
// payer
let fee_amount =
wrapper.header().wrapper().unwrap().get_tx_fee().unwrap();
let fee_amount = namada::token::denom_to_amount(
fee_amount,
&wrapper.header().wrapper().unwrap().fee.token,
&shell.state,
)
.unwrap();
assert!(fee_amount > initial_balance);

let processed_tx = ProcessedTx {
tx: wrapper.to_bytes().into(),
result: TxResult {
Expand All @@ -2849,10 +2952,6 @@ mod test_finalize_block {
assert_eq!(event.event_type.to_string(), String::from("applied"));
let code = event.attributes.get("code").expect("Test failed").as_str();
assert_eq!(code, String::from(ResultCode::InvalidTx).as_str());
let balance_key = token::storage_key::balance_key(
&shell.state.in_mem().native_token,
&Address::from(&keypair.to_public()),
);
let balance: Amount =
shell.state.read(&balance_key).unwrap().unwrap_or_default();

Expand Down

0 comments on commit 60892d9

Please sign in to comment.