Skip to content

Commit

Permalink
adding test
Browse files Browse the repository at this point in the history
  • Loading branch information
EdHastingsCasperAssociation committed Apr 30, 2024
1 parent e153367 commit 6dab257
Show file tree
Hide file tree
Showing 12 changed files with 403 additions and 72 deletions.
20 changes: 6 additions & 14 deletions node/src/components/contract_runtime/operations.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::{collections::BTreeMap, convert::TryInto, sync::Arc, time::Instant};

use itertools::Itertools;
use num_rational::Ratio;
use tracing::{debug, error, info, trace, warn};

use casper_execution_engine::engine_state::{ExecutionEngineV1, WasmV1Request, WasmV1Result};
Expand Down Expand Up @@ -191,13 +190,12 @@ pub fn execute_finalized_block(
artifact_builder.with_added_cost(cost);

let is_standard_payment = transaction.is_standard_payment();
let refund_purse_active = !is_standard_payment && !refund_handling.skip_refund();
// set up the refund purse for this transaction, if custom payment && refunds are on
let refund_purse_active = !is_standard_payment; //&& !refund_handling.skip_refund();
if refund_purse_active {
// if refunds are turned on we initialize the refund purse to the initiator's main
// purse before doing any processing. NOTE: when executed, custom payment logic
// has the option to call set_refund_purse on the handle payment contract to set
// up a different refund purse, if desired.
// if custom payment before doing any processing, initialize the initiator's main purse
// to be the refund purse for this transaction.
// NOTE: when executed, custom payment logic has the option to call set_refund_purse
// on the handle payment contract to set up a different refund purse, if desired.
let handle_refund_request = HandleRefundRequest::new(
native_runtime_config.clone(),
state_root_hash,
Expand Down Expand Up @@ -445,18 +443,12 @@ pub fn execute_finalized_block(
// and then point the balance_identifier to the refund purse
// this will result in the downstream no fee handling logic
// placing a hold on the correct purse.
let source = Box::new(balance_identifier.clone());
let target = Box::new(BalanceIdentifier::Refund);
balance_identifier = BalanceIdentifier::Refund;
Some(HandleRefundMode::Refund {
Some(HandleRefundMode::CustomHold {
initiator_addr: Box::new(initiator_addr.clone()),
limit: gas_limit.value(),
gas_price: current_gas_price,
consumed: U512::zero(),
cost,
ratio: Ratio::new_raw(1, 1),
source,
target,
})
} else {
None
Expand Down
6 changes: 3 additions & 3 deletions node/src/reactor/main_reactor/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ impl TestFixture {
if era_duration != TimeDiff::from_millis(0) {
chainspec.core_config.era_duration = era_duration;
}
info!("Foooo {block_gas_limit}");
info!(?block_gas_limit);
chainspec.core_config.minimum_block_time = minimum_block_time;
chainspec.core_config.minimum_era_height = minimum_era_height;
chainspec.core_config.unbonding_delay = unbonding_delay;
Expand Down Expand Up @@ -415,9 +415,9 @@ impl TestFixture {
chainspec.core_config.gas_hold_balance_handling = gas_hold_balance_handling;
}

let limit = chainspec.transaction_config.block_gas_limit;
let applied_block_gas_limit = chainspec.transaction_config.block_gas_limit;

info!("THE LIMIT {limit}");
info!(?applied_block_gas_limit);

let mut fixture = TestFixture {
rng,
Expand Down
146 changes: 144 additions & 2 deletions node/src/reactor/main_reactor/tests/transactions.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::*;
use casper_storage::data_access_layer::ProofHandling;
use casper_storage::data_access_layer::{BalanceIdentifier, ProofHandling};
use casper_types::GasLimited;
use once_cell::sync::Lazy;

Expand Down Expand Up @@ -156,6 +156,39 @@ fn get_balance(
))
}

fn get_payment_purse_balance(
fixture: &mut TestFixture,
block_height: Option<u64>,
) -> BalanceResult {
let (_node_id, runner) = fixture.network.nodes().iter().next().unwrap();
let protocol_version = fixture.chainspec.protocol_version();
let block_height = block_height.unwrap_or(
runner
.main_reactor()
.storage()
.highest_complete_block_height()
.expect("missing highest completed block"),
);
let block_header = runner
.main_reactor()
.storage()
.read_block_header_by_height(block_height, true)
.expect("failure to read block header")
.unwrap();
let state_hash = *block_header.state_root_hash();
runner
.main_reactor()
.contract_runtime()
.data_access_layer()
.balance(BalanceRequest::new(
state_hash,
protocol_version,
BalanceIdentifier::Payment,
BalanceHandling::Available,
ProofHandling::NoProofs,
))
}

fn assert_exec_result_cost(
exec_result: ExecutionResult,
expected_cost: U512,
Expand Down Expand Up @@ -768,6 +801,7 @@ struct SingleTransactionTestCase {
charlie_public_key: PublicKey,
}

#[derive(Debug, PartialEq)]
struct BalanceAmount {
available: U512,
total: U512,
Expand Down Expand Up @@ -981,7 +1015,7 @@ impl SingleTransactionTestCase {
.balance(BalanceRequest::new(
state_hash,
protocol_version,
casper_storage::data_access_layer::BalanceIdentifier::Accumulate,
BalanceIdentifier::Accumulate,
balance_handling,
ProofHandling::NoProofs,
))
Expand Down Expand Up @@ -1591,6 +1625,114 @@ async fn only_refunds_are_burnt_no_fee_custom_payment() {
);
}

#[tokio::test]
async fn no_refund_no_fee_custom_payment() {
const MAX_GAS_PRICE: u8 = MIN_GAS_PRICE;

let config = SingleTransactionTestCase::default_test_config()
.with_pricing_handling(PricingHandling::Classic)
.with_refund_handling(RefundHandling::NoRefund)
.with_fee_handling(FeeHandling::NoFee);

let mut test = SingleTransactionTestCase::new(
ALICE_SECRET_KEY.clone(),
BOB_SECRET_KEY.clone(),
CHARLIE_SECRET_KEY.clone(),
Some(config),
)
.await;

// This contract uses custom payment.
let contract_file = RESOURCES_PATH
.join("..")
.join("target")
.join("wasm32-unknown-unknown")
.join("release")
.join("ee_601_regression.wasm");
let module_bytes = Bytes::from(std::fs::read(contract_file).expect("cannot read module bytes"));

let expected_transaction_gas = 1000u64;
let expected_transaction_cost = expected_transaction_gas * MIN_GAS_PRICE as u64;

let mut txn = Transaction::from(
TransactionV1Builder::new_session(TransactionSessionKind::Standard, module_bytes, "call")
.with_chain_name(CHAIN_NAME)
.with_pricing_mode(PricingMode::Classic {
payment_amount: expected_transaction_gas,
gas_price_tolerance: MIN_GAS_PRICE,
standard_payment: false,
})
.with_initiator_addr(BOB_PUBLIC_KEY.clone())
.build()
.unwrap(),
);
txn.sign(&BOB_SECRET_KEY);

test.fixture
.run_until_consensus_in_era(ERA_ONE, ONE_MIN)
.await;

let (alice_initial_balance, bob_initial_balance, _charlie_initial_balance) =
test.get_balances(None);
let initial_total_supply = test.get_total_supply(None);
let (_txn_hash, block_height, exec_result) = test.send_transaction(txn).await;
// expected to fail due to insufficient funding
assert!(!exec_result_is_success(&exec_result), "should have failed");
match exec_result {
ExecutionResult::V2(exec_result_v2) => {
assert_eq!(exec_result_v2.cost, expected_transaction_cost.into());
}
_ => {
panic!("Unexpected exec result version.")
}
}

let payment_purse_balance = get_payment_purse_balance(&mut test.fixture, Some(block_height));
assert_eq!(
*payment_purse_balance
.total_balance()
.expect("should have total balance"),
U512::zero(),
"payment purse should have a 0 balance"
);

// we're not burning anything, so total supply should be the same
assert_eq!(
test.get_total_supply(Some(block_height)),
initial_total_supply,
"total supply should be the same before and after"
);

// updated balances
let (alice_current_balance, bob_current_balance, _) = test.get_balances(Some(block_height));

// the proposer's balance should be the same because we are in no fee mode
assert_eq!(
alice_initial_balance, alice_current_balance,
"the proposers balance should be unchanged as we are in no fee mode"
);

// the initiator should have a hold equal to the cost
assert_eq!(
bob_current_balance.total.clone(),
bob_initial_balance.total,
"bob's total balance should be unchanged as we are in no fee mode"
);

assert_ne!(
bob_current_balance.available.clone(),
bob_initial_balance.total,
"bob's available balance and total balance should not be the same"
);

let bob_expected_available_balance = bob_initial_balance.total - expected_transaction_cost;
assert_eq!(
bob_current_balance.available.clone(),
bob_expected_available_balance,
"bob's available balance should reflect a hold for the cost"
);
}

async fn transfer_fee_is_burnt_no_refund(txn_pricing_mode: PricingMode) {
let (price_handling, min_gas_price, gas_limit) = match_pricing_mode(&txn_pricing_mode);

Expand Down
4 changes: 2 additions & 2 deletions storage/src/data_access_layer/balance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,14 @@ impl BalanceIdentifier {
BalanceIdentifier::Public(public_key) => {
let account_hash = public_key.to_account_hash();
match tc.get_addressable_entity_by_account_hash(protocol_version, account_hash) {
Ok(entity) => entity.main_purse(),
Ok((_, entity)) => entity.main_purse(),
Err(tce) => return Err(tce),
}
}
BalanceIdentifier::Account(account_hash)
| BalanceIdentifier::PenalizedAccount(account_hash) => {
match tc.get_addressable_entity_by_account_hash(protocol_version, *account_hash) {
Ok(entity) => entity.main_purse(),
Ok((_, entity)) => entity.main_purse(),
Err(tce) => return Err(tce),
}
}
Expand Down
19 changes: 17 additions & 2 deletions storage/src/data_access_layer/handle_refund.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ pub enum HandleRefundMode {
source: Box<BalanceIdentifier>,
target: Box<BalanceIdentifier>,
},
CustomHold {
initiator_addr: Box<InitiatorAddr>,
limit: U512,
cost: U512,
gas_price: u8,
},
RefundAmount {
limit: U512,
cost: U512,
Expand All @@ -48,6 +54,7 @@ impl HandleRefundMode {
HandleRefundMode::ClearRefundPurse
| HandleRefundMode::Burn { .. }
| HandleRefundMode::Refund { .. }
| HandleRefundMode::CustomHold { .. }
| HandleRefundMode::RefundAmount { .. } => Phase::FinalizePayment,
HandleRefundMode::SetRefundPurse { .. } => Phase::Payment,
}
Expand Down Expand Up @@ -107,6 +114,7 @@ impl HandleRefundRequest {
}
}

#[derive(Debug)]
pub enum HandleRefundResult {
/// Invalid state root hash.
RootNotFound,
Expand All @@ -115,6 +123,8 @@ pub enum HandleRefundResult {
effects: Effects,
amount: Option<U512>,
},
/// Invalid phase selected (programmer error).
InvalidPhase,
/// Handle refund request failed.
Failure(TrackingCopyError),
}
Expand All @@ -123,15 +133,19 @@ impl HandleRefundResult {
/// The effects, if any.
pub fn effects(&self) -> Effects {
match self {
HandleRefundResult::RootNotFound | HandleRefundResult::Failure(_) => Effects::new(),
HandleRefundResult::RootNotFound
| HandleRefundResult::InvalidPhase
| HandleRefundResult::Failure(_) => Effects::new(),
HandleRefundResult::Success { effects, .. } => effects.clone(),
}
}

/// The refund amount.
pub fn refund_amount(&self) -> U512 {
match self {
HandleRefundResult::RootNotFound | HandleRefundResult::Failure(_) => U512::zero(),
HandleRefundResult::RootNotFound
| HandleRefundResult::InvalidPhase
| HandleRefundResult::Failure(_) => U512::zero(),
HandleRefundResult::Success {
amount: refund_amount,
..
Expand All @@ -143,6 +157,7 @@ impl HandleRefundResult {
pub fn error_message(&self) -> Option<String> {
match self {
HandleRefundResult::RootNotFound => Some("root not found".to_string()),
HandleRefundResult::InvalidPhase => Some("invalid phase selected".to_string()),
HandleRefundResult::Failure(tce) => Some(format!("{}", tce)),
HandleRefundResult::Success { .. } => None,
}
Expand Down
Loading

0 comments on commit 6dab257

Please sign in to comment.