From 02cce04fc67c1a9270876ea16efcc867e7347f24 Mon Sep 17 00:00:00 2001 From: Mario Zupan Date: Tue, 3 Mar 2026 15:43:42 +0100 Subject: [PATCH] Improve Status Flags and Add Payment Actions --- CHANGELOG.md | 6 + Cargo.toml | 2 +- crates/bcr-ebill-api/src/external/bitcoin.rs | 6 +- .../src/service/bill_service/data_fetching.rs | 478 +++++++++++++++++- .../src/service/bill_service/issue.rs | 3 +- .../src/service/bill_service/mod.rs | 18 +- .../src/service/bill_service/service.rs | 243 +++------ .../src/service/bill_service/test_utils.rs | 45 +- .../src/service/bill_service/tests.rs | 274 +++++++--- .../src/service/search_service.rs | 14 +- .../src/application/bill/mod.rs | 97 +++- .../src/protocol/blockchain/bill/chain.rs | 20 +- .../src/protocol/blockchain/bill/mod.rs | 9 +- crates/bcr-ebill-persistence/src/db/bill.rs | 361 ++++++++++++- crates/bcr-ebill-persistence/src/tests/mod.rs | 12 +- crates/bcr-ebill-wasm/src/api/bill.rs | 27 +- crates/bcr-ebill-wasm/src/api/general.rs | 9 +- crates/bcr-ebill-wasm/src/data/bill.rs | 253 ++++++++- 18 files changed, 1510 insertions(+), 367 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc00c9d6..f383a4ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 0.5.4 + +* Adapt actions and status implementation for `BitcreditBillResult` (breaking DB change - bill cache clear is enough + * Add `payment_actions` and `state` to `BitcreditBillResult` + * Rename `PastPaymentStatus` to `PaymentStatus` (breaking API change) + # 0.5.3 * Fix minting URL and use new bcr-common diff --git a/Cargo.toml b/Cargo.toml index bfd1e6b4..5644aa3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace.package] -version = "0.5.3" +version = "0.5.4" edition = "2024" license = "MIT" repository = "https://github.com/BitcreditProtocol/Bitcredit-Core" diff --git a/crates/bcr-ebill-api/src/external/bitcoin.rs b/crates/bcr-ebill-api/src/external/bitcoin.rs index 07099041..e518c562 100644 --- a/crates/bcr-ebill-api/src/external/bitcoin.rs +++ b/crates/bcr-ebill-api/src/external/bitcoin.rs @@ -300,12 +300,14 @@ impl BitcoinClientApi for BitcoinClient { origin: None, }; let desc_seckey = miniscript::descriptor::DescriptorSecretKey::Single(single); - let desc_pubkey = desc_seckey.to_public(secp256k1::global::SECP256K1).unwrap(); + let desc_pubkey = desc_seckey + .to_public(secp256k1::global::SECP256K1) + .expect("is a valid key"); let kmap = miniscript::descriptor::KeyMap::from_iter(std::iter::once(( desc_pubkey.clone(), desc_seckey, ))); - let desc = miniscript::Descriptor::new_wpkh(desc_pubkey).unwrap(); + let desc = miniscript::Descriptor::new_wpkh(desc_pubkey).expect("is a valid descriptor"); Ok(desc.to_string_with_secret(&kmap)) } diff --git a/crates/bcr-ebill-api/src/service/bill_service/data_fetching.rs b/crates/bcr-ebill-api/src/service/bill_service/data_fetching.rs index 9739926b..9a1e58b8 100644 --- a/crates/bcr-ebill-api/src/service/bill_service/data_fetching.rs +++ b/crates/bcr-ebill-api/src/service/bill_service/data_fetching.rs @@ -4,14 +4,17 @@ use super::service::BillService; use super::{Error, Result}; use bcr_common::core::{BillId, NodeId}; use bcr_ebill_core::application::bill::{ - BillCallerActions, BillCallerBillAction, BillMintStatus, BillWaitingStatePaymentData, - PaymentState, + BillAcceptState, BillCallerActions, BillCallerBillAction, BillCallerPayment, + BillCallerPaymentAction, BillCallerPaymentState, BillMintState, BillMintStatus, + BillPaymentState, BillState, BillWaitingStatePaymentData, PastPaymentDataPayment, + PastPaymentDataRecourse, PastPaymentDataSell, PastPaymentResult, PaymentState, }; use bcr_ebill_core::application::contact::Contact; use bcr_ebill_core::protocol::Timestamp; use bcr_ebill_core::protocol::Validate; use bcr_ebill_core::protocol::blockchain::Block; -use bcr_ebill_core::protocol::blockchain::bill::BillValidateActionData; +use bcr_ebill_core::protocol::blockchain::bill::block::BillIssueBlockData; +use bcr_ebill_core::protocol::blockchain::bill::{BillValidateActionData, PaymentStatus}; use bcr_ebill_core::protocol::{Date, ProtocolValidationError}; use bcr_ebill_core::protocol::{EmailIdentityProofData, SignedIdentityProof, Sum}; use bcr_ebill_core::{ @@ -204,9 +207,11 @@ impl BillService { chain: &BillBlockchain, bill_keys: &BcrKeys, local_identity: &Identity, - current_identity_node_id: &NodeId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, current_timestamp: Timestamp, ) -> Result { + let current_identity_node_id = caller_public_data.node_id(); // fetch contacts to get current contact data for participants let contacts = self.contact_store.get_map().await?; @@ -219,7 +224,7 @@ impl BillService { let time_of_drawing = first_version_bill.signing_timestamp; let past_endorsees = chain - .get_past_endorsees_for_bill(bill_keys, current_identity_node_id) + .get_past_endorsees_for_bill(bill_keys, ¤t_identity_node_id) .map_err(|e| Error::Protocol(e.into()))?; let bill_participants = chain .get_all_nodes_from_bill(bill_keys) @@ -234,11 +239,21 @@ impl BillService { None => &bill.payee, Some(ref endorsee) => endorsee, }; + // states + let mut bill_mint_state = BillMintState::None; + let mut bill_accept_state = BillAcceptState::None; + let mut bill_payment_state = BillPaymentState::None; + + // payment actions + let mut payment_actions = vec![]; let has_mint_requests = self .mint_store - .exists_for_bill(current_identity_node_id, &bill.id) + .exists_for_bill(¤t_identity_node_id, &bill.id) .await?; + if has_mint_requests { + bill_mint_state = BillMintState::Requested; + } let mut paid = false; let mut requested_to_pay = false; let mut rejected_to_pay = false; @@ -250,9 +265,16 @@ impl BillService { chain.get_last_version_block_with_op_code(BillOpCode::RequestToPay) { requested_to_pay = true; + bill_payment_state = BillPaymentState::Requested(req_to_pay_block.timestamp); time_of_request_to_pay = Some(req_to_pay_block.timestamp); paid = self.store.is_paid(&bill.id).await?; - rejected_to_pay = chain.block_with_operation_code_exists(BillOpCode::RejectToPay); + if let Some(reject_to_pay_block) = + chain.get_last_version_block_with_op_code(BillOpCode::RejectToPay) + { + rejected_to_pay = true; + bill_payment_state = BillPaymentState::Rejected(reject_to_pay_block.timestamp); + } + let (is_expired, payment_deadline) = chain .is_req_to_pay_block_payment_expired( req_to_pay_block, @@ -265,18 +287,26 @@ impl BillService { if !paid && !rejected_to_pay && is_expired { // this is true, if the payment is expired (after maturity date) request_to_pay_timed_out = true; + bill_payment_state = BillPaymentState::Expired(payment_deadline); + } + + if paid + && let Some(PaymentState::PaidConfirmed(payment_data)) = + self.store.get_payment_state(&bill.id).await? + { + bill_payment_state = BillPaymentState::Paid(payment_data.block_time) } } // calculate, if the caller has received funds at any point in the bill let mut redeemed_funds_available = - chain.is_beneficiary_from_a_block(bill_keys, current_identity_node_id); - if holder.node_id() == *current_identity_node_id && paid { + chain.is_beneficiary_from_a_block(bill_keys, ¤t_identity_node_id); + if holder.node_id() == current_identity_node_id && paid { redeemed_funds_available = true; } let has_requested_funds = - chain.is_beneficiary_from_a_request_funds_block(bill_keys, current_identity_node_id); + chain.is_beneficiary_from_a_request_funds_block(bill_keys, ¤t_identity_node_id); let mut offered_to_sell = false; let mut rejected_offer_to_sell = false; @@ -354,8 +384,23 @@ impl BillService { } let mut request_to_accept_timed_out = false; - let rejected_to_accept = chain.block_with_operation_code_exists(BillOpCode::RejectToAccept); - let accepted = chain.block_with_operation_code_exists(BillOpCode::Accept); + let rejected_to_accept = if let Some(reject_to_accept_block) = + chain.get_last_version_block_with_op_code(BillOpCode::RejectToAccept) + { + bill_accept_state = BillAcceptState::Rejected(reject_to_accept_block.timestamp); + true + } else { + false + }; + + let accepted = if let Some(accept_block) = + chain.get_last_version_block_with_op_code(BillOpCode::Accept) + { + bill_accept_state = BillAcceptState::Accepted(accept_block.timestamp); + true + } else { + false + }; let mut time_of_request_to_accept = None; let mut requested_to_accept = false; let mut acceptance_deadline_timestamp = None; @@ -363,6 +408,10 @@ impl BillService { chain.get_last_version_block_with_op_code(BillOpCode::RequestToAccept) { requested_to_accept = true; + if !accepted && !rejected_to_accept { + bill_accept_state = BillAcceptState::Requested(req_to_accept_block.timestamp); + } + time_of_request_to_accept = Some(req_to_accept_block.timestamp); let (is_expired, acceptance_deadline) = chain @@ -371,6 +420,7 @@ impl BillService { acceptance_deadline_timestamp = Some(acceptance_deadline); if !accepted && !rejected_to_accept && is_expired { request_to_accept_timed_out = true; + bill_accept_state = BillAcceptState::Expired(acceptance_deadline); } } @@ -436,6 +486,51 @@ impl BillService { .bitcoin_client .get_mempool_link_for_address(&address_to_pay); + // if we're payer, create pay action, if we're payee, create check payment action + if current_identity_node_id == buyer.node_id() { + payment_actions.push(BillCallerPaymentAction::Pay( + BillCallerPayment::Sell { + buyer: buyer.clone(), + seller: seller.clone(), + state: BillCallerPaymentState { + time_of_request: last_block.timestamp, + sum: payment_info.sum.clone(), + link_to_pay: link_to_pay.clone(), + address_to_pay: address_to_pay.clone(), + mempool_link_for_address_to_pay: + mempool_link_for_address_to_pay.clone(), + status: PaymentStatus::Requested(last_block.timestamp), + payment_deadline: payment_info.buying_deadline_timestamp, + tx_id: tx_id.clone(), + in_mempool, + confirmations, + private_descriptor_to_spend: None, + }, + }, + )); + } else if current_identity_node_id == seller.node_id() { + payment_actions.push(BillCallerPaymentAction::CheckPayment( + BillCallerPayment::Sell { + buyer: buyer.clone(), + seller: seller.clone(), + state: BillCallerPaymentState { + time_of_request: last_block.timestamp, + sum: payment_info.sum.clone(), + link_to_pay: link_to_pay.clone(), + address_to_pay: address_to_pay.clone(), + mempool_link_for_address_to_pay: + mempool_link_for_address_to_pay.clone(), + status: PaymentStatus::Requested(last_block.timestamp), + payment_deadline: payment_info.buying_deadline_timestamp, + tx_id: tx_id.clone(), + in_mempool, + confirmations, + private_descriptor_to_spend: None, + }, + }, + )); + } + Some(BillCurrentWaitingState::Sell(BillWaitingForSellState { seller, buyer, @@ -504,6 +599,53 @@ impl BillService { .bitcoin_client .get_mempool_link_for_address(&address_to_pay); + if let Some(payment_deadline) = payment_deadline_timestamp { + // if we're payer, create pay action, if we're payee, create check payment action + if current_identity_node_id == bill.drawee.node_id { + payment_actions.push(BillCallerPaymentAction::Pay( + BillCallerPayment::Payment { + payer: bill.drawee.clone(), + payee: holder.clone(), + state: BillCallerPaymentState { + time_of_request: last_block.timestamp, + sum: bill.sum.clone(), + link_to_pay: link_to_pay.clone(), + address_to_pay: address_to_pay.clone(), + mempool_link_for_address_to_pay: + mempool_link_for_address_to_pay.clone(), + status: PaymentStatus::Requested(last_block.timestamp), + payment_deadline, + tx_id: tx_id.clone(), + in_mempool, + confirmations, + private_descriptor_to_spend: None, + }, + }, + )); + } else if current_identity_node_id == holder.node_id() { + payment_actions.push(BillCallerPaymentAction::CheckPayment( + BillCallerPayment::Payment { + payer: bill.drawee.clone(), + payee: holder.clone(), + state: BillCallerPaymentState { + time_of_request: last_block.timestamp, + sum: bill.sum.clone(), + link_to_pay: link_to_pay.clone(), + address_to_pay: address_to_pay.clone(), + mempool_link_for_address_to_pay: + mempool_link_for_address_to_pay.clone(), + status: PaymentStatus::Requested(last_block.timestamp), + payment_deadline, + tx_id: tx_id.clone(), + in_mempool, + confirmations, + private_descriptor_to_spend: None, + }, + }, + )); + } + } + Some(BillCurrentWaitingState::Payment( BillWaitingForPaymentState { payer: bill.drawee.clone(), @@ -588,6 +730,51 @@ impl BillService { .bitcoin_client .get_mempool_link_for_address(&address_to_pay); + // if we're payer, create pay action, if we're payee, create check payment action + if current_identity_node_id == recoursee.node_id { + payment_actions.push(BillCallerPaymentAction::Pay( + BillCallerPayment::Recourse { + recourser: recourser.clone(), + recoursee: recoursee.clone(), + state: BillCallerPaymentState { + time_of_request: last_block.timestamp, + sum: payment_info.sum.clone(), + link_to_pay: link_to_pay.clone(), + address_to_pay: address_to_pay.clone(), + mempool_link_for_address_to_pay: + mempool_link_for_address_to_pay.clone(), + status: PaymentStatus::Requested(last_block.timestamp), + payment_deadline: payment_info.recourse_deadline_timestamp, + tx_id: tx_id.clone(), + in_mempool, + confirmations, + private_descriptor_to_spend: None, + }, + }, + )); + } else if current_identity_node_id == recourser.node_id() { + payment_actions.push(BillCallerPaymentAction::CheckPayment( + BillCallerPayment::Recourse { + recourser: recourser.clone(), + recoursee: recoursee.clone(), + state: BillCallerPaymentState { + time_of_request: last_block.timestamp, + sum: payment_info.sum.clone(), + link_to_pay: link_to_pay.clone(), + address_to_pay: address_to_pay.clone(), + mempool_link_for_address_to_pay: + mempool_link_for_address_to_pay.clone(), + status: PaymentStatus::Requested(last_block.timestamp), + payment_deadline: payment_info.recourse_deadline_timestamp, + tx_id: tx_id.clone(), + in_mempool, + confirmations, + private_descriptor_to_spend: None, + }, + }, + )); + } + Some(BillCurrentWaitingState::Recourse( BillWaitingForRecourseState { recourser, @@ -615,6 +802,88 @@ impl BillService { _ => None, }; + // add past payments as check_payment actions for the caller + let mut past_payments: Vec = self + .fetch_past_payments( + &bill.id, + caller_public_data, + caller_keys, + current_timestamp, + chain, + bill_keys, + paid, + &first_version_bill, + ) + .await? + .into_iter() + .map(|pp| match pp { + PastPaymentResult::Sell(data) => { + BillCallerPaymentAction::CheckPayment(BillCallerPayment::Sell { + buyer: data.buyer, + seller: data.seller, + state: BillCallerPaymentState { + time_of_request: data.time_of_request, + sum: data.sum, + link_to_pay: data.link_to_pay, + address_to_pay: data.address_to_pay, + mempool_link_for_address_to_pay: data.mempool_link_for_address_to_pay, + status: data.status, + payment_deadline: data.payment_deadline, + tx_id: None, + in_mempool: false, + confirmations: 0, + private_descriptor_to_spend: Some(data.private_descriptor_to_spend), + }, + }) + } + PastPaymentResult::Payment(data) => { + BillCallerPaymentAction::CheckPayment(BillCallerPayment::Payment { + payer: data.payer, + payee: data.payee, + state: BillCallerPaymentState { + time_of_request: data.time_of_request, + sum: data.sum, + link_to_pay: data.link_to_pay, + address_to_pay: data.address_to_pay, + mempool_link_for_address_to_pay: data.mempool_link_for_address_to_pay, + status: data.status, + payment_deadline: data.payment_deadline, + tx_id: None, + in_mempool: false, + confirmations: 0, + private_descriptor_to_spend: Some(data.private_descriptor_to_spend), + }, + }) + } + PastPaymentResult::Recourse(data) => { + BillCallerPaymentAction::CheckPayment(BillCallerPayment::Recourse { + recourser: data.recourser, + recoursee: data.recoursee, + state: BillCallerPaymentState { + time_of_request: data.time_of_request, + sum: data.sum, + link_to_pay: data.link_to_pay, + address_to_pay: data.address_to_pay, + mempool_link_for_address_to_pay: data.mempool_link_for_address_to_pay, + status: data.status, + payment_deadline: data.payment_deadline, + tx_id: None, + in_mempool: false, + confirmations: 0, + private_descriptor_to_spend: Some(data.private_descriptor_to_spend), + }, + }) + } + }) + .collect(); + payment_actions.append(&mut past_payments); + + let state = BillState { + mint: bill_mint_state, + accept: bill_accept_state, + payment: bill_payment_state, + }; + let status = BillStatus { acceptance: BillAcceptanceStatus { time_of_request_to_accept, @@ -691,7 +960,7 @@ impl BillService { bill_data.maturity_date.clone(), bill_keys.to_owned(), current_timestamp, - current_identity_node_id.to_owned(), + current_identity_node_id, paid, is_waiting_for_req_to_pay, recourse_waiting_for_payment_state, @@ -700,6 +969,7 @@ impl BillService { request_to_accept_timed_out, past_endorsees, )?, + payment_actions, }; Ok(BitcreditBillResult { @@ -707,12 +977,175 @@ impl BillService { participants, data: bill_data, status, + state, current_waiting_state, history: bill_history, actions: bill_caller_actions, }) } + pub(super) async fn fetch_past_payments( + &self, + bill_id: &BillId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, + timestamp: Timestamp, + chain: &BillBlockchain, + bill_keys: &BcrKeys, + is_paid: bool, + bill: &BillIssueBlockData, + ) -> Result> { + let mut result = vec![]; + + let bill_parties = chain + .get_bill_parties(bill_keys, bill) + .map_err(|e| Error::Protocol(e.into()))?; + + let holder = match bill_parties.endorsee { + None => &bill_parties.payee, + Some(ref endorsee) => endorsee, + }; + + let descriptor_to_spend = self.bitcoin_client.get_combined_private_descriptor( + &BcrKeys::from_private_key(&bill_keys.get_private_key()) + .get_bitcoin_private_key(get_config().bitcoin_network()), + &caller_keys.get_bitcoin_private_key(get_config().bitcoin_network()), + )?; + + // Request to Pay + if holder.node_id() == caller_public_data.node_id() + && let Some(req_to_pay) = + chain.get_last_version_block_with_op_code(BillOpCode::RequestToPay) + { + let address_to_pay = self + .bitcoin_client + .get_address_to_pay(&bill_keys.pub_key(), &holder.node_id().pub_key())?; + let link_to_pay = self.bitcoin_client.generate_link_to_pay( + &address_to_pay, + &bill.sum, + &format!("Payment in relation to a bill {}", bill.id.clone()), + ); + let mempool_link_for_address_to_pay = self + .bitcoin_client + .get_mempool_link_for_address(&address_to_pay); + + // we check for the payment expiration, not the request expiration + // if the request expired, but the payment deadline hasn't, it's not a past payment + let (is_expired, payment_deadline) = chain + .is_req_to_pay_block_payment_expired( + req_to_pay, + bill_keys, + timestamp, + Some(&bill.maturity_date), + ) + .map_err(|e| Error::Protocol(e.into()))?; + + let is_rejected = chain.block_with_operation_code_exists(BillOpCode::RejectToPay); + + if is_paid || is_rejected || is_expired { + result.push(PastPaymentResult::Payment(PastPaymentDataPayment { + time_of_request: req_to_pay.timestamp, + payer: bill_parties.drawee.clone().into(), + payee: holder.clone().into(), + sum: bill.sum.clone(), + link_to_pay, + address_to_pay, + private_descriptor_to_spend: descriptor_to_spend.clone(), + mempool_link_for_address_to_pay, + status: if is_paid { + if let Ok(Some(PaymentState::PaidConfirmed(paid_date))) = + self.store.get_payment_state(bill_id).await + { + PaymentStatus::Paid(paid_date.block_time) + } else { + // fall back to req to pay time, if we don't have the paid ts + PaymentStatus::Paid(req_to_pay.timestamp) + } + } else if is_rejected { + let ts = if let Some(reject_to_pay_block) = + chain.get_last_version_block_with_op_code(BillOpCode::RejectToPay) + { + reject_to_pay_block.timestamp + } else { + req_to_pay.timestamp + }; + PaymentStatus::Rejected(ts) + } else { + PaymentStatus::Expired(payment_deadline) + }, + payment_deadline, + })); + } + } + + // OfferToSell + let past_sell_payments = chain + .get_past_sell_payments_for_node_id(bill_keys, &caller_public_data.node_id(), timestamp) + .map_err(|e| Error::Protocol(e.into()))?; + for past_sell_payment in past_sell_payments { + let address_to_pay = past_sell_payment.0.payment_address; + let link_to_pay = self.bitcoin_client.generate_link_to_pay( + &address_to_pay, + &past_sell_payment.0.sum, + &format!("Payment in relation to a bill {}", &bill.id), + ); + let mempool_link_for_address_to_pay = self + .bitcoin_client + .get_mempool_link_for_address(&address_to_pay); + + result.push(PastPaymentResult::Sell(PastPaymentDataSell { + time_of_request: past_sell_payment.2, + buyer: past_sell_payment.0.buyer, + seller: past_sell_payment.0.seller, + sum: past_sell_payment.0.sum, + link_to_pay, + address_to_pay, + private_descriptor_to_spend: descriptor_to_spend.clone(), + mempool_link_for_address_to_pay, + status: past_sell_payment.1, + payment_deadline: past_sell_payment.0.buying_deadline_timestamp, + })); + } + + // Recourse + let past_recourse_payments = chain + .get_past_recourse_payments_for_node_id( + bill_keys, + &caller_public_data.node_id(), + timestamp, + ) + .map_err(|e| Error::Protocol(e.into()))?; + for past_sell_payment in past_recourse_payments { + let address_to_pay = self.bitcoin_client.get_address_to_pay( + &bill_keys.pub_key(), + &past_sell_payment.0.recourser.node_id().pub_key(), + )?; + let link_to_pay = self.bitcoin_client.generate_link_to_pay( + &address_to_pay, + &past_sell_payment.0.sum, + &format!("Payment in relation to a bill {}", &bill.id), + ); + let mempool_link_for_address_to_pay = self + .bitcoin_client + .get_mempool_link_for_address(&address_to_pay); + + result.push(PastPaymentResult::Recourse(PastPaymentDataRecourse { + time_of_request: past_sell_payment.2, + recoursee: past_sell_payment.0.recoursee.into(), + recourser: past_sell_payment.0.recourser.into(), + sum: past_sell_payment.0.sum, + link_to_pay, + address_to_pay, + private_descriptor_to_spend: descriptor_to_spend.clone(), + mempool_link_for_address_to_pay, + status: past_sell_payment.1, + payment_deadline: past_sell_payment.0.recourse_deadline_timestamp, + })); + } + + Ok(result) + } + pub(super) fn check_requests_for_expiration( &self, bill: &BitcreditBillResult, @@ -880,7 +1313,8 @@ impl BillService { &self, bill_id: &BillId, local_identity: &Identity, - current_identity_node_id: &NodeId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, current_timestamp: Timestamp, ) -> Result { let chain = self.blockchain_store.get_chain(bill_id).await?; @@ -890,13 +1324,14 @@ impl BillService { &chain, &bill_keys, local_identity, - current_identity_node_id, + caller_public_data, + caller_keys, current_timestamp, ) .await?; if let Err(e) = self .store - .save_bill_to_cache(bill_id, current_identity_node_id, &calculated_bill) + .save_bill_to_cache(bill_id, &caller_public_data.node_id(), &calculated_bill) .await { error!("Error saving calculated bill {bill_id} to cache: {e}"); @@ -908,7 +1343,8 @@ impl BillService { &self, bill_id: &BillId, local_identity: &Identity, - current_identity_node_id: &NodeId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, current_timestamp: Timestamp, ) -> Result { // if there is no such bill, we return an error @@ -925,7 +1361,7 @@ impl BillService { // check if the bill is in the cache let bill_cache_result = self .store - .get_bill_from_cache(bill_id, current_identity_node_id) + .get_bill_from_cache(bill_id, &caller_public_data.node_id()) .await; let mut bill = match bill_cache_result { Ok(Some(mut bill)) => { @@ -946,7 +1382,8 @@ impl BillService { self.recalculate_and_cache_bill( bill_id, local_identity, - current_identity_node_id, + caller_public_data, + caller_keys, current_timestamp, ) .await? @@ -963,7 +1400,8 @@ impl BillService { self.recalculate_and_cache_bill( bill_id, local_identity, - current_identity_node_id, + caller_public_data, + caller_keys, current_timestamp, ) .await? diff --git a/crates/bcr-ebill-api/src/service/bill_service/issue.rs b/crates/bcr-ebill-api/src/service/bill_service/issue.rs index 59d465b4..ce544e28 100644 --- a/crates/bcr-ebill-api/src/service/bill_service/issue.rs +++ b/crates/bcr-ebill-api/src/service/bill_service/issue.rs @@ -259,7 +259,8 @@ impl BillService { &chain, &bill_keys, &identity.identity, - &data.drawer_public_data.node_id(), + &data.drawer_public_data, + &data.drawer_keys, data.timestamp, ) .await?; diff --git a/crates/bcr-ebill-api/src/service/bill_service/mod.rs b/crates/bcr-ebill-api/src/service/bill_service/mod.rs index 8fafb679..4f949a3a 100644 --- a/crates/bcr-ebill-api/src/service/bill_service/mod.rs +++ b/crates/bcr-ebill-api/src/service/bill_service/mod.rs @@ -51,7 +51,8 @@ pub trait BillServiceApi: ServiceTraitBounds { async fn get_bill_balances( &self, currency: &Currency, - current_identity_node_id: &NodeId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, ) -> Result; /// Search for bills @@ -62,13 +63,15 @@ pub trait BillServiceApi: ServiceTraitBounds { date_range_from: Option, date_range_to: Option, role: &BillsFilterRole, - current_identity_node_id: &NodeId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, ) -> Result>; /// Gets all bills async fn get_bills( &self, - current_identity_node_id: &NodeId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, ) -> Result>; /// Gets the combined bitcoin private key for a given bill @@ -84,7 +87,8 @@ pub trait BillServiceApi: ServiceTraitBounds { &self, bill_id: &BillId, local_identity: &Identity, - current_identity_node_id: &NodeId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, current_timestamp: Timestamp, ) -> Result; @@ -170,7 +174,8 @@ pub trait BillServiceApi: ServiceTraitBounds { &self, bill_id: &BillId, identity: &Identity, - current_identity_node_id: &NodeId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, current_timestamp: Timestamp, ) -> Result>; @@ -247,7 +252,8 @@ pub trait BillServiceApi: ServiceTraitBounds { &self, bill_id: &BillId, local_identity: &Identity, - current_identity_node_id: &NodeId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, current_timestamp: Timestamp, ) -> Result; } diff --git a/crates/bcr-ebill-api/src/service/bill_service/service.rs b/crates/bcr-ebill-api/src/service/bill_service/service.rs index 5aa3f014..8280c612 100644 --- a/crates/bcr-ebill-api/src/service/bill_service/service.rs +++ b/crates/bcr-ebill-api/src/service/bill_service/service.rs @@ -13,8 +13,7 @@ use async_trait::async_trait; use bcr_common::core::{BillId, NodeId}; use bcr_ebill_core::application::bill::{ BillCombinedBitcoinKey, BillRole, BillsBalance, BillsBalanceOverview, BillsFilterRole, - BitcreditBillResult, Endorsement, LightBitcreditBillResult, PastPaymentDataPayment, - PastPaymentDataRecourse, PastPaymentDataSell, PastPaymentResult, PaymentState, + BitcreditBillResult, Endorsement, LightBitcreditBillResult, PastPaymentResult, }; use bcr_ebill_core::application::company::Company; use bcr_ebill_core::application::contact::{Contact, LightBillParticipant}; @@ -28,8 +27,7 @@ use bcr_ebill_core::protocol::blockchain::bill::block::{ use bcr_ebill_core::protocol::blockchain::bill::chain::BillBlockPlaintextWrapper; use bcr_ebill_core::protocol::blockchain::bill::{ BillBlockchain, BillHistory, BillIssueData, BillOpCode, BillValidateActionData, - BillValidationActionMode, BitcreditBill, PastPaymentStatus, - create_bill_to_share_with_external_party, + BillValidationActionMode, BitcreditBill, create_bill_to_share_with_external_party, participant::{BillAnonParticipant, BillIdentParticipant, BillParticipant, PastEndorsee}, }; use bcr_ebill_core::protocol::blockchain::{Blockchain, identity::IdentityType}; @@ -121,7 +119,8 @@ impl BillService { chain: &BillBlockchain, bill_keys: &BcrKeys, local_identity: &Identity, - current_identity_node_id: &NodeId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, current_timestamp: Timestamp, ) -> Result<()> { let calculated_bill = self @@ -129,12 +128,13 @@ impl BillService { chain, bill_keys, local_identity, - current_identity_node_id, + caller_public_data, + caller_keys, current_timestamp, ) .await?; self.store - .save_bill_to_cache(bill_id, current_identity_node_id, &calculated_bill) + .save_bill_to_cache(bill_id, &caller_public_data.node_id(), &calculated_bill) .await?; Ok(()) } @@ -755,18 +755,20 @@ impl BillServiceApi for BillService { async fn get_bill_balances( &self, _currency: &Currency, - current_identity_node_id: &NodeId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, ) -> Result { + let current_identity_node_id = caller_public_data.node_id(); // TODO (currency): convert between currencies based on given currency - validate_node_id_network(current_identity_node_id)?; - let bills = self.get_bills(current_identity_node_id).await?; + validate_node_id_network(¤t_identity_node_id)?; + let bills = self.get_bills(caller_public_data, caller_keys).await?; let mut payer_sum = 0; let mut payee_sum = 0; let mut contingent_sum = 0; for bill in bills { - if let Some(bill_role) = bill.get_bill_role_for_node_id(current_identity_node_id) { + if let Some(bill_role) = bill.get_bill_role_for_node_id(¤t_identity_node_id) { let sum = bill.data.sum; match bill_role { BillRole::Payee => payee_sum += sum.as_sat(), @@ -778,7 +780,7 @@ impl BillServiceApi for BillService { for endorsement in endorsements.iter() { let holder = &endorsement.pay_to_the_order_of; // we're in the chain as non-anon - if &holder.node_id() == current_identity_node_id + if holder.node_id() == current_identity_node_id && matches!(holder, LightBillParticipant::Ident(_)) { in_guarantee_chain_as_non_anon = true; @@ -786,7 +788,7 @@ impl BillServiceApi for BillService { } } if in_guarantee_chain_as_non_anon - || &bill.participants.drawer.node_id == current_identity_node_id + || bill.participants.drawer.node_id == current_identity_node_id { contingent_sum += sum.as_sat() } @@ -815,13 +817,15 @@ impl BillServiceApi for BillService { date_range_from: Option, date_range_to: Option, role: &BillsFilterRole, - current_identity_node_id: &NodeId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, ) -> Result> { debug!( "searching bills with {search_term:?} from {date_range_from:?} to {date_range_to:?} and {role:?}" ); - validate_node_id_network(current_identity_node_id)?; - let bills = self.get_bills(current_identity_node_id).await?; + let current_identity_node_id = caller_public_data.node_id(); + validate_node_id_network(¤t_identity_node_id)?; + let bills = self.get_bills(caller_public_data, caller_keys).await?; let mut result = vec![]; // for now we do the search here - with the quick-fetch table, we can search in surrealDB @@ -840,7 +844,7 @@ impl BillServiceApi for BillService { continue; } - let bill_role = match bill.get_bill_role_for_node_id(current_identity_node_id) { + let bill_role = match bill.get_bill_role_for_node_id(¤t_identity_node_id) { Some(bill_role) => bill_role, None => continue, // node is not in bill - don't add }; @@ -882,9 +886,10 @@ impl BillServiceApi for BillService { async fn get_bills( &self, - current_identity_node_id: &NodeId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, ) -> Result> { - validate_node_id_network(current_identity_node_id)?; + validate_node_id_network(&caller_public_data.node_id())?; let bill_ids = self.store.get_ids().await?; let identity = self.identity_store.get().await?; let current_timestamp = Timestamp::now(); @@ -894,7 +899,7 @@ impl BillServiceApi for BillService { let mut bills = self .store - .get_bills_from_cache(&bill_ids, current_identity_node_id) + .get_bills_from_cache(&bill_ids, &caller_public_data.node_id()) .await?; // extend identities for cached bills for bill in bills.iter_mut() { @@ -912,7 +917,8 @@ impl BillServiceApi for BillService { .recalculate_and_cache_bill( &bill.id, &identity, - current_identity_node_id, + caller_public_data, + caller_keys, current_timestamp, ) .await?; @@ -927,7 +933,8 @@ impl BillServiceApi for BillService { .recalculate_and_cache_bill( bill_id, &identity, - current_identity_node_id, + caller_public_data, + caller_keys, current_timestamp, ) .await?; @@ -952,7 +959,7 @@ impl BillServiceApi for BillService { b.participants .all_participant_node_ids .iter() - .any(|p| p == current_identity_node_id) + .any(|p| p == &caller_public_data.node_id()) }) .collect()) } @@ -992,16 +999,18 @@ impl BillServiceApi for BillService { &self, bill_id: &BillId, identity: &Identity, - current_identity_node_id: &NodeId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, current_timestamp: Timestamp, ) -> Result { validate_bill_id_network(bill_id)?; - validate_node_id_network(current_identity_node_id)?; + validate_node_id_network(&caller_public_data.node_id())?; let res = self .get_full_bill( bill_id, identity, - current_identity_node_id, + caller_public_data, + caller_keys, current_timestamp, ) .await?; @@ -1010,7 +1019,7 @@ impl BillServiceApi for BillService { .participants .all_participant_node_ids .iter() - .any(|p| p == current_identity_node_id) + .any(|p| p == &caller_public_data.node_id()) { return Err(Error::NotFound); } @@ -1121,7 +1130,8 @@ impl BillServiceApi for BillService { &blockchain, &bill_keys, &identity.identity, - &signer_public_data.node_id(), + signer_public_data, + signer_keys, timestamp, ) .await?; @@ -1335,182 +1345,44 @@ impl BillServiceApi for BillService { return Err(Error::NotFound); } }; - - let mut result = vec![]; - let chain = self.blockchain_store.get_chain(bill_id).await?; let bill_keys = self.store.get_keys(bill_id).await?; let is_paid = self.store.is_paid(bill_id).await?; let bill = chain .get_first_version_bill(&bill_keys) .map_err(|e| Error::Protocol(e.into()))?; - let bill_parties = chain - .get_bill_parties(&bill_keys, &bill) - .map_err(|e| Error::Protocol(e.into()))?; - - let holder = match bill_parties.endorsee { - None => &bill_parties.payee, - Some(ref endorsee) => endorsee, - }; - - let descriptor_to_spend = self.bitcoin_client.get_combined_private_descriptor( - &BcrKeys::from_private_key(&bill_keys.get_private_key()) - .get_bitcoin_private_key(get_config().bitcoin_network()), - &caller_keys.get_bitcoin_private_key(get_config().bitcoin_network()), - )?; - - // Request to Pay - if holder.node_id() == caller_public_data.node_id() - && let Some(req_to_pay) = - chain.get_last_version_block_with_op_code(BillOpCode::RequestToPay) - { - let address_to_pay = self - .bitcoin_client - .get_address_to_pay(&bill_keys.pub_key(), &holder.node_id().pub_key())?; - let link_to_pay = self.bitcoin_client.generate_link_to_pay( - &address_to_pay, - &bill.sum, - &format!("Payment in relation to a bill {}", bill.id.clone()), - ); - let mempool_link_for_address_to_pay = self - .bitcoin_client - .get_mempool_link_for_address(&address_to_pay); - - // we check for the payment expiration, not the request expiration - // if the request expired, but the payment deadline hasn't, it's not a past payment - let (is_expired, payment_deadline) = chain - .is_req_to_pay_block_payment_expired( - req_to_pay, - &bill_keys, - timestamp, - Some(&bill.maturity_date), - ) - .map_err(|e| Error::Protocol(e.into()))?; - - let is_rejected = chain.block_with_operation_code_exists(BillOpCode::RejectToPay); - - if is_paid || is_rejected || is_expired { - result.push(PastPaymentResult::Payment(PastPaymentDataPayment { - time_of_request: req_to_pay.timestamp, - payer: bill_parties.drawee.clone().into(), - payee: holder.clone().into(), - sum: bill.sum.clone(), - link_to_pay, - address_to_pay, - private_descriptor_to_spend: descriptor_to_spend.clone(), - mempool_link_for_address_to_pay, - status: if is_paid { - if let Ok(Some(PaymentState::PaidConfirmed(paid_date))) = - self.store.get_payment_state(bill_id).await - { - PastPaymentStatus::Paid(paid_date.block_time) - } else { - // fall back to req to pay time, if we don't have the paid ts - PastPaymentStatus::Paid(req_to_pay.timestamp) - } - } else if is_rejected { - let ts = if let Some(reject_to_pay_block) = - chain.get_last_version_block_with_op_code(BillOpCode::RejectToPay) - { - reject_to_pay_block.timestamp - } else { - req_to_pay.timestamp - }; - PastPaymentStatus::Rejected(ts) - } else { - PastPaymentStatus::Expired(payment_deadline) - }, - payment_deadline, - })); - } - } - // OfferToSell - let past_sell_payments = chain - .get_past_sell_payments_for_node_id( - &bill_keys, - &caller_public_data.node_id(), + let res = self + .fetch_past_payments( + bill_id, + caller_public_data, + caller_keys, timestamp, - ) - .map_err(|e| Error::Protocol(e.into()))?; - for past_sell_payment in past_sell_payments { - let address_to_pay = past_sell_payment.0.payment_address; - let link_to_pay = self.bitcoin_client.generate_link_to_pay( - &address_to_pay, - &past_sell_payment.0.sum, - &format!("Payment in relation to a bill {}", &bill.id), - ); - let mempool_link_for_address_to_pay = self - .bitcoin_client - .get_mempool_link_for_address(&address_to_pay); - - result.push(PastPaymentResult::Sell(PastPaymentDataSell { - time_of_request: past_sell_payment.2, - buyer: past_sell_payment.0.buyer, - seller: past_sell_payment.0.seller, - sum: past_sell_payment.0.sum, - link_to_pay, - address_to_pay, - private_descriptor_to_spend: descriptor_to_spend.clone(), - mempool_link_for_address_to_pay, - status: past_sell_payment.1, - payment_deadline: past_sell_payment.0.buying_deadline_timestamp, - })); - } - - // Recourse - let past_recourse_payments = chain - .get_past_recourse_payments_for_node_id( + &chain, &bill_keys, - &caller_public_data.node_id(), - timestamp, + is_paid, + &bill, ) - .map_err(|e| Error::Protocol(e.into()))?; - for past_sell_payment in past_recourse_payments { - let address_to_pay = self.bitcoin_client.get_address_to_pay( - &bill_keys.pub_key(), - &past_sell_payment.0.recourser.node_id().pub_key(), - )?; - let link_to_pay = self.bitcoin_client.generate_link_to_pay( - &address_to_pay, - &past_sell_payment.0.sum, - &format!("Payment in relation to a bill {}", &bill.id), - ); - let mempool_link_for_address_to_pay = self - .bitcoin_client - .get_mempool_link_for_address(&address_to_pay); - - result.push(PastPaymentResult::Recourse(PastPaymentDataRecourse { - time_of_request: past_sell_payment.2, - recoursee: past_sell_payment.0.recoursee.into(), - recourser: past_sell_payment.0.recourser.into(), - sum: past_sell_payment.0.sum, - link_to_pay, - address_to_pay, - private_descriptor_to_spend: descriptor_to_spend.clone(), - mempool_link_for_address_to_pay, - status: past_sell_payment.1, - payment_deadline: past_sell_payment.0.recourse_deadline_timestamp, - })); - } - - Ok(result) + .await?; + Ok(res) } async fn get_endorsements( &self, bill_id: &BillId, identity: &Identity, - current_identity_node_id: &NodeId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, current_timestamp: Timestamp, ) -> Result> { validate_bill_id_network(bill_id)?; - validate_node_id_network(current_identity_node_id)?; + validate_node_id_network(&caller_public_data.node_id())?; let bill = self .get_detail( bill_id, identity, - current_identity_node_id, + caller_public_data, + caller_keys, current_timestamp, ) .await?; @@ -1643,7 +1515,8 @@ impl BillServiceApi for BillService { &blockchain, &bill_keys, &identity, - &signer_public_data.node_id(), + signer_public_data, + signer_keys, timestamp, ) .await?; @@ -2008,14 +1881,16 @@ impl BillServiceApi for BillService { &self, bill_id: &BillId, local_identity: &Identity, - current_identity_node_id: &NodeId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, current_timestamp: Timestamp, ) -> Result { let detail = self .get_detail( bill_id, local_identity, - current_identity_node_id, + caller_public_data, + caller_keys, current_timestamp, ) .await?; diff --git a/crates/bcr-ebill-api/src/service/bill_service/test_utils.rs b/crates/bcr-ebill-api/src/service/bill_service/test_utils.rs index f887d105..a9b4f775 100644 --- a/crates/bcr-ebill-api/src/service/bill_service/test_utils.rs +++ b/crates/bcr-ebill-api/src/service/bill_service/test_utils.rs @@ -19,29 +19,26 @@ use crate::{ }; use bcr_ebill_core::{ application::bill::{ - BillAcceptanceStatus, BillCallerActions, BillData, BillMintStatus, BillParticipants, - BillPaymentStatus, BillRecourseStatus, BillSellStatus, BillStatus, PaidData, PaymentState, + BillAcceptState, BillAcceptanceStatus, BillCallerActions, BillData, BillMintState, + BillMintStatus, BillParticipants, BillPaymentState, BillPaymentStatus, BillRecourseStatus, + BillSellStatus, BillState, BillStatus, PaidData, PaymentState, }, - protocol::Address, - protocol::BitcoinAddress, - protocol::City, - protocol::Country, - protocol::Date, - protocol::Name, - protocol::Sum, - protocol::Timestamp, - protocol::blockchain::bill::participant::{BillIdentParticipant, BillParticipant}, - protocol::blockchain::bill::{ - BillBlock, - block::{ - BillAcceptBlockData, BillIssueBlockData, BillOfferToSellBlockData, - BillParticipantBlockData, BillRecourseBlockData, BillRecourseReasonBlockData, - BillRejectBlockData, BillRejectToBuyBlockData, BillRequestRecourseBlockData, - BillRequestToAcceptBlockData, BillRequestToPayBlockData, BillSellBlockData, + protocol::{ + Address, BitcoinAddress, City, Country, Date, Name, Sum, Timestamp, + blockchain::bill::{ + BillBlock, + block::{ + BillAcceptBlockData, BillIssueBlockData, BillOfferToSellBlockData, + BillParticipantBlockData, BillRecourseBlockData, BillRecourseReasonBlockData, + BillRejectBlockData, BillRejectToBuyBlockData, BillRequestRecourseBlockData, + BillRequestToAcceptBlockData, BillRequestToPayBlockData, BillSellBlockData, + }, + participant::{BillIdentParticipant, BillParticipant}, + }, + constants::{ + ACCEPT_DEADLINE_SECONDS, DAY_IN_SECS, PAYMENT_DEADLINE_SECONDS, + RECOURSE_DEADLINE_SECONDS, }, - }, - protocol::constants::{ - ACCEPT_DEADLINE_SECONDS, DAY_IN_SECS, PAYMENT_DEADLINE_SECONDS, RECOURSE_DEADLINE_SECONDS, }, }; use external::{bitcoin::MockBitcoinClientApi, mint::MockMintClientApi}; @@ -152,10 +149,16 @@ pub fn get_baseline_cached_bill(id: BillId) -> BitcreditBillResult { has_requested_funds: false, last_block_time: test_ts(), }, + state: BillState { + mint: BillMintState::None, + accept: BillAcceptState::None, + payment: BillPaymentState::None, + }, current_waiting_state: None, history: BillHistory { blocks: vec![] }, actions: BillCallerActions { bill_actions: vec![], + payment_actions: vec![], }, } } diff --git a/crates/bcr-ebill-api/src/service/bill_service/tests.rs b/crates/bcr-ebill-api/src/service/bill_service/tests.rs index dfcc23b0..e7ea6f98 100644 --- a/crates/bcr-ebill-api/src/service/bill_service/tests.rs +++ b/crates/bcr-ebill-api/src/service/bill_service/tests.rs @@ -9,9 +9,10 @@ use crate::{ }, tests::tests::{ bill_id_test, bill_id_test_other, bill_id_test_other2, - bill_identified_participant_only_node_id, empty_address, empty_bill_identified_participant, - empty_identity, init_test_cfg, node_id_test, node_id_test_other, private_key_test, - signed_identity_proof_test, test_ts, valid_payment_address_testnet, + bill_identified_participant_only_node_id, bill_participant_only_node_id, empty_address, + empty_bill_identified_participant, empty_identity, init_test_cfg, node_id_test, + node_id_test_other, private_key_test, signed_identity_proof_test, test_ts, + valid_payment_address_testnet, }, util::get_uuid_v4, }; @@ -31,7 +32,7 @@ use bcr_ebill_core::{ blockchain::{ Block, Blockchain, bill::{ - BillBlock, BillOpCode, PastPaymentStatus, RecourseReason, + BillBlock, BillOpCode, PaymentStatus, RecourseReason, block::{ BillEndorseBlockData, BillMintBlockData, BillOfferToSellBlockData, BillParticipantBlockData, BillRecourseReasonBlockData, BillRejectBlockData, @@ -66,7 +67,8 @@ use test_utils::{ async fn get_bill_balances_baseline() { let mut ctx = get_ctx(); let identity = get_baseline_identity(); - let company_node_id = NodeId::new(BcrKeys::new().pub_key(), bitcoin::Network::Testnet); + let company_keys = BcrKeys::new(); + let company_node_id = NodeId::new(company_keys.pub_key(), bitcoin::Network::Testnet); let mut bill1 = get_baseline_bill(&bill_id_test()); bill1.sum = Sum::new_sat(1000).expect("sat works"); @@ -119,7 +121,11 @@ async fn get_bill_balances_baseline() { // for identity let res = service - .get_bill_balances(&Currency::sat(), &identity.identity.node_id) + .get_bill_balances( + &Currency::sat(), + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, + ) .await; assert!(res.is_ok()); assert_eq!( @@ -137,7 +143,13 @@ async fn get_bill_balances_baseline() { // for company let res_comp = service - .get_bill_balances(&Currency::sat(), &company_node_id) + .get_bill_balances( + &Currency::sat(), + &BillParticipant::Ident(bill_identified_participant_only_node_id( + company_node_id.clone(), + )), + &company_keys, + ) .await; assert!(res_comp.is_ok()); assert_eq!( @@ -158,7 +170,8 @@ async fn get_bill_balances_baseline() { async fn get_search_bill() { let mut ctx = get_ctx(); let identity = get_baseline_identity(); - let company_node_id = NodeId::new(BcrKeys::new().pub_key(), bitcoin::Network::Testnet); + let company_keys = BcrKeys::new(); + let company_node_id = NodeId::new(company_keys.pub_key(), bitcoin::Network::Testnet); let mut bill1 = get_baseline_bill(&bill_id_test()); bill1.issue_date = Date::new("2020-05-01").unwrap(); @@ -217,7 +230,10 @@ async fn get_search_bill() { None, None, &BillsFilterRole::All, - &company_node_id, + &BillParticipant::Ident(bill_identified_participant_only_node_id( + company_node_id.clone(), + )), + &company_keys, ) .await; assert!(res_all_comp.is_ok()); @@ -229,7 +245,8 @@ async fn get_search_bill() { None, None, &BillsFilterRole::All, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, ) .await; assert!(res_all.is_ok()); @@ -242,7 +259,8 @@ async fn get_search_bill() { None, None, &BillsFilterRole::All, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, ) .await; assert!(res_term.is_ok()); @@ -257,7 +275,8 @@ async fn get_search_bill() { Some(from_ts), Some(to_ts), &BillsFilterRole::All, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, ) .await; assert!(res_fromto.is_ok()); @@ -270,7 +289,8 @@ async fn get_search_bill() { None, None, &BillsFilterRole::Payer, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, ) .await; assert!(res_role.is_ok()); @@ -283,7 +303,8 @@ async fn get_search_bill() { Some(from_ts), Some(to_ts), &BillsFilterRole::Payee, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, ) .await; assert!(res_comb.is_ok()); @@ -685,9 +706,13 @@ async fn get_bills_baseline() { }); let service = get_service(ctx); + let identity = get_baseline_identity(); let res = service - .get_bills(&get_baseline_identity().identity.node_id) + .get_bills( + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, + ) .await; assert!(res.is_ok()); let returned_bills = res.unwrap(); @@ -734,7 +759,10 @@ async fn get_bills_baseline_from_cache() { let service = get_service(ctx); let res = service - .get_bills(&get_baseline_identity().identity.node_id) + .get_bills( + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, + ) .await; assert!(res.is_ok()); let returned_bills = res.unwrap(); @@ -790,7 +818,10 @@ async fn get_bills_baseline_from_cache_with_payment_expiration() { let service = get_service(ctx); let res = service - .get_bills(&get_baseline_identity().identity.node_id) + .get_bills( + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, + ) .await; assert!(res.is_ok()); let returned_bills = res.unwrap(); @@ -800,7 +831,8 @@ async fn get_bills_baseline_from_cache_with_payment_expiration() { #[tokio::test] async fn get_bills_baseline_company() { let mut ctx = get_ctx(); - let company_node_id = NodeId::new(BcrKeys::new().pub_key(), bitcoin::Network::Testnet); + let company_keys = BcrKeys::new(); + let company_node_id = NodeId::new(company_keys.pub_key(), bitcoin::Network::Testnet); let mut bill = get_baseline_bill(&bill_id_test()); bill.payee = BillParticipant::Ident( BillIdentParticipant::new(get_baseline_identity().identity).unwrap(), @@ -823,15 +855,26 @@ async fn get_bills_baseline_company() { let service = get_service(ctx); + let identity = get_baseline_identity(); let res = service - .get_bills(&get_baseline_identity().identity.node_id) + .get_bills( + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, + ) .await; assert!(res.is_ok()); let returned_bills = res.unwrap(); assert!(returned_bills.len() == 1); assert_eq!(returned_bills[0].id, bill_id_test()); - let res = service.get_bills(&company_node_id).await; + let res = service + .get_bills( + &BillParticipant::Ident(bill_identified_participant_only_node_id( + company_node_id.clone(), + )), + &company_keys, + ) + .await; assert!(res.is_ok()); assert_eq!(res.as_ref().unwrap().len(), 0); } @@ -886,8 +929,12 @@ async fn get_bills_req_to_pay() { .returning(|_| HashMap::new()); }); + let identity = get_baseline_identity(); let res = get_service(ctx) - .get_bills(&get_baseline_identity().identity.node_id) + .get_bills( + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, + ) .await; assert!(res.is_ok()); let returned_bills = res.unwrap(); @@ -905,8 +952,12 @@ async fn get_bills_empty_for_no_bills() { .returning(|_| HashMap::new()); }); ctx.bill_store.expect_get_ids().returning(|| Ok(vec![])); + let identity = get_baseline_identity(); let res = get_service(ctx) - .get_bills(&get_baseline_identity().identity.node_id) + .get_bills( + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, + ) .await; assert!(res.is_ok()); assert!(res.unwrap().is_empty()); @@ -933,7 +984,8 @@ async fn get_detail_bill_baseline() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -990,7 +1042,8 @@ async fn get_detail_bill_baseline_from_cache() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -1046,7 +1099,8 @@ async fn get_detail_bill_baseline_from_cache_with_payment_expiration() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -1088,7 +1142,8 @@ async fn get_detail_bill_baseline_error_from_cache() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -1118,12 +1173,14 @@ async fn get_detail_bill_fails_for_non_participant() { .with(eq(bill_id_test())) .returning(|_| None); }); + let keys = BcrKeys::new(); let res = get_service(ctx) .get_detail( &bill_id_test(), &identity.identity, - &NodeId::new(BcrKeys::new().pub_key(), bitcoin::Network::Testnet), + &bill_participant_only_node_id(NodeId::new(keys.pub_key(), bitcoin::Network::Testnet)), + &keys, test_ts(), ) .await; @@ -1160,7 +1217,8 @@ async fn get_detail_waiting_for_offer_to_sell() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -1222,7 +1280,8 @@ async fn get_detail_waiting_for_offer_to_sell_and_sell() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -1282,7 +1341,8 @@ async fn get_detail_waiting_for_offer_to_sell_and_expire() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, now, ) .await; @@ -1349,7 +1409,8 @@ async fn get_detail_waiting_for_offer_to_sell_and_reject() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, now, ) .await; @@ -1398,7 +1459,8 @@ async fn get_detail_bill_req_to_recourse() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -1473,7 +1535,8 @@ async fn get_detail_bill_req_to_recourse_recoursed() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -1539,7 +1602,8 @@ async fn get_detail_bill_req_to_recourse_rejected() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -1601,7 +1665,8 @@ async fn get_detail_bill_req_to_recourse_expired() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, now, ) .await; @@ -1658,7 +1723,8 @@ async fn get_detail_bill_req_to_pay() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -1710,7 +1776,8 @@ async fn get_detail_bill_req_to_pay_paid() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -1767,7 +1834,8 @@ async fn get_detail_bill_req_to_pay_rejected() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -1823,7 +1891,8 @@ async fn get_detail_bill_req_to_pay_rejected_but_paid() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -1880,7 +1949,8 @@ async fn get_detail_bill_req_to_pay_expired() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, now, ) .await; @@ -1936,7 +2006,8 @@ async fn get_detail_bill_req_to_pay_expired_but_paid() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, now, ) .await; @@ -1988,7 +2059,8 @@ async fn get_detail_bill_req_to_accept() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -2040,7 +2112,8 @@ async fn get_detail_bill_req_to_accept_accepted() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -2096,7 +2169,8 @@ async fn get_detail_bill_req_to_accept_rejected() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, now, ) .await; @@ -2151,7 +2225,8 @@ async fn get_detail_bill_req_to_accept_expired() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, now, ) .await; @@ -3354,7 +3429,8 @@ async fn endorse_bitcredit_bill_multiple_back_and_forth() { .get_detail( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, current_timestamp, ) .await; @@ -3376,7 +3452,8 @@ async fn endorse_bitcredit_bill_multiple_back_and_forth() { .get_endorsements( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -3927,7 +4004,8 @@ async fn get_endorsements_baseline() { .get_endorsements( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -4002,6 +4080,30 @@ async fn get_endorsements_multi_with_anon() { .unwrap(); assert!(chain.try_add_block(endorse_block)); + // add offer to sell block from endorsee to sell endorsee + let offer_to_sell_block = BillBlock::create_block_for_offer_to_sell( + bill_id_test(), + chain.get_latest_block(), + &BillOfferToSellBlockData { + buyer: BillParticipantBlockData::Ident(sell_endorsee.clone().into()), + // endorsed by endorsee + seller: BillParticipantBlockData::Anon(endorse_endorsee.clone().into()), + sum: Sum::new_sat(15000).expect("sat works"), + payment_address: valid_payment_address_testnet(), + signatory: None, + signing_timestamp: now + 2, + signing_address: Some(empty_address()), + signer_identity_proof: Some(signed_identity_proof_test().into()), + buying_deadline_timestamp: now + 1000, + }, + &BcrKeys::from_private_key(&private_key_test()), + Some(&BcrKeys::from_private_key(&private_key_test())), + &BcrKeys::from_private_key(&private_key_test()), + now + 2, + ) + .unwrap(); + assert!(chain.try_add_block(offer_to_sell_block)); + // add sell block from endorsee to sell endorsee let sell_block = BillBlock::create_block_for_sell( bill_id_test(), @@ -4013,14 +4115,14 @@ async fn get_endorsements_multi_with_anon() { sum: Sum::new_sat(15000).expect("sat works"), payment_address: valid_payment_address_testnet(), signatory: None, - signing_timestamp: now + 2, + signing_timestamp: now + 3, signing_address: Some(empty_address()), signer_identity_proof: Some(signed_identity_proof_test().into()), }, &BcrKeys::from_private_key(&private_key_test()), Some(&BcrKeys::from_private_key(&private_key_test())), &BcrKeys::from_private_key(&private_key_test()), - now + 2, + now + 3, ) .unwrap(); assert!(chain.try_add_block(sell_block)); @@ -4035,14 +4137,14 @@ async fn get_endorsements_multi_with_anon() { endorser: BillParticipantBlockData::Ident(sell_endorsee.clone().into()), sum: Sum::new_sat(15000).expect("sat works"), signatory: None, - signing_timestamp: now + 3, + signing_timestamp: now + 4, signing_address: Some(empty_address()), signer_identity_proof: Some(signed_identity_proof_test().into()), }, &BcrKeys::from_private_key(&private_key_test()), Some(&BcrKeys::from_private_key(&private_key_test())), &BcrKeys::from_private_key(&private_key_test()), - now + 3, + now + 4, ) .unwrap(); assert!(chain.try_add_block(mint_block)); @@ -4056,7 +4158,8 @@ async fn get_endorsements_multi_with_anon() { .get_endorsements( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -4143,6 +4246,29 @@ async fn get_endorsements_multi() { .unwrap(); assert!(chain.try_add_block(endorse_block)); + // add offer to sell block from endorsee to sell endorsee + let offer_to_sell_block = BillBlock::create_block_for_offer_to_sell( + bill_id_test(), + chain.get_latest_block(), + &BillOfferToSellBlockData { + buyer: BillParticipantBlockData::Ident(sell_endorsee.clone().into()), + // endorsed by endorsee + seller: BillParticipantBlockData::Ident(endorse_endorsee.clone().into()), + sum: Sum::new_sat(15000).expect("sat works"), + payment_address: valid_payment_address_testnet(), + signatory: None, + signing_timestamp: now + 2, + signing_address: Some(empty_address()), + signer_identity_proof: Some(signed_identity_proof_test().into()), + buying_deadline_timestamp: now + 1000, + }, + &BcrKeys::from_private_key(&private_key_test()), + Some(&BcrKeys::from_private_key(&private_key_test())), + &BcrKeys::from_private_key(&private_key_test()), + now + 2, + ) + .unwrap(); + assert!(chain.try_add_block(offer_to_sell_block)); // add sell block from endorsee to sell endorsee let sell_block = BillBlock::create_block_for_sell( bill_id_test(), @@ -4154,14 +4280,14 @@ async fn get_endorsements_multi() { sum: Sum::new_sat(15000).expect("sat works"), payment_address: valid_payment_address_testnet(), signatory: None, - signing_timestamp: now + 2, + signing_timestamp: now + 3, signing_address: Some(empty_address()), signer_identity_proof: Some(signed_identity_proof_test().into()), }, &BcrKeys::from_private_key(&private_key_test()), Some(&BcrKeys::from_private_key(&private_key_test())), &BcrKeys::from_private_key(&private_key_test()), - now + 2, + now + 3, ) .unwrap(); assert!(chain.try_add_block(sell_block)); @@ -4176,14 +4302,14 @@ async fn get_endorsements_multi() { endorser: BillParticipantBlockData::Ident(sell_endorsee.clone().into()), sum: Sum::new_sat(15000).expect("sat works"), signatory: None, - signing_timestamp: now + 3, + signing_timestamp: now + 4, signing_address: Some(empty_address()), signer_identity_proof: Some(signed_identity_proof_test().into()), }, &BcrKeys::from_private_key(&private_key_test()), Some(&BcrKeys::from_private_key(&private_key_test())), &BcrKeys::from_private_key(&private_key_test()), - now + 3, + now + 4, ) .unwrap(); assert!(chain.try_add_block(mint_block)); @@ -4197,7 +4323,8 @@ async fn get_endorsements_multi() { .get_endorsements( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; @@ -4862,25 +4989,25 @@ async fn past_payments_baseline() { assert_eq!(res_past_payments.as_ref().unwrap().len(), 4); match res_past_payments.as_ref().unwrap()[0] { PastPaymentResult::Payment(ref data) => { - assert!(matches!(data.status, PastPaymentStatus::Paid(_))); + assert!(matches!(data.status, PaymentStatus::Paid(_))); } _ => panic!("wrong result"), }; match res_past_payments.as_ref().unwrap()[1] { PastPaymentResult::Sell(ref data) => { - assert!(matches!(data.status, PastPaymentStatus::Paid(_))); + assert!(matches!(data.status, PaymentStatus::Paid(_))); } _ => panic!("wrong result"), }; match res_past_payments.as_ref().unwrap()[2] { PastPaymentResult::Sell(ref data) => { - assert!(matches!(data.status, PastPaymentStatus::Rejected(_))); + assert!(matches!(data.status, PaymentStatus::Rejected(_))); } _ => panic!("wrong result"), }; match res_past_payments.as_ref().unwrap()[3] { PastPaymentResult::Sell(ref data) => { - assert!(matches!(data.status, PastPaymentStatus::Expired(_))); + assert!(matches!(data.status, PaymentStatus::Expired(_))); } _ => panic!("wrong result"), }; @@ -4970,25 +5097,25 @@ async fn past_payments_recourse() { assert_eq!(res_past_payments.as_ref().unwrap().len(), 4); match res_past_payments.as_ref().unwrap()[0] { PastPaymentResult::Payment(ref data) => { - assert!(matches!(data.status, PastPaymentStatus::Rejected(_))); + assert!(matches!(data.status, PaymentStatus::Rejected(_))); } _ => panic!("wrong result"), }; match res_past_payments.as_ref().unwrap()[1] { PastPaymentResult::Recourse(ref data) => { - assert!(matches!(data.status, PastPaymentStatus::Paid(_))); + assert!(matches!(data.status, PaymentStatus::Paid(_))); } _ => panic!("wrong result"), }; match res_past_payments.as_ref().unwrap()[2] { PastPaymentResult::Recourse(ref data) => { - assert!(matches!(data.status, PastPaymentStatus::Rejected(_))); + assert!(matches!(data.status, PaymentStatus::Rejected(_))); } _ => panic!("wrong result"), }; match res_past_payments.as_ref().unwrap()[3] { PastPaymentResult::Recourse(ref data) => { - assert!(matches!(data.status, PastPaymentStatus::Expired(_))); + assert!(matches!(data.status, PaymentStatus::Expired(_))); } _ => panic!("wrong result"), }; @@ -7031,7 +7158,8 @@ async fn wrong_network_failures() { .get_detail( &mainnet_bill_id, &identity.identity, - &node_id_test(), + &participant, + &BcrKeys::new(), test_ts() ) .await, @@ -7044,7 +7172,8 @@ async fn wrong_network_failures() { .get_detail( &bill_id_test(), &identity.identity, - &mainnet_node_id, + &mainnet_participant, + &BcrKeys::new(), test_ts() ) .await, @@ -7125,7 +7254,8 @@ async fn wrong_network_failures() { .get_endorsements( &mainnet_bill_id, &identity.identity, - &node_id_test(), + &participant, + &BcrKeys::new(), test_ts() ) .await, @@ -7138,7 +7268,8 @@ async fn wrong_network_failures() { .get_endorsements( &bill_id_test(), &identity.identity, - &mainnet_node_id, + &mainnet_participant, + &BcrKeys::new(), test_ts() ) .await, @@ -7400,7 +7531,8 @@ async fn get_bill_history_baseline() { .get_bill_history( &bill_id_test(), &identity.identity, - &identity.identity.node_id, + &BillParticipant::Ident(BillIdentParticipant::new(identity.identity.clone()).unwrap()), + &identity.key_pair, test_ts(), ) .await; diff --git a/crates/bcr-ebill-api/src/service/search_service.rs b/crates/bcr-ebill-api/src/service/search_service.rs index be352273..06cfa846 100644 --- a/crates/bcr-ebill-api/src/service/search_service.rs +++ b/crates/bcr-ebill-api/src/service/search_service.rs @@ -6,9 +6,10 @@ use super::{ contact_service::ContactServiceApi, }; use async_trait::async_trait; -use bcr_common::core::NodeId; use bcr_ebill_core::application::bill::BillsFilterRole; use bcr_ebill_core::protocol::Currency; +use bcr_ebill_core::protocol::blockchain::bill::participant::BillParticipant; +use bcr_ebill_core::protocol::crypto::BcrKeys; use log::debug; use std::sync::Arc; @@ -25,7 +26,8 @@ pub trait SearchServiceApi: ServiceTraitBounds { search_term: &str, currency: &Currency, item_types: &[GeneralSearchFilterItemType], - current_identity_node_id: &NodeId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, ) -> Result; } @@ -61,9 +63,10 @@ impl SearchServiceApi for SearchService { search_term: &str, currency: &Currency, item_types: &[GeneralSearchFilterItemType], - current_identity_node_id: &NodeId, + caller_public_data: &BillParticipant, + caller_keys: &BcrKeys, ) -> Result { - validate_node_id_network(current_identity_node_id)?; + validate_node_id_network(&caller_public_data.node_id())?; debug!("search for {search_term}, with {currency} and {item_types:?}"); let search_term_lc = search_term.to_lowercase(); let bills = if item_types.contains(&GeneralSearchFilterItemType::Bill) { @@ -74,7 +77,8 @@ impl SearchServiceApi for SearchService { None, None, &BillsFilterRole::All, - current_identity_node_id, + caller_public_data, + caller_keys, ) .await? } else { diff --git a/crates/bcr-ebill-core/src/application/bill/mod.rs b/crates/bcr-ebill-core/src/application/bill/mod.rs index ba4cc36a..53d3b8d0 100644 --- a/crates/bcr-ebill-core/src/application/bill/mod.rs +++ b/crates/bcr-ebill-core/src/application/bill/mod.rs @@ -5,7 +5,7 @@ use super::{ use crate::protocol::{ BitcoinAddress, City, Country, Date, File, PostalAddress, Sum, Timestamp, blockchain::bill::{ - BillHistory, BillOpCode, ContactType, PastPaymentStatus, + BillHistory, BillOpCode, ContactType, PaymentStatus, participant::{BillIdentParticipant, BillParticipant, SignedBy}, }, }; @@ -53,6 +53,48 @@ impl BillCallerBillAction { } } +/// Possible Bill Payment Actions a caller can do on a bill +#[derive(Debug, Clone)] +pub enum BillCallerPaymentAction { + Pay(BillCallerPayment), + CheckPayment(BillCallerPayment), +} + +#[derive(Debug, Clone)] +pub enum BillCallerPayment { + Sell { + buyer: BillParticipant, + seller: BillParticipant, + state: BillCallerPaymentState, + }, + Payment { + payer: BillIdentParticipant, + payee: BillParticipant, + state: BillCallerPaymentState, + }, + Recourse { + recourser: BillParticipant, + recoursee: BillIdentParticipant, + state: BillCallerPaymentState, + }, +} + +#[derive(Debug, Clone)] +pub struct BillCallerPaymentState { + pub time_of_request: Timestamp, + pub sum: Sum, + pub link_to_pay: String, + pub address_to_pay: BitcoinAddress, + pub mempool_link_for_address_to_pay: String, + pub status: PaymentStatus, + pub payment_deadline: Timestamp, + pub tx_id: Option, + pub in_mempool: bool, + pub confirmations: u64, + // only set if we're receiver + pub private_descriptor_to_spend: Option, +} + #[repr(u8)] #[derive(Debug, Clone, serde_repr::Serialize_repr, serde_repr::Deserialize_repr, PartialEq, Eq)] pub enum BillType { @@ -67,12 +109,16 @@ pub struct BitcreditBillResult { pub id: BillId, pub participants: BillParticipants, pub data: BillData, + /* Marked for deprecation */ pub status: BillStatus, + pub state: BillState, + /* Marked for deprecation */ pub current_waiting_state: Option, pub history: BillHistory, pub actions: BillCallerActions, } +/* Marked for deprecation */ #[derive(Debug, Clone, PartialEq, Eq)] pub enum BillCurrentWaitingState { Sell(BillWaitingForSellState), @@ -80,6 +126,7 @@ pub enum BillCurrentWaitingState { Recourse(BillWaitingForRecourseState), } +/* Marked for deprecation */ #[derive(Debug, Clone, PartialEq, Eq)] pub struct BillWaitingForSellState { pub buyer: BillParticipant, @@ -87,6 +134,7 @@ pub struct BillWaitingForSellState { pub payment_data: BillWaitingStatePaymentData, } +/* Marked for deprecation */ #[derive(Debug, Clone, PartialEq, Eq)] pub struct BillWaitingForPaymentState { pub payer: BillIdentParticipant, @@ -94,6 +142,7 @@ pub struct BillWaitingForPaymentState { pub payment_data: BillWaitingStatePaymentData, } +/* Marked for deprecation */ #[derive(Debug, Clone, PartialEq, Eq)] pub struct BillWaitingForRecourseState { pub recourser: BillParticipant, @@ -101,6 +150,7 @@ pub struct BillWaitingForRecourseState { pub payment_data: BillWaitingStatePaymentData, } +/* Marked for deprecation */ #[derive(Debug, Clone, PartialEq, Eq)] pub struct BillWaitingStatePaymentData { pub time_of_request: Timestamp, @@ -114,18 +164,51 @@ pub struct BillWaitingStatePaymentData { pub payment_deadline: Option, } +/* Marked for deprecation */ #[derive(Debug, Clone)] pub struct BillStatus { pub acceptance: BillAcceptanceStatus, pub payment: BillPaymentStatus, pub sell: BillSellStatus, pub recourse: BillRecourseStatus, - pub mint: BillMintStatus, pub redeemed_funds_available: bool, pub has_requested_funds: bool, pub last_block_time: Timestamp, + pub mint: BillMintStatus, +} + +#[derive(Debug, Clone)] +pub struct BillState { + pub mint: BillMintState, + pub accept: BillAcceptState, + pub payment: BillPaymentState, +} + +#[derive(Debug, Clone)] +pub enum BillAcceptState { + None, + Requested(Timestamp), + Accepted(Timestamp), + Expired(Timestamp), + Rejected(Timestamp), +} + +#[derive(Debug, Clone)] +pub enum BillPaymentState { + None, + Requested(Timestamp), + Paid(Timestamp), + Expired(Timestamp), + Rejected(Timestamp), +} + +#[derive(Debug, Clone)] +pub enum BillMintState { + None, + Requested, } +/* Marked for deprecation */ #[derive(Debug, Clone)] pub struct BillAcceptanceStatus { pub time_of_request_to_accept: Option, @@ -136,6 +219,7 @@ pub struct BillAcceptanceStatus { pub acceptance_deadline_timestamp: Option, } +/* Marked for deprecation */ #[derive(Debug, Clone)] pub struct BillPaymentStatus { pub time_of_request_to_pay: Option, @@ -146,6 +230,7 @@ pub struct BillPaymentStatus { pub payment_deadline_timestamp: Option, } +/* Marked for deprecation */ #[derive(Debug, Clone)] pub struct BillSellStatus { pub time_of_last_offer_to_sell: Option, @@ -156,6 +241,7 @@ pub struct BillSellStatus { pub buying_deadline_timestamp: Option, } +/* Marked for deprecation */ #[derive(Debug, Clone)] pub struct BillRecourseStatus { pub time_of_last_request_to_recourse: Option, @@ -202,6 +288,7 @@ pub struct BillParticipants { pub struct BillCallerActions { /// Actions that concern the bill chain directly - e.g. Accept etc. pub bill_actions: Vec, + pub payment_actions: Vec, } impl BillHistory { @@ -452,7 +539,7 @@ pub struct PastPaymentDataSell { pub address_to_pay: BitcoinAddress, pub private_descriptor_to_spend: String, pub mempool_link_for_address_to_pay: String, - pub status: PastPaymentStatus, + pub status: PaymentStatus, pub payment_deadline: Timestamp, } @@ -466,7 +553,7 @@ pub struct PastPaymentDataPayment { pub address_to_pay: BitcoinAddress, pub private_descriptor_to_spend: String, pub mempool_link_for_address_to_pay: String, - pub status: PastPaymentStatus, + pub status: PaymentStatus, pub payment_deadline: Timestamp, } @@ -480,7 +567,7 @@ pub struct PastPaymentDataRecourse { pub address_to_pay: BitcoinAddress, pub private_descriptor_to_spend: String, pub mempool_link_for_address_to_pay: String, - pub status: PastPaymentStatus, + pub status: PaymentStatus, pub payment_deadline: Timestamp, } diff --git a/crates/bcr-ebill-core/src/protocol/blockchain/bill/chain.rs b/crates/bcr-ebill-core/src/protocol/blockchain/bill/chain.rs index 6787ccc6..e1ee1b52 100644 --- a/crates/bcr-ebill-core/src/protocol/blockchain/bill/chain.rs +++ b/crates/bcr-ebill-core/src/protocol/blockchain/bill/chain.rs @@ -16,7 +16,7 @@ use crate::protocol::blockchain::bill::participant::{ BillParticipant, BillSignatory, PastEndorsee, SignedBy, }; use crate::protocol::blockchain::bill::validation::get_expiration_deadline_base_for_req_to_pay; -use crate::protocol::blockchain::bill::{BillHistory, BillHistoryBlock, PastPaymentStatus}; +use crate::protocol::blockchain::bill::{BillHistory, BillHistoryBlock, PaymentStatus}; use crate::protocol::blockchain::{Block, Blockchain, Error, borsh_to_json_value}; use crate::protocol::crypto::BcrKeys; use bcr_common::core::NodeId; @@ -355,7 +355,7 @@ impl BillBlockchain { bill_keys: &BcrKeys, node_id: &NodeId, timestamp: Timestamp, - ) -> Result> { + ) -> Result> { let mut result = vec![]; let blocks = self.blocks(); let mut sell_pairs: Vec<(BillBlock, Option)> = vec![]; @@ -426,14 +426,14 @@ impl BillBlockchain { BillOpCode::RejectToBuy => { result.push(( payment_info, - PastPaymentStatus::Rejected(reject_or_sell_block.timestamp), + PaymentStatus::Rejected(reject_or_sell_block.timestamp), offer_to_sell_block.timestamp, )); } BillOpCode::Sell => { result.push(( payment_info, - PastPaymentStatus::Paid(reject_or_sell_block.timestamp), + PaymentStatus::Paid(reject_or_sell_block.timestamp), offer_to_sell_block.timestamp, )); } @@ -446,9 +446,7 @@ impl BillBlockchain { { result.push(( payment_info, - PastPaymentStatus::Expired( - block_data_decrypted.buying_deadline_timestamp, - ), + PaymentStatus::Expired(block_data_decrypted.buying_deadline_timestamp), offer_to_sell_block.timestamp, )); } @@ -465,7 +463,7 @@ impl BillBlockchain { bill_keys: &BcrKeys, node_id: &NodeId, timestamp: Timestamp, - ) -> Result> { + ) -> Result> { let mut result = vec![]; let blocks = self.blocks(); let mut recourse_pairs: Vec<(BillBlock, Option)> = vec![]; @@ -536,14 +534,14 @@ impl BillBlockchain { BillOpCode::RejectToPayRecourse => { result.push(( payment_info, - PastPaymentStatus::Rejected(reject_or_recourse_block.timestamp), + PaymentStatus::Rejected(reject_or_recourse_block.timestamp), request_to_recourse_block.timestamp, )); } BillOpCode::Recourse => { result.push(( payment_info, - PastPaymentStatus::Paid(reject_or_recourse_block.timestamp), + PaymentStatus::Paid(reject_or_recourse_block.timestamp), request_to_recourse_block.timestamp, )); } @@ -556,7 +554,7 @@ impl BillBlockchain { { result.push(( payment_info, - PastPaymentStatus::Expired( + PaymentStatus::Expired( block_data_decrypted.recourse_deadline_timestamp, ), request_to_recourse_block.timestamp, diff --git a/crates/bcr-ebill-core/src/protocol/blockchain/bill/mod.rs b/crates/bcr-ebill-core/src/protocol/blockchain/bill/mod.rs index d17555c2..017196ce 100644 --- a/crates/bcr-ebill-core/src/protocol/blockchain/bill/mod.rs +++ b/crates/bcr-ebill-core/src/protocol/blockchain/bill/mod.rs @@ -86,10 +86,11 @@ pub struct RecoursePaymentInfo { } #[derive(Debug, Clone)] -pub enum PastPaymentStatus { - Paid(Timestamp), // timestamp - Rejected(Timestamp), // timestamp - Expired(Timestamp), // timestamp +pub enum PaymentStatus { + Requested(Timestamp), + Paid(Timestamp), + Rejected(Timestamp), + Expired(Timestamp), } #[derive(BorshSerialize, BorshDeserialize, Serialize, Deserialize, Debug, Clone)] diff --git a/crates/bcr-ebill-persistence/src/db/bill.rs b/crates/bcr-ebill-persistence/src/db/bill.rs index 27c1efba..8ca6020e 100644 --- a/crates/bcr-ebill-persistence/src/db/bill.rs +++ b/crates/bcr-ebill-persistence/src/db/bill.rs @@ -8,11 +8,12 @@ use async_trait::async_trait; use bcr_common::core::{BillId, NodeId}; use bcr_ebill_core::application::ServiceTraitBounds; use bcr_ebill_core::application::bill::{ - BillAcceptanceStatus, BillCallerActions, BillCallerBillAction, BillCurrentWaitingState, - BillData, BillMintStatus, BillParticipants, BillPaymentStatus, BillRecourseStatus, - BillSellStatus, BillStatus, BillWaitingForPaymentState, BillWaitingForRecourseState, - BillWaitingForSellState, BillWaitingStatePaymentData, BitcreditBillResult, Endorsement, - InMempoolData, LightSignedBy, PaidData, PaymentState, + BillAcceptState, BillAcceptanceStatus, BillCallerActions, BillCallerBillAction, + BillCallerPayment, BillCallerPaymentAction, BillCallerPaymentState, BillCurrentWaitingState, + BillData, BillMintState, BillMintStatus, BillParticipants, BillPaymentState, BillPaymentStatus, + BillRecourseStatus, BillSellStatus, BillState, BillStatus, BillWaitingForPaymentState, + BillWaitingForRecourseState, BillWaitingForSellState, BillWaitingStatePaymentData, + BitcreditBillResult, Endorsement, InMempoolData, LightSignedBy, PaidData, PaymentState, }; use bcr_ebill_core::application::contact::{ LightBillAnonParticipant, LightBillIdentParticipant, LightBillIdentParticipantWithAddress, @@ -28,7 +29,7 @@ use bcr_ebill_core::protocol::Timestamp; use bcr_ebill_core::protocol::blockchain::bill::participant::{ BillAnonParticipant, BillIdentParticipant, BillParticipant, BillSignatory, SignedBy, }; -use bcr_ebill_core::protocol::blockchain::bill::{BillHistory, BillHistoryBlock}; +use bcr_ebill_core::protocol::blockchain::bill::{BillHistory, BillHistoryBlock, PaymentStatus}; use bcr_ebill_core::protocol::blockchain::bill::{BillOpCode, ContactType}; use bcr_ebill_core::protocol::crypto::BcrKeys; use bcr_ebill_core::protocol::{BitcoinAddress, SecretKey}; @@ -379,6 +380,7 @@ pub struct BitcreditBillResultDb { pub participants: BillParticipantsDb, pub data: BillDataDb, pub status: BillStatusDb, + pub state: BillStateDb, pub current_waiting_state: Option, pub history: BillHistoryDb, pub actions: BillCallerActionsDb, @@ -392,6 +394,7 @@ impl From for BitcreditBillResult { participants: value.participants.into(), data: value.data.into(), status: value.status.into(), + state: value.state.into(), current_waiting_state: value.current_waiting_state.map(|cws| cws.into()), history: value.history.into(), actions: value.actions.into(), @@ -406,9 +409,10 @@ impl From<(&BitcreditBillResult, &NodeId)> for BitcreditBillResultDb { participants: (&value.participants).into(), data: (&value.data).into(), status: (&value.status).into(), + state: (&value.state).into(), current_waiting_state: value.current_waiting_state.as_ref().map(|cws| cws.into()), history: value.history.clone().into(), - actions: value.actions.clone().into(), + actions: (&value.actions).into(), identity_node_id: identity_node_id.to_owned(), } } @@ -617,6 +621,133 @@ impl From<&BillStatus> for BillStatusDb { } } +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct BillStateDb { + pub mint: BillMintStateDb, + pub accept: BillAcceptStateDb, + pub payment: BillPaymentStateDb, +} + +impl From for BillState { + fn from(value: BillStateDb) -> Self { + Self { + mint: value.mint.into(), + accept: value.accept.into(), + payment: value.payment.into(), + } + } +} + +impl From<&BillState> for BillStateDb { + fn from(value: &BillState) -> Self { + Self { + mint: (&value.mint).into(), + accept: (&value.accept).into(), + payment: (&value.payment).into(), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum BillAcceptStateDb { + None, + Requested(Timestamp), + Accepted(Timestamp), + Expired(Timestamp), + Rejected(Timestamp), +} + +impl From for BillAcceptState { + fn from(value: BillAcceptStateDb) -> Self { + match value { + BillAcceptStateDb::None => BillAcceptState::None, + BillAcceptStateDb::Requested(timestamp) => BillAcceptState::Requested(timestamp), + BillAcceptStateDb::Accepted(timestamp) => BillAcceptState::Accepted(timestamp), + BillAcceptStateDb::Expired(timestamp) => BillAcceptState::Expired(timestamp), + BillAcceptStateDb::Rejected(timestamp) => BillAcceptState::Rejected(timestamp), + } + } +} + +impl From<&BillAcceptState> for BillAcceptStateDb { + fn from(value: &BillAcceptState) -> Self { + match value { + BillAcceptState::None => BillAcceptStateDb::None, + BillAcceptState::Requested(timestamp) => { + BillAcceptStateDb::Requested(timestamp.to_owned()) + } + BillAcceptState::Accepted(timestamp) => { + BillAcceptStateDb::Accepted(timestamp.to_owned()) + } + BillAcceptState::Expired(timestamp) => BillAcceptStateDb::Expired(timestamp.to_owned()), + BillAcceptState::Rejected(timestamp) => { + BillAcceptStateDb::Rejected(timestamp.to_owned()) + } + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum BillPaymentStateDb { + None, + Requested(Timestamp), + Paid(Timestamp), + Expired(Timestamp), + Rejected(Timestamp), +} + +impl From for BillPaymentState { + fn from(value: BillPaymentStateDb) -> Self { + match value { + BillPaymentStateDb::None => BillPaymentState::None, + BillPaymentStateDb::Requested(timestamp) => BillPaymentState::Requested(timestamp), + BillPaymentStateDb::Paid(timestamp) => BillPaymentState::Paid(timestamp), + BillPaymentStateDb::Expired(timestamp) => BillPaymentState::Expired(timestamp), + BillPaymentStateDb::Rejected(timestamp) => BillPaymentState::Rejected(timestamp), + } + } +} + +impl From<&BillPaymentState> for BillPaymentStateDb { + fn from(value: &BillPaymentState) -> Self { + match value { + BillPaymentState::None => BillPaymentStateDb::None, + BillPaymentState::Requested(timestamp) => { + BillPaymentStateDb::Requested(timestamp.to_owned()) + } + BillPaymentState::Paid(timestamp) => BillPaymentStateDb::Paid(timestamp.to_owned()), + BillPaymentState::Expired(timestamp) => { + BillPaymentStateDb::Expired(timestamp.to_owned()) + } + BillPaymentState::Rejected(timestamp) => { + BillPaymentStateDb::Rejected(timestamp.to_owned()) + } + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum BillMintStateDb { + None, + Requested, +} +impl From for BillMintState { + fn from(value: BillMintStateDb) -> Self { + match value { + BillMintStateDb::None => BillMintState::None, + BillMintStateDb::Requested => BillMintState::Requested, + } + } +} +impl From<&BillMintState> for BillMintStateDb { + fn from(value: &BillMintState) -> Self { + match value { + BillMintState::None => BillMintStateDb::None, + BillMintState::Requested => BillMintStateDb::Requested, + } + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct BillAcceptanceStatusDb { pub time_of_request_to_accept: Option, @@ -898,20 +1029,230 @@ impl From for BillHistoryDb { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct BillCallerActionsDb { pub bill_actions: Vec, + pub payment_actions: Vec, } impl From for BillCallerActions { fn from(value: BillCallerActionsDb) -> Self { Self { bill_actions: value.bill_actions, + payment_actions: value + .payment_actions + .into_iter() + .map(|b| b.into()) + .collect(), } } } -impl From for BillCallerActionsDb { - fn from(value: BillCallerActions) -> Self { +impl From<&BillCallerActions> for BillCallerActionsDb { + fn from(value: &BillCallerActions) -> Self { Self { - bill_actions: value.bill_actions, + bill_actions: value.bill_actions.to_owned(), + payment_actions: value.payment_actions.iter().map(|b| b.into()).collect(), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum BillCallerPaymentActionDb { + Pay(BillCallerPaymentDb), + CheckPayment(BillCallerPaymentDb), +} + +impl From for BillCallerPaymentAction { + fn from(value: BillCallerPaymentActionDb) -> Self { + match value { + BillCallerPaymentActionDb::Pay(bill_caller_payment_db) => { + BillCallerPaymentAction::Pay(bill_caller_payment_db.into()) + } + BillCallerPaymentActionDb::CheckPayment(bill_caller_payment_db) => { + BillCallerPaymentAction::CheckPayment(bill_caller_payment_db.into()) + } + } + } +} + +impl From<&BillCallerPaymentAction> for BillCallerPaymentActionDb { + fn from(value: &BillCallerPaymentAction) -> Self { + match value { + BillCallerPaymentAction::Pay(bill_caller_payment_db) => { + BillCallerPaymentActionDb::Pay(bill_caller_payment_db.into()) + } + BillCallerPaymentAction::CheckPayment(bill_caller_payment_db) => { + BillCallerPaymentActionDb::CheckPayment(bill_caller_payment_db.into()) + } + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum BillCallerPaymentDb { + Sell { + buyer: BillParticipantDb, + seller: BillParticipantDb, + state: BillCallerPaymentStateDb, + }, + Payment { + payer: BillIdentParticipantDb, + payee: BillParticipantDb, + state: BillCallerPaymentStateDb, + }, + Recourse { + recourser: BillParticipantDb, + recoursee: BillIdentParticipantDb, + state: BillCallerPaymentStateDb, + }, +} + +impl From for BillCallerPayment { + fn from(value: BillCallerPaymentDb) -> Self { + match value { + BillCallerPaymentDb::Sell { + buyer, + seller, + state, + } => BillCallerPayment::Sell { + buyer: buyer.into(), + seller: seller.into(), + state: state.into(), + }, + BillCallerPaymentDb::Payment { + payer, + payee, + state, + } => BillCallerPayment::Payment { + payer: payer.into(), + payee: payee.into(), + state: state.into(), + }, + BillCallerPaymentDb::Recourse { + recourser, + recoursee, + state, + } => BillCallerPayment::Recourse { + recourser: recourser.into(), + recoursee: recoursee.into(), + state: state.into(), + }, + } + } +} + +impl From<&BillCallerPayment> for BillCallerPaymentDb { + fn from(value: &BillCallerPayment) -> Self { + match value { + BillCallerPayment::Sell { + buyer, + seller, + state, + } => BillCallerPaymentDb::Sell { + buyer: buyer.into(), + seller: seller.into(), + state: state.into(), + }, + BillCallerPayment::Payment { + payer, + payee, + state, + } => BillCallerPaymentDb::Payment { + payer: payer.into(), + payee: payee.into(), + state: state.into(), + }, + BillCallerPayment::Recourse { + recourser, + recoursee, + state, + } => BillCallerPaymentDb::Recourse { + recourser: recourser.into(), + recoursee: recoursee.into(), + state: state.into(), + }, + } + } +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct BillCallerPaymentStateDb { + pub time_of_request: Timestamp, + pub sum: Sum, + pub link_to_pay: String, + pub address_to_pay: BitcoinAddress, + pub private_descriptor_to_spend: Option, + pub mempool_link_for_address_to_pay: String, + pub status: PaymentStatusDb, + pub payment_deadline: Timestamp, + pub tx_id: Option, + pub in_mempool: bool, + pub confirmations: u64, +} + +impl From for BillCallerPaymentState { + fn from(value: BillCallerPaymentStateDb) -> Self { + Self { + time_of_request: value.time_of_request, + sum: value.sum, + link_to_pay: value.link_to_pay, + address_to_pay: value.address_to_pay, + private_descriptor_to_spend: value.private_descriptor_to_spend, + mempool_link_for_address_to_pay: value.mempool_link_for_address_to_pay, + status: value.status.into(), + payment_deadline: value.payment_deadline, + tx_id: value.tx_id, + in_mempool: value.in_mempool, + confirmations: value.confirmations, + } + } +} + +impl From<&BillCallerPaymentState> for BillCallerPaymentStateDb { + fn from(value: &BillCallerPaymentState) -> Self { + Self { + time_of_request: value.time_of_request, + sum: value.sum.to_owned(), + link_to_pay: value.link_to_pay.to_owned(), + address_to_pay: value.address_to_pay.to_owned(), + private_descriptor_to_spend: value + .private_descriptor_to_spend + .as_ref() + .map(|pd| pd.to_owned()), + mempool_link_for_address_to_pay: value.mempool_link_for_address_to_pay.to_owned(), + status: (&value.status).into(), + payment_deadline: value.payment_deadline, + tx_id: value.tx_id.as_ref().map(|tx| tx.to_owned()), + in_mempool: value.in_mempool, + confirmations: value.confirmations, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum PaymentStatusDb { + Requested(Timestamp), + Paid(Timestamp), + Rejected(Timestamp), + Expired(Timestamp), +} + +impl From for PaymentStatus { + fn from(value: PaymentStatusDb) -> Self { + match value { + PaymentStatusDb::Requested(timestamp) => PaymentStatus::Requested(timestamp), + PaymentStatusDb::Paid(timestamp) => PaymentStatus::Paid(timestamp), + PaymentStatusDb::Rejected(timestamp) => PaymentStatus::Rejected(timestamp), + PaymentStatusDb::Expired(timestamp) => PaymentStatus::Expired(timestamp), + } + } +} + +impl From<&PaymentStatus> for PaymentStatusDb { + fn from(value: &PaymentStatus) -> Self { + match value { + PaymentStatus::Requested(timestamp) => PaymentStatusDb::Requested(timestamp.to_owned()), + PaymentStatus::Paid(timestamp) => PaymentStatusDb::Paid(timestamp.to_owned()), + PaymentStatus::Rejected(timestamp) => PaymentStatusDb::Rejected(timestamp.to_owned()), + PaymentStatus::Expired(timestamp) => PaymentStatusDb::Expired(timestamp.to_owned()), } } } diff --git a/crates/bcr-ebill-persistence/src/tests/mod.rs b/crates/bcr-ebill-persistence/src/tests/mod.rs index 49d69d42..84427d08 100644 --- a/crates/bcr-ebill-persistence/src/tests/mod.rs +++ b/crates/bcr-ebill-persistence/src/tests/mod.rs @@ -7,9 +7,9 @@ pub mod tests { use bcr_ebill_core::{ application::{ bill::{ - BillAcceptanceStatus, BillCallerActions, BillData, BillMintStatus, - BillParticipants, BillPaymentStatus, BillRecourseStatus, BillSellStatus, - BillStatus, BitcreditBillResult, + BillAcceptState, BillAcceptanceStatus, BillCallerActions, BillData, BillMintState, + BillMintStatus, BillParticipants, BillPaymentState, BillPaymentStatus, + BillRecourseStatus, BillSellStatus, BillState, BillStatus, BitcreditBillResult, }, identity::Identity, }, @@ -173,10 +173,16 @@ pub mod tests { has_requested_funds: false, last_block_time: test_ts(), }, + state: BillState { + mint: BillMintState::None, + accept: BillAcceptState::None, + payment: BillPaymentState::None, + }, current_waiting_state: None, history: BillHistory { blocks: vec![] }, actions: BillCallerActions { bill_actions: vec![], + payment_actions: vec![], }, } } diff --git a/crates/bcr-ebill-wasm/src/api/bill.rs b/crates/bcr-ebill-wasm/src/api/bill.rs index 401ae248..9a460c1e 100644 --- a/crates/bcr-ebill-wasm/src/api/bill.rs +++ b/crates/bcr-ebill-wasm/src/api/bill.rs @@ -57,13 +57,15 @@ async fn get_attachment(bill_id: &str, file_name: &Name) -> Result<(Vec, Str let parsed_bill_id = BillId::from_str(bill_id).map_err(ProtocolValidationError::from)?; let current_timestamp = Timestamp::now(); let identity = get_ctx().identity_service.get_identity().await?; + let (caller_public_data, caller_keys) = get_signer_public_data_and_keys().await?; // get bill let bill = get_ctx() .bill_service .get_detail( &parsed_bill_id, &identity, - &get_current_identity_node_id().await?, + &caller_public_data, + &caller_keys, current_timestamp, ) .await?; @@ -108,12 +110,14 @@ impl Bill { let bill_id = BillId::from_str(id).map_err(ProtocolValidationError::from)?; let current_timestamp = Timestamp::now(); let identity = get_ctx().identity_service.get_identity().await?; + let (caller_public_data, caller_keys) = get_signer_public_data_and_keys().await?; let result = get_ctx() .bill_service .get_endorsements( &bill_id, &identity, - &get_current_identity_node_id().await?, + &caller_public_data, + &caller_keys, current_timestamp, ) .await?; @@ -254,6 +258,7 @@ impl Bill { (Some(from), Some(to)) } }; + let (caller_public_data, caller_keys) = get_signer_public_data_and_keys().await?; let bills = get_ctx() .bill_service .search_bills( @@ -262,7 +267,8 @@ impl Bill { from, to, &BillsFilterRole::from(filter.role), - &get_current_identity_node_id().await?, + &caller_public_data, + &caller_keys, ) .await?; @@ -277,9 +283,10 @@ impl Bill { #[wasm_bindgen(unchecked_return_type = "TSResult")] pub async fn list_light(&self) -> JsValue { let res: Result = async { + let (caller_public_data, caller_keys) = get_signer_public_data_and_keys().await?; let bills: Vec = get_ctx() .bill_service - .get_bills(&get_current_identity_node_id().await?) + .get_bills(&caller_public_data, &caller_keys) .await? .into_iter() .map(|b| b.into()) @@ -295,9 +302,10 @@ impl Bill { #[wasm_bindgen(unchecked_return_type = "TSResult")] pub async fn list(&self) -> JsValue { let res: Result = async { + let (caller_public_data, caller_keys) = get_signer_public_data_and_keys().await?; let bills = get_ctx() .bill_service - .get_bills(&get_current_identity_node_id().await?) + .get_bills(&caller_public_data, &caller_keys) .await?; Ok(BillsResponse { bills: bills.into_iter().map(|b| b.into()).collect(), @@ -313,12 +321,15 @@ impl Bill { let bill_id = BillId::from_str(id).map_err(ProtocolValidationError::from)?; let current_timestamp = Timestamp::now(); let identity = get_ctx().identity_service.get_identity().await?; + + let (caller_public_data, caller_keys) = get_signer_public_data_and_keys().await?; let bill_detail = get_ctx() .bill_service .get_detail( &bill_id, &identity, - &get_current_identity_node_id().await?, + &caller_public_data, + &caller_keys, current_timestamp, ) .await?; @@ -1093,12 +1104,14 @@ impl Bill { BillId::from_str(bill_id).map_err(ProtocolValidationError::from)?; let current_timestamp = Timestamp::now(); let identity = get_ctx().identity_service.get_identity().await?; + let (caller_public_data, caller_keys) = get_signer_public_data_and_keys().await?; let res: BillHistoryResponse = get_ctx() .bill_service .get_bill_history( &parsed_bill_id, &identity, - &get_current_identity_node_id().await?, + &caller_public_data, + &caller_keys, current_timestamp, ) .await? diff --git a/crates/bcr-ebill-wasm/src/api/general.rs b/crates/bcr-ebill-wasm/src/api/general.rs index 78f101d7..7b0c7e3f 100644 --- a/crates/bcr-ebill-wasm/src/api/general.rs +++ b/crates/bcr-ebill-wasm/src/api/general.rs @@ -11,7 +11,7 @@ use wasm_bindgen::prelude::*; use crate::{ TSResult, - api::identity::get_current_identity_node_id, + api::bill::get_signer_public_data_and_keys, context::get_ctx, data::{ BalanceResponse, BinaryFileResponse, CurrenciesResponse, CurrencyResponse, @@ -108,9 +108,10 @@ impl General { }; let parsed_currency = Currency::sat(); + let (caller_public_data, caller_keys) = get_signer_public_data_and_keys().await?; let result = get_ctx() .bill_service - .get_bill_balances(&parsed_currency, &get_current_identity_node_id().await?) + .get_bill_balances(&parsed_currency, &caller_public_data, &caller_keys) .await?; Ok(OverviewResponse { @@ -147,13 +148,15 @@ impl General { .into_iter() .map(GeneralSearchFilterItemType::from) .collect(); + let (caller_public_data, caller_keys) = get_signer_public_data_and_keys().await?; let result = get_ctx() .search_service .search( &search_filter.filter.search_term, &Currency::sat(), &filters, - &get_current_identity_node_id().await?, + &caller_public_data, + &caller_keys, ) .await?; diff --git a/crates/bcr-ebill-wasm/src/data/bill.rs b/crates/bcr-ebill-wasm/src/data/bill.rs index e2876c68..bbeceb97 100644 --- a/crates/bcr-ebill-wasm/src/data/bill.rs +++ b/crates/bcr-ebill-wasm/src/data/bill.rs @@ -2,9 +2,11 @@ use bcr_common::core::{BillId, NodeId}; use bcr_ebill_core::{ application::{ bill::{ - BillAcceptanceStatus, BillCallerActions, BillCallerBillAction, BillCombinedBitcoinKey, - BillCurrentWaitingState, BillData, BillMintStatus, BillParticipants, BillPaymentStatus, - BillRecourseStatus, BillSellStatus, BillStatus, BillWaitingForPaymentState, + BillAcceptState, BillAcceptanceStatus, BillCallerActions, BillCallerBillAction, + BillCallerPayment, BillCallerPaymentAction, BillCallerPaymentState, + BillCombinedBitcoinKey, BillCurrentWaitingState, BillData, BillMintState, + BillMintStatus, BillParticipants, BillPaymentState, BillPaymentStatus, + BillRecourseStatus, BillSellStatus, BillState, BillStatus, BillWaitingForPaymentState, BillWaitingForRecourseState, BillWaitingForSellState, BillWaitingStatePaymentData, BillsFilterRole, BitcreditBillResult, Endorsement, LightBitcreditBillResult, LightSignedBy, PastPaymentDataPayment, PastPaymentDataRecourse, PastPaymentDataSell, @@ -18,7 +20,7 @@ use bcr_ebill_core::{ protocol::{ BitcoinAddress, BlockId, City, Country, Date, Email, Name, Timestamp, blockchain::bill::{ - BillHistory, BillHistoryBlock, BillOpCode, PastPaymentStatus, + BillHistory, BillHistoryBlock, BillOpCode, PaymentStatus, participant::{ BillAnonParticipant, BillIdentParticipant, BillParticipant, PastEndorsee, SignedBy, }, @@ -371,18 +373,20 @@ impl From for PastPaymentResultWeb { #[derive(Tsify, Debug, Clone, Serialize)] #[tsify(into_wasm_abi)] -pub enum PastPaymentStatusWeb { +pub enum PaymentStatusWeb { + Requested(u64), Paid(u64), Rejected(u64), Expired(u64), } -impl From for PastPaymentStatusWeb { - fn from(val: PastPaymentStatus) -> Self { +impl From for PaymentStatusWeb { + fn from(val: PaymentStatus) -> Self { match val { - PastPaymentStatus::Paid(ts) => PastPaymentStatusWeb::Paid(ts.inner()), - PastPaymentStatus::Rejected(ts) => PastPaymentStatusWeb::Rejected(ts.inner()), - PastPaymentStatus::Expired(ts) => PastPaymentStatusWeb::Expired(ts.inner()), + PaymentStatus::Requested(ts) => PaymentStatusWeb::Requested(ts.inner()), + PaymentStatus::Paid(ts) => PaymentStatusWeb::Paid(ts.inner()), + PaymentStatus::Rejected(ts) => PaymentStatusWeb::Rejected(ts.inner()), + PaymentStatus::Expired(ts) => PaymentStatusWeb::Expired(ts.inner()), } } } @@ -401,7 +405,7 @@ pub struct PastPaymentDataSellWeb { pub address_to_pay: BitcoinAddress, pub private_descriptor_to_spend: String, pub mempool_link_for_address_to_pay: String, - pub status: PastPaymentStatusWeb, + pub status: PaymentStatusWeb, } impl From for PastPaymentDataSellWeb { @@ -435,7 +439,7 @@ pub struct PastPaymentDataPaymentWeb { pub address_to_pay: BitcoinAddress, pub private_descriptor_to_spend: String, pub mempool_link_for_address_to_pay: String, - pub status: PastPaymentStatusWeb, + pub status: PaymentStatusWeb, } impl From for PastPaymentDataPaymentWeb { fn from(val: PastPaymentDataPayment) -> Self { @@ -468,7 +472,7 @@ pub struct PastPaymentDataRecourseWeb { pub address_to_pay: BitcoinAddress, pub private_descriptor_to_spend: String, pub mempool_link_for_address_to_pay: String, - pub status: PastPaymentStatusWeb, + pub status: PaymentStatusWeb, } impl From for PastPaymentDataRecourseWeb { @@ -496,6 +500,8 @@ pub struct BitcreditBillWeb { pub participants: BillParticipantsWeb, pub data: BillDataWeb, pub status: BillStatusWeb, + pub state: BillStateWeb, + /* Marked for deprecation */ pub current_waiting_state: Option, pub actions: BillCallerActionsWeb, } @@ -507,12 +513,97 @@ impl From for BitcreditBillWeb { participants: val.participants.into(), data: val.data.into(), status: val.status.into(), + state: val.state.into(), current_waiting_state: val.current_waiting_state.map(|cws| cws.into()), actions: val.actions.into(), } } } +#[derive(Tsify, Debug, Serialize, Clone)] +#[tsify(into_wasm_abi)] +pub struct BillStateWeb { + pub mint: BillMintStateWeb, + pub accept: BillAcceptStateWeb, + pub payment: BillPaymentStateWeb, +} + +impl From for BillStateWeb { + fn from(value: BillState) -> Self { + Self { + mint: value.mint.into(), + accept: value.accept.into(), + payment: value.payment.into(), + } + } +} + +#[derive(Tsify, Debug, Serialize, Clone)] +#[tsify(into_wasm_abi)] +pub enum BillAcceptStateWeb { + None, + Requested(u64), + Accepted(u64), + Expired(u64), + Rejected(u64), +} + +impl From for BillAcceptStateWeb { + fn from(value: BillAcceptState) -> Self { + match value { + BillAcceptState::None => BillAcceptStateWeb::None, + BillAcceptState::Requested(timestamp) => { + BillAcceptStateWeb::Requested(timestamp.inner()) + } + BillAcceptState::Accepted(timestamp) => BillAcceptStateWeb::Accepted(timestamp.inner()), + BillAcceptState::Expired(timestamp) => BillAcceptStateWeb::Expired(timestamp.inner()), + BillAcceptState::Rejected(timestamp) => BillAcceptStateWeb::Rejected(timestamp.inner()), + } + } +} + +#[derive(Tsify, Debug, Serialize, Clone)] +#[tsify(into_wasm_abi)] +pub enum BillPaymentStateWeb { + None, + Requested(u64), + Paid(u64), + Expired(u64), + Rejected(u64), +} + +impl From for BillPaymentStateWeb { + fn from(value: BillPaymentState) -> Self { + match value { + BillPaymentState::None => BillPaymentStateWeb::None, + BillPaymentState::Requested(timestamp) => { + BillPaymentStateWeb::Requested(timestamp.inner()) + } + BillPaymentState::Paid(timestamp) => BillPaymentStateWeb::Paid(timestamp.inner()), + BillPaymentState::Expired(timestamp) => BillPaymentStateWeb::Expired(timestamp.inner()), + BillPaymentState::Rejected(timestamp) => { + BillPaymentStateWeb::Rejected(timestamp.inner()) + } + } + } +} + +#[derive(Tsify, Debug, Serialize, Clone)] +#[tsify(into_wasm_abi)] +pub enum BillMintStateWeb { + None, + Requested, +} +impl From for BillMintStateWeb { + fn from(value: BillMintState) -> Self { + match value { + BillMintState::None => BillMintStateWeb::None, + BillMintState::Requested => BillMintStateWeb::Requested, + } + } +} + +/* Marked for deprecation */ #[derive(Tsify, Debug, Serialize, Clone)] #[tsify(into_wasm_abi)] pub enum BillCurrentWaitingStateWeb { @@ -535,6 +626,7 @@ impl From for BillCurrentWaitingStateWeb { } } +/* Marked for deprecation */ #[derive(Tsify, Debug, Serialize, Clone)] #[tsify(into_wasm_abi)] pub struct BillWaitingStatePaymentDataWeb { @@ -570,6 +662,7 @@ impl From for BillWaitingStatePaymentDataWeb { } } +/* Marked for deprecation */ #[derive(Tsify, Debug, Serialize, Clone)] #[tsify(into_wasm_abi)] pub struct BillWaitingForSellStateWeb { @@ -588,6 +681,7 @@ impl From for BillWaitingForSellStateWeb { } } +/* Marked for deprecation */ #[derive(Tsify, Debug, Serialize, Clone)] #[tsify(into_wasm_abi)] pub struct BillWaitingForPaymentStateWeb { @@ -606,6 +700,7 @@ impl From for BillWaitingForPaymentStateWeb { } } +/* Marked for deprecation */ #[derive(Tsify, Debug, Serialize, Clone)] #[tsify(into_wasm_abi)] pub struct BillWaitingForRecourseStateWeb { @@ -626,14 +721,22 @@ impl From for BillWaitingForRecourseStateWeb { #[derive(Tsify, Debug, Serialize, Clone)] #[tsify(into_wasm_abi)] pub struct BillStatusWeb { + /* Marked for deprecation */ pub acceptance: BillAcceptanceStatusWeb, + /* Marked for deprecation */ pub payment: BillPaymentStatusWeb, + /* Marked for deprecation */ pub sell: BillSellStatusWeb, + /* Marked for deprecation */ pub recourse: BillRecourseStatusWeb, pub mint: BillMintStatusWeb, + /* Marked for deprecation */ pub redeemed_funds_available: bool, + /* Marked for deprecation */ pub has_requested_funds: bool, + /* Marked for deprecation */ #[tsify(type = "number")] + /* Marked for deprecation */ pub last_block_time: Timestamp, } @@ -652,6 +755,7 @@ impl From for BillStatusWeb { } } +/* Marked for deprecation */ #[derive(Tsify, Debug, Serialize, Clone)] #[tsify(into_wasm_abi)] pub struct BillAcceptanceStatusWeb { @@ -678,6 +782,7 @@ impl From for BillAcceptanceStatusWeb { } } +/* Marked for deprecation */ #[derive(Tsify, Debug, Serialize, Clone)] #[tsify(into_wasm_abi)] pub struct BillPaymentStatusWeb { @@ -703,6 +808,7 @@ impl From for BillPaymentStatusWeb { } } +/* Marked for deprecation */ #[derive(Tsify, Debug, Serialize, Clone)] #[tsify(into_wasm_abi)] pub struct BillSellStatusWeb { @@ -728,6 +834,7 @@ impl From for BillSellStatusWeb { } } +/* Marked for deprecation */ #[derive(Tsify, Debug, Serialize, Clone)] #[tsify(into_wasm_abi)] pub struct BillRecourseStatusWeb { @@ -841,12 +948,18 @@ impl From for BillParticipantsWeb { #[tsify(into_wasm_abi)] pub struct BillCallerActionsWeb { pub bill_actions: Vec, + pub payment_actions: Vec, } impl From for BillCallerActionsWeb { fn from(value: BillCallerActions) -> Self { Self { bill_actions: value.bill_actions.into_iter().map(|ba| ba.into()).collect(), + payment_actions: value + .payment_actions + .into_iter() + .map(|ba| ba.into()) + .collect(), } } } @@ -897,6 +1010,120 @@ impl From for BillCallerBillActionWeb { } } +#[derive(Tsify, Debug, Clone, Serialize)] +#[tsify(into_wasm_abi)] +pub enum BillCallerPaymentActionWeb { + Pay(BillCallerPaymentWeb), + CheckPayment(BillCallerPaymentWeb), +} + +impl From for BillCallerPaymentActionWeb { + fn from(value: BillCallerPaymentAction) -> Self { + match value { + BillCallerPaymentAction::Pay(bill_caller_payment) => { + BillCallerPaymentActionWeb::Pay(bill_caller_payment.into()) + } + BillCallerPaymentAction::CheckPayment(bill_caller_payment) => { + BillCallerPaymentActionWeb::CheckPayment(bill_caller_payment.into()) + } + } + } +} + +#[derive(Tsify, Debug, Clone, Serialize)] +#[tsify(into_wasm_abi)] +pub enum BillCallerPaymentWeb { + Sell { + buyer: BillParticipantWeb, + seller: BillParticipantWeb, + state: BillCallerPaymentStateWeb, + }, + Payment { + payer: BillIdentParticipantWeb, + payee: BillParticipantWeb, + state: BillCallerPaymentStateWeb, + }, + Recourse { + recourser: BillParticipantWeb, + recoursee: BillIdentParticipantWeb, + state: BillCallerPaymentStateWeb, + }, +} + +impl From for BillCallerPaymentWeb { + fn from(value: BillCallerPayment) -> Self { + match value { + BillCallerPayment::Sell { + buyer, + seller, + state, + } => BillCallerPaymentWeb::Sell { + buyer: buyer.into(), + seller: seller.into(), + state: state.into(), + }, + BillCallerPayment::Payment { + payer, + payee, + state, + } => BillCallerPaymentWeb::Payment { + payer: payer.into(), + payee: payee.into(), + state: state.into(), + }, + BillCallerPayment::Recourse { + recourser, + recoursee, + state, + } => BillCallerPaymentWeb::Recourse { + recourser: recourser.into(), + recoursee: recoursee.into(), + state: state.into(), + }, + } + } +} + +#[derive(Tsify, Debug, Clone, Serialize)] +#[tsify(into_wasm_abi)] +pub struct BillCallerPaymentStateWeb { + #[tsify(type = "number")] + pub time_of_request: Timestamp, + pub currency: String, + pub sum: String, + pub link_to_pay: String, + #[tsify(type = "string")] + pub address_to_pay: BitcoinAddress, + pub mempool_link_for_address_to_pay: String, + pub status: PaymentStatusWeb, + #[tsify(type = "number")] + pub payment_deadline: Timestamp, + pub tx_id: Option, + pub in_mempool: bool, + pub confirmations: u64, + // only set if we're receiver + pub private_descriptor_to_spend: Option, +} + +impl From for BillCallerPaymentStateWeb { + fn from(value: BillCallerPaymentState) -> Self { + Self { + time_of_request: value.time_of_request, + currency: value.sum.currency().code().to_owned(), + sum: value.sum.as_sat_string(), + link_to_pay: value.link_to_pay, + address_to_pay: value.address_to_pay, + mempool_link_for_address_to_pay: value.mempool_link_for_address_to_pay, + status: value.status.into(), + payment_deadline: value.payment_deadline, + tx_id: value.tx_id, + in_mempool: value.in_mempool, + confirmations: value.confirmations, + private_descriptor_to_spend: value.private_descriptor_to_spend, + } + } +} + #[derive(Tsify, Debug, Serialize, Clone)] #[tsify(into_wasm_abi)] pub struct LightBitcreditBillWeb {