Skip to content

Commit 711bd75

Browse files
committed
Ledger/tests: signed command that creates a new account
1 parent 6c5c98f commit 711bd75

File tree

1 file changed

+125
-0
lines changed

1 file changed

+125
-0
lines changed

ledger/tests/test_transaction_logic_first_pass.rs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//!
55
//! Tests the first pass of two-phase transaction application, covering:
66
//! - Successful payment transactions
7+
//! - Payment creating receiver account
78
//! - Insufficient balance errors
89
//! - Invalid nonce errors
910
//! - Nonexistent fee payer errors
@@ -439,3 +440,127 @@ fn test_apply_payment_nonexistent_fee_payer() {
439440
"Alice's account should still not exist after transaction error"
440441
);
441442
}
443+
444+
/// Test payment that creates a new receiver account.
445+
///
446+
/// When the receiver account doesn't exist, a new account is created
447+
/// automatically. The account creation fee is deducted from the payment amount,
448+
/// not from the sender's balance.
449+
///
450+
/// Ledger state: Sender's balance decreased by amount + fee, receiver account
451+
/// created with balance = amount - account_creation_fee.
452+
#[test]
453+
fn test_apply_payment_creates_receiver_account() {
454+
let db = Database::create(15);
455+
let mut ledger = Mask::new_root(db);
456+
457+
let alice_pk = mina_signer::PubKey::from_address(
458+
"B62qmnY6m4c6bdgSPnQGZriSaj9vuSjsfh6qkveGTsFX3yGA5ywRaja",
459+
)
460+
.unwrap()
461+
.into_compressed();
462+
let bob_pk = mina_signer::PubKey::from_address(
463+
"B62qjVQLxt9nYMWGn45mkgwYfcz8e8jvjNCBo11VKJb7vxDNwv5QLPS",
464+
)
465+
.unwrap()
466+
.into_compressed();
467+
468+
// Create only Alice's account
469+
let alice_id = AccountId::new(alice_pk.clone(), Default::default());
470+
let alice_account = Account::create_with(alice_id.clone(), Balance::from_u64(5_000_000_000));
471+
ledger
472+
.get_or_create_account(alice_id.clone(), alice_account)
473+
.unwrap();
474+
475+
let bob_id = AccountId::new(bob_pk.clone(), Default::default());
476+
477+
// Verify Bob's account does not exist before the transaction
478+
assert!(
479+
ledger.location_of_account(&bob_id).is_none(),
480+
"Bob's account should not exist before transaction"
481+
);
482+
483+
// Record initial state
484+
let alice_location = ledger.location_of_account(&alice_id).unwrap();
485+
let alice_before = ledger.get(alice_location).unwrap();
486+
let initial_alice_balance = alice_before.balance;
487+
let initial_alice_nonce = alice_before.nonce;
488+
let initial_alice_receipt_hash = alice_before.receipt_chain_hash;
489+
490+
let amount = 2_000_000_000; // 2 MINA
491+
let fee = 10_000_000; // 0.01 MINA
492+
let nonce = 0;
493+
let payment = create_payment(&alice_pk, &bob_pk, amount, fee, nonce);
494+
495+
let constraint_constants = &test_constraint_constants();
496+
let account_creation_fee = constraint_constants.account_creation_fee; // 1 MINA
497+
498+
let state_view = ProtocolStateView {
499+
snarked_ledger_hash: Fp::zero(),
500+
blockchain_length: Length::from_u32(0),
501+
min_window_density: Length::from_u32(0),
502+
total_currency: Amount::zero(),
503+
global_slot_since_genesis: Slot::from_u32(0),
504+
staking_epoch_data: dummy_epoch_data(),
505+
next_epoch_data: dummy_epoch_data(),
506+
};
507+
let result = apply_transaction_first_pass(
508+
constraint_constants,
509+
Slot::from_u32(0),
510+
&state_view,
511+
&mut ledger,
512+
&Transaction::Command(UserCommand::SignedCommand(Box::new(payment))),
513+
);
514+
515+
assert!(result.is_ok());
516+
517+
// Verify Alice's balance decreased by fee + payment amount
518+
let alice_location = ledger.location_of_account(&alice_id).unwrap();
519+
let alice_after = ledger.get(alice_location).unwrap();
520+
let expected_alice_balance = initial_alice_balance
521+
.sub_amount(Amount::from_u64(fee))
522+
.unwrap()
523+
.sub_amount(Amount::from_u64(amount))
524+
.unwrap();
525+
assert_eq!(
526+
alice_after.balance, expected_alice_balance,
527+
"Alice's balance should decrease by fee + payment amount"
528+
);
529+
530+
// Verify Alice's nonce incremented
531+
assert_eq!(
532+
alice_after.nonce,
533+
initial_alice_nonce.incr(),
534+
"Alice's nonce should be incremented"
535+
);
536+
537+
// Verify Alice's receipt chain hash updated
538+
assert_ne!(
539+
alice_after.receipt_chain_hash, initial_alice_receipt_hash,
540+
"Alice's receipt chain hash should be updated"
541+
);
542+
543+
// Verify Bob's account was created
544+
let bob_location = ledger.location_of_account(&bob_id);
545+
assert!(
546+
bob_location.is_some(),
547+
"Bob's account should now exist after transaction"
548+
);
549+
550+
// Verify Bob's balance is payment amount minus account creation fee
551+
let bob_location = bob_location.unwrap();
552+
let bob_after = ledger.get(bob_location).unwrap();
553+
let expected_bob_balance =
554+
Balance::from_u64(amount - account_creation_fee);
555+
assert_eq!(
556+
bob_after.balance, expected_bob_balance,
557+
"Bob's balance should be payment amount minus account creation fee"
558+
);
559+
560+
// Verify Bob's nonce is 0 (new account)
561+
assert_eq!(
562+
bob_after.nonce,
563+
Nonce::zero(),
564+
"Bob's nonce should be 0 for new account"
565+
);
566+
}

0 commit comments

Comments
 (0)