Skip to content

Commit c77b395

Browse files
authored
ping-pong-test (#616)
1 parent 638b488 commit c77b395

File tree

1 file changed

+158
-0
lines changed
  • crates/bcr-ebill-api/src/service/bill_service

1 file changed

+158
-0
lines changed

crates/bcr-ebill-api/src/service/bill_service/mod.rs

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3322,6 +3322,164 @@ pub mod tests {
33223322
assert!(res.unwrap().blocks()[1].op_code == BillOpCode::Endorse);
33233323
}
33243324

3325+
#[tokio::test]
3326+
async fn endorse_bitcredit_bill_multiple_back_and_forth() {
3327+
let identity = get_baseline_identity();
3328+
let mut bill = get_baseline_bill(&bill_id_test());
3329+
bill.payee = BillParticipant::Ident(bill_identified_participant_only_node_id(
3330+
identity.identity.node_id.clone(),
3331+
));
3332+
3333+
let party2_keys = BcrKeys::new();
3334+
let party2_node_id = NodeId::new(party2_keys.pub_key(), bitcoin::Network::Testnet);
3335+
let party2_participant = bill_identified_participant_only_node_id(party2_node_id.clone());
3336+
3337+
let mut current_chain = get_genesis_chain(Some(bill.clone()));
3338+
let mut current_timestamp = 1731593928u64;
3339+
3340+
for i in 0..10 {
3341+
let is_even = i % 2 == 0;
3342+
3343+
let mut ctx = get_ctx();
3344+
ctx.bill_store
3345+
.expect_save_bill_to_cache()
3346+
.returning(|_, _, _| Ok(()))
3347+
.times(1);
3348+
ctx.bill_store.expect_exists().returning(|_| Ok(true));
3349+
3350+
let chain_for_ctx = current_chain.clone();
3351+
ctx.bill_blockchain_store
3352+
.expect_get_chain()
3353+
.returning(move |_| Ok(chain_for_ctx.clone()));
3354+
3355+
ctx.notification_service
3356+
.expect_send_bill_is_endorsed_event()
3357+
.returning(|_| Ok(()));
3358+
3359+
expect_populates_identity_block(&mut ctx);
3360+
3361+
let service = get_service(ctx);
3362+
3363+
// Determine endorser and endorsee based on iteration
3364+
let (endorser_participant, endorser_keys, endorsee_participant) = if is_even {
3365+
// Even iterations: Party1 endorses to Party2
3366+
(
3367+
BillParticipant::Ident(
3368+
BillIdentParticipant::new(identity.identity.clone()).unwrap(),
3369+
),
3370+
&identity.key_pair,
3371+
BillParticipant::Ident(party2_participant.clone()),
3372+
)
3373+
} else {
3374+
// Odd iterations: Party2 endorses to Party1
3375+
(
3376+
BillParticipant::Ident(party2_participant.clone()),
3377+
&party2_keys,
3378+
BillParticipant::Ident(
3379+
BillIdentParticipant::new(identity.identity.clone()).unwrap(),
3380+
),
3381+
)
3382+
};
3383+
3384+
// Execute the endorsement
3385+
let result = service
3386+
.execute_bill_action(
3387+
&bill_id_test(),
3388+
BillAction::Endorse(endorsee_participant),
3389+
&endorser_participant,
3390+
endorser_keys,
3391+
current_timestamp,
3392+
)
3393+
.await;
3394+
3395+
assert!(result.is_ok(), "Endorsement {} failed", i + 1);
3396+
current_chain = result.unwrap();
3397+
3398+
// Verify the chain grows by one block each time
3399+
// The chain should have 1 genesis block plus (i+1) endorsement blocks after each iteration.
3400+
assert_eq!(current_chain.blocks().len(), 1 + (i + 1)); // Genesis + (i+1) endorsements
3401+
assert_eq!(
3402+
current_chain.blocks().last().unwrap().op_code,
3403+
BillOpCode::Endorse
3404+
);
3405+
3406+
// Verify timestamp ordering: the new block's timestamp should be >= previous block's timestamp
3407+
let blocks = current_chain.blocks();
3408+
let new_block_index = blocks.len() - 1;
3409+
if new_block_index > 0 {
3410+
let prev_timestamp = blocks[new_block_index - 1].timestamp;
3411+
let curr_timestamp = blocks[new_block_index].timestamp;
3412+
assert!(
3413+
curr_timestamp >= prev_timestamp,
3414+
"Block {} timestamp ({}) is before previous block {} timestamp ({})",
3415+
new_block_index,
3416+
curr_timestamp,
3417+
new_block_index - 1,
3418+
prev_timestamp
3419+
);
3420+
}
3421+
3422+
current_timestamp += 1;
3423+
}
3424+
3425+
// Create a final context to verify the end state
3426+
let mut final_ctx = get_ctx();
3427+
final_ctx.bill_store.expect_exists().returning(|_| Ok(true));
3428+
3429+
let final_chain = current_chain.clone();
3430+
final_ctx
3431+
.bill_blockchain_store
3432+
.expect_get_chain()
3433+
.returning(move |_| Ok(final_chain.clone()));
3434+
3435+
final_ctx
3436+
.notification_service
3437+
.expect_get_active_bill_notification()
3438+
.returning(|_| None);
3439+
3440+
let final_service = get_service(final_ctx);
3441+
3442+
// After back-and-forth endorsements, the bill should be back with Party1
3443+
// (start with Party1 and do an even number of transfers)
3444+
let bill_detail = final_service
3445+
.get_detail(
3446+
&bill_id_test(),
3447+
&identity.identity,
3448+
&identity.identity.node_id,
3449+
current_timestamp,
3450+
)
3451+
.await;
3452+
assert!(bill_detail.is_ok());
3453+
3454+
let bill_result = bill_detail.unwrap();
3455+
assert_eq!(
3456+
bill_result
3457+
.participants
3458+
.endorsee
3459+
.as_ref()
3460+
.unwrap()
3461+
.node_id(),
3462+
identity.identity.node_id,
3463+
);
3464+
3465+
// Verify the endorsement chain
3466+
let endorsements = final_service
3467+
.get_endorsements(&bill_id_test(), &identity.identity.node_id)
3468+
.await;
3469+
assert!(endorsements.is_ok());
3470+
3471+
// Should have 10 endorsements total
3472+
assert_eq!(endorsements.as_ref().unwrap().len(), 10);
3473+
3474+
// The most recent endorsement should be back to party1 (identity)
3475+
assert_eq!(
3476+
endorsements.as_ref().unwrap()[0]
3477+
.pay_to_the_order_of
3478+
.node_id,
3479+
identity.identity.node_id
3480+
);
3481+
}
3482+
33253483
#[tokio::test]
33263484
async fn endorse_bitcredit_bill_anon_baseline() {
33273485
let mut ctx = get_ctx();

0 commit comments

Comments
 (0)