diff --git a/Makefile b/Makefile index e15f0f483a..e0e8810b70 100644 --- a/Makefile +++ b/Makefile @@ -142,7 +142,7 @@ lint-smart-contracts: .PHONY: audit-rs audit-rs: - $(CARGO) audit --ignore RUSTSEC-2024-0006 --ignore RUSTSEC-2024-0003 --ignore RUSTSEC-2024-0019 + $(CARGO) audit --ignore RUSTSEC-2024-0006 --ignore RUSTSEC-2024-0003 --ignore RUSTSEC-2024-0019 --ignore RUSTSEC-2024-0332 .PHONY: audit-as audit-as: diff --git a/node/src/components/contract_runtime/operations.rs b/node/src/components/contract_runtime/operations.rs index 817d7dd1e9..52e45f6609 100644 --- a/node/src/components/contract_runtime/operations.rs +++ b/node/src/components/contract_runtime/operations.rs @@ -25,7 +25,7 @@ use casper_types::{ execution::{Effects, ExecutionResult, TransformKindV2, TransformV2}, system::mint::BalanceHoldAddrTag, BlockHeader, BlockTime, BlockV2, CLValue, CategorizedTransaction, Chainspec, ChecksumRegistry, - Digest, EraEndV2, EraId, FeeHandling, Gas, GasLimited, HoldsEpoch, Key, ProtocolVersion, + Digest, EraEndV2, EraId, FeeHandling, Gas, GasLimited, HoldsEpoch, Key, Motes, ProtocolVersion, PublicKey, Transaction, TransactionCategory, U512, }; @@ -387,6 +387,9 @@ pub fn execute_finalized_block( // in this mode, consumed gas is accumulated into a single purse for later // distribution let consumed = Gas::new(artifact_builder.consumed()); + let amount = Motes::from_gas(consumed, current_gas_price) + .map(|x| x.value()) + .unwrap_or_else(U512::zero); let handle_payment_request = HandlePaymentRequest::new( native_runtime_config.clone(), state_root_hash, @@ -396,7 +399,7 @@ pub fn execute_finalized_block( gas_limit.value(), current_gas_price, cost, - consumed.value(), + amount, balance_identifier, BalanceIdentifier::Accumulate, holds_epoch, @@ -410,13 +413,14 @@ pub fn execute_finalized_block( .map_err(|_| BlockExecutionError::RootNotFound(state_root_hash))?; } FeeHandling::Burn => { - let consumed = artifact_builder.consumed(); + let consumed = Gas::new(artifact_builder.consumed()); + let amount = Motes::from_gas(consumed, current_gas_price).map(|x| x.value()); let handle_payment_request = HandlePaymentRequest::new( native_runtime_config.clone(), state_root_hash, protocol_version, transaction_hash, - HandlePaymentMode::burn(balance_identifier, Some(consumed)), + HandlePaymentMode::burn(balance_identifier, amount), ); let handle_payment_result = scratch_state.handle_payment(handle_payment_request); state_root_hash = scratch_state diff --git a/node/src/reactor/main_reactor/tests/transactions.rs b/node/src/reactor/main_reactor/tests/transactions.rs index 3e31ea4820..89b9c53cd5 100644 --- a/node/src/reactor/main_reactor/tests/transactions.rs +++ b/node/src/reactor/main_reactor/tests/transactions.rs @@ -5,8 +5,8 @@ use casper_types::execution::ExecutionResultV1; async fn transfer_to_account>( fixture: &mut TestFixture, amount: A, - to: PublicKey, from: &SecretKey, + to: PublicKey, pricing: PricingMode, transfer_id: Option, ) -> (TransactionHash, u64, ExecutionResult) { @@ -202,8 +202,8 @@ async fn transfer_cost_fixed_price_no_fee_no_refund() { let (_txn_hash, block_height, exec_result) = transfer_to_account( &mut fixture, TRANSFER_AMOUNT, - PublicKey::from(&*charlie_secret_key), &alice_secret_key, + PublicKey::from(&*charlie_secret_key), PricingMode::Fixed { gas_price_tolerance: 1, }, @@ -305,8 +305,8 @@ async fn should_accept_transfer_without_id() { let (_, _, result) = transfer_to_account( &mut fixture, transfer_amount, - PublicKey::from(&*charlie_secret_key), &alice_secret_key, + PublicKey::from(&*charlie_secret_key), PricingMode::Fixed { gas_price_tolerance: 1, }, @@ -346,8 +346,8 @@ async fn failed_transfer_cost_fixed_price_no_fee_no_refund() { let (_txn_hash, _block, exec_result) = transfer_to_account( &mut fixture, transfer_amount, - PublicKey::from(&*charlie_secret_key), &alice_secret_key, + PublicKey::from(&*charlie_secret_key), PricingMode::Fixed { gas_price_tolerance: 1, }, @@ -361,8 +361,8 @@ async fn failed_transfer_cost_fixed_price_no_fee_no_refund() { let (_txn_hash, block_height, exec_result) = transfer_to_account( &mut fixture, transfer_amount + 100, - PublicKey::from(&*bob_secret_key), &charlie_secret_key, + PublicKey::from(&*bob_secret_key), PricingMode::Fixed { gas_price_tolerance: 1, }, @@ -433,8 +433,8 @@ async fn transfer_cost_classic_price_no_fee_no_refund() { let (_txn_hash, block_height, exec_result) = transfer_to_account( &mut fixture, TRANSFER_AMOUNT, - PublicKey::from(&*charlie_secret_key), &alice_secret_key, + PublicKey::from(&*charlie_secret_key), PricingMode::Classic { payment_amount: TRANSFER_GAS, gas_price_tolerance: MIN_GAS_PRICE + 1, @@ -541,8 +541,8 @@ async fn transaction_with_low_threshold_should_not_get_included() { let (_, _, _) = transfer_to_account( &mut fixture, TRANSFER_AMOUNT, - PublicKey::from(&*charlie_secret_key), &alice_secret_key, + PublicKey::from(&*charlie_secret_key), PricingMode::Classic { payment_amount: 1000, gas_price_tolerance: MIN_GAS_PRICE - 1, @@ -553,113 +553,129 @@ async fn transaction_with_low_threshold_should_not_get_included() { .await; } -// #[tokio::test] -// async fn transfer_fee_is_burnt_no_refund() { -// const MIN_GAS_PRICE: u8 = 5; -// const MAX_GAS_PRICE: u8 = MIN_GAS_PRICE; -// -// let initial_stakes = InitialStakes::FromVec(vec![u128::MAX, 1]); -// -// let config = ConfigsOverride::default() -// .with_minimum_era_height(5) // make the era longer so that the transaction doesn't land in the switch block. -// .with_pricing_handling(PricingHandling::Fixed) -// .with_refund_handling(RefundHandling::NoRefund) -// .with_fee_handling(FeeHandling::Burn) -// .with_balance_hold_interval(TimeDiff::from_seconds(5)) -// .with_min_gas_price(MIN_GAS_PRICE) -// .with_max_gas_price(MAX_GAS_PRICE); -// -// let mut fixture = TestFixture::new(initial_stakes, Some(config)).await; -// -// let alice_secret_key = Arc::clone(&fixture.node_contexts[0].secret_key); -// let alice_public_key = PublicKey::from(&*alice_secret_key); -// let charlie_secret_key = Arc::new(SecretKey::random(&mut fixture.rng)); -// let charlie_public_key = PublicKey::from(&*charlie_secret_key); -// -// // Wait for all nodes to complete era 0. -// fixture.run_until_consensus_in_era(ERA_ONE, ONE_MIN).await; -// -// let initial_total_supply = get_total_supply(&mut fixture, None); -// -// let alice_initial_balance = *get_balance(&mut fixture, &alice_public_key, None, true) -// .motes() -// .expect("Expected Alice to have a balance."); -// -// let transfer_amount = fixture -// .chainspec -// .transaction_config -// .native_transfer_minimum_motes -// + 100; -// -// let (_txn_hash, block_height, exec_result) = transfer_to_account( -// &mut fixture, -// transfer_amount, -// PublicKey::from(&*charlie_secret_key), -// &alice_secret_key, -// PricingMode::Fixed { -// gas_price_tolerance: MIN_GAS_PRICE, -// }, -// None, -// ) -// .await; -// -// assert!(exec_result_is_success(&exec_result)); // transaction should have succeeded. -// -// let expected_transfer_gas: u64 = fixture -// .chainspec -// .system_costs_config -// .mint_costs() -// .transfer -// .into(); -// let expected_transfer_cost = expected_transfer_gas * MIN_GAS_PRICE as u64; -// assert_exec_result_cost( -// exec_result, -// expected_transfer_cost.into(), -// expected_transfer_gas.into(), -// ); -// -// // The fees should have been burnt. So expect the total supply should have been reduced by the -// // fee that was burnt. -// let total_supply_after_transaction = get_total_supply(&mut fixture, Some(block_height)); -// assert_eq!( -// total_supply_after_transaction, -// initial_total_supply - expected_transfer_cost -// ); -// -// let alice_available_balance = -// get_balance(&mut fixture, &alice_public_key, Some(block_height), false); -// let alice_total_balance = -// get_balance(&mut fixture, &alice_public_key, Some(block_height), true); -// -// let alice_expected_total_balance = -// alice_initial_balance - transfer_amount - expected_transfer_cost; -// let alice_expected_available_balance = alice_expected_total_balance; -// -// let charlie_balance = get_balance(&mut fixture, &charlie_public_key, Some(block_height), false); -// assert_eq!( -// charlie_balance -// .motes() -// .expect("Expected Charlie to have a balance") -// .clone(), -// transfer_amount.into() -// ); -// -// assert_eq!( -// alice_available_balance -// .motes() -// .expect("Expected Alice to have a balance") -// .clone(), -// alice_expected_available_balance -// ); -// -// assert_eq!( -// alice_total_balance -// .motes() -// .expect("Expected Alice to have a balance") -// .clone(), -// alice_expected_total_balance -// ); -// } +#[tokio::test] +async fn transfer_fee_is_burnt_no_refund() { + const MIN_GAS_PRICE: u8 = 5; + const MAX_GAS_PRICE: u8 = MIN_GAS_PRICE; + + let initial_stakes = InitialStakes::FromVec(vec![u128::MAX, 1]); + + // make the era longer so that the transaction doesn't land in the switch block. + let minimum_era_height = 5; + // make the hold interval very short so we can see the behavior. + let balance_hold_interval = TimeDiff::from_seconds(5); + + let config = ConfigsOverride::default() + .with_minimum_era_height(minimum_era_height) + .with_pricing_handling(PricingHandling::Fixed) + .with_refund_handling(RefundHandling::NoRefund) + .with_fee_handling(FeeHandling::Burn) + .with_balance_hold_interval(balance_hold_interval) + .with_min_gas_price(MIN_GAS_PRICE) + .with_max_gas_price(MAX_GAS_PRICE); + + let mut fixture = TestFixture::new(initial_stakes, Some(config)).await; + + let alice_secret_key = Arc::clone(&fixture.node_contexts[0].secret_key); + let alice_public_key = PublicKey::from(&*alice_secret_key); + let charlie_secret_key = Arc::new(SecretKey::random(&mut fixture.rng)); + let charlie_public_key = PublicKey::from(&*charlie_secret_key); + + info!("waiting for all nodes to complete era 0"); + fixture.run_until_consensus_in_era(ERA_ONE, ONE_MIN).await; + + let initial_total_supply = get_total_supply(&mut fixture, None); + + let alice_initial_balance = *get_balance(&mut fixture, &alice_public_key, None, true) + .motes() + .expect("expected alice to have a balance"); + + let transfer_amount = fixture + .chainspec + .transaction_config + .native_transfer_minimum_motes + + 100; + + info!("transferring from alice to charlie"); + let (_txn_hash, block_height, exec_result) = transfer_to_account( + &mut fixture, + transfer_amount, + &alice_secret_key, + PublicKey::from(&*charlie_secret_key), + PricingMode::Fixed { + gas_price_tolerance: MIN_GAS_PRICE, + }, + None, + ) + .await; + assert!(exec_result_is_success(&exec_result), "{:?}", exec_result); + info!("transfer was successful"); + + let expected_transfer_gas: u64 = fixture + .chainspec + .system_costs_config + .mint_costs() + .transfer + .into(); + let expected_transfer_cost = expected_transfer_gas * MIN_GAS_PRICE as u64; + info!("checking expected cost"); + assert_exec_result_cost( + exec_result, + expected_transfer_cost.into(), + expected_transfer_gas.into(), + ); + + // The fees should have been burnt so expect the total supply to have been + // reduced by the fee that was burnt. + info!("checking total supply"); + let total_supply_after_transaction = get_total_supply(&mut fixture, Some(block_height)); + assert_ne!( + total_supply_after_transaction, initial_total_supply, + "total supply should be lowered" + ); + let diff = initial_total_supply - total_supply_after_transaction; + assert_eq!( + diff, + U512::from(expected_transfer_cost), + "total supply should be lowered by expected transfer cost" + ); + + let alice_available_balance = + get_balance(&mut fixture, &alice_public_key, Some(block_height), false); + let alice_total_balance = + get_balance(&mut fixture, &alice_public_key, Some(block_height), true); + let alice_expected_total_balance = + alice_initial_balance - transfer_amount - expected_transfer_cost; + let alice_expected_available_balance = alice_expected_total_balance; + + info!("checking charlie balance"); + let charlie_balance = get_balance(&mut fixture, &charlie_public_key, Some(block_height), false); + assert_eq!( + charlie_balance + .motes() + .expect("Expected Charlie to have a balance") + .clone(), + transfer_amount.into() + ); + + info!("checking alice available balance"); + assert_eq!( + alice_available_balance + .motes() + .expect("Expected Alice to have a balance") + .clone(), + alice_expected_available_balance + ); + + info!("checking alice total balance"); + assert_eq!( + alice_total_balance + .motes() + .expect("Expected Alice to have a balance") + .clone(), + alice_expected_total_balance + ); +} #[tokio::test] async fn fee_is_payed_to_proposer_no_refund() { @@ -705,8 +721,8 @@ async fn fee_is_payed_to_proposer_no_refund() { let (_txn_hash, block_height, exec_result) = transfer_to_account( &mut fixture, transfer_amount, - PublicKey::from(&*charlie_secret_key), &bob_secret_key, + PublicKey::from(&*charlie_secret_key), PricingMode::Fixed { gas_price_tolerance: MIN_GAS_PRICE, },