Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 0.5.4

* If the bill holder is anon, the `signing_address` needs to not be set
* If the bill holder is anon and a company, the `signatory` shouldn't have a `name` set (breaking DB and bill block change)

# 0.5.3

* Fix minting URL and use new bcr-common
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand Down
114 changes: 95 additions & 19 deletions crates/bcr-ebill-api/src/service/bill_service/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use bcr_ebill_core::{
BillOfferToSellBlockData, BillRecourseBlockData, BillRecourseReasonBlockData,
BillRejectBlockData, BillRejectToBuyBlockData, BillRequestRecourseBlockData,
BillRequestToAcceptBlockData, BillRequestToPayBlockData, BillSellBlockData,
ContactType,
BillSignatoryBlockData, ContactType,
},
participant::BillParticipant,
},
Expand Down Expand Up @@ -109,9 +109,16 @@ impl BillService {
} else {
signer_public_data.clone().into()
},
signatory: signing_keys.signatory_identity,
signatory: signatory_for_signer(
holder_is_anon,
signing_keys.signatory_identity,
),
signing_timestamp: timestamp,
signing_address: signer_public_data.postal_address(),
signing_address: if holder_is_anon {
None
} else {
signer_public_data.postal_address()
},
signer_identity_proof: if holder_is_anon {
None
} else {
Expand Down Expand Up @@ -141,9 +148,16 @@ impl BillService {
signer_public_data.clone().into()
},
currency: currency.to_owned(),
signatory: signing_keys.signatory_identity,
signatory: signatory_for_signer(
holder_is_anon,
signing_keys.signatory_identity,
),
signing_timestamp: timestamp,
signing_address: signer_public_data.postal_address(),
signing_address: if holder_is_anon {
None
} else {
signer_public_data.postal_address()
},
signer_identity_proof: if holder_is_anon {
None
} else {
Expand Down Expand Up @@ -188,9 +202,16 @@ impl BillService {
recoursee: recoursee.clone().into(),
sum,
recourse_reason: reason,
signatory: signing_keys.signatory_identity,
signatory: signatory_for_signer(
holder_is_anon,
signing_keys.signatory_identity,
),
signing_timestamp: timestamp,
signing_address: signer_public_data.postal_address(),
signing_address: if holder_is_anon {
None
} else {
signer_public_data.postal_address()
},
signer_identity_proof: if holder_is_anon {
None
} else {
Expand Down Expand Up @@ -227,9 +248,16 @@ impl BillService {
recoursee: recoursee.clone().into(),
sum: sum.clone(),
recourse_reason: reason,
signatory: signing_keys.signatory_identity,
signatory: signatory_for_signer(
holder_is_anon,
signing_keys.signatory_identity,
),
signing_timestamp: timestamp,
signing_address: signer_public_data.postal_address(),
signing_address: if holder_is_anon {
None
} else {
signer_public_data.postal_address()
},
signer_identity_proof: if holder_is_anon {
None
} else {
Expand Down Expand Up @@ -260,9 +288,16 @@ impl BillService {
},
endorsee: mint.clone().into(),
sum: sum.clone(),
signatory: signing_keys.signatory_identity,
signatory: signatory_for_signer(
holder_is_anon,
signing_keys.signatory_identity,
),
signing_timestamp: timestamp,
signing_address: signer_public_data.postal_address(),
signing_address: if holder_is_anon {
None
} else {
signer_public_data.postal_address()
},
signer_identity_proof: if holder_is_anon {
None
} else {
Expand Down Expand Up @@ -298,9 +333,16 @@ impl BillService {
buyer: buyer.clone().into(),
sum: sum.clone(),
payment_address: address_to_pay,
signatory: signing_keys.signatory_identity,
signatory: signatory_for_signer(
holder_is_anon,
signing_keys.signatory_identity,
),
signing_timestamp: timestamp,
signing_address: signer_public_data.postal_address(),
signing_address: if holder_is_anon {
None
} else {
signer_public_data.postal_address()
},
signer_identity_proof: if holder_is_anon {
None
} else {
Expand Down Expand Up @@ -333,9 +375,16 @@ impl BillService {
buyer: buyer.clone().into(),
sum: sum.clone(),
payment_address: payment_address.to_owned(),
signatory: signing_keys.signatory_identity,
signatory: signatory_for_signer(
holder_is_anon,
signing_keys.signatory_identity,
),
signing_timestamp: timestamp,
signing_address: signer_public_data.postal_address(),
signing_address: if holder_is_anon {
None
} else {
signer_public_data.postal_address()
},
signer_identity_proof: if holder_is_anon {
None
} else {
Expand Down Expand Up @@ -365,9 +414,16 @@ impl BillService {
signer_public_data.clone().into()
},
endorsee: endorsee.clone().into(),
signatory: signing_keys.signatory_identity,
signatory: signatory_for_signer(
holder_is_anon,
signing_keys.signatory_identity,
),
signing_timestamp: timestamp,
signing_address: signer_public_data.postal_address(),
signing_address: if holder_is_anon {
None
} else {
signer_public_data.postal_address()
},
signer_identity_proof: if holder_is_anon {
None
} else {
Expand Down Expand Up @@ -426,9 +482,16 @@ impl BillService {
} else {
signer_public_data.clone().into()
},
signatory: signing_keys.signatory_identity,
signatory: signatory_for_signer(
holder_is_anon,
signing_keys.signatory_identity,
),
signing_timestamp: timestamp,
signing_address: signer_public_data.postal_address(),
signing_address: if holder_is_anon {
None
} else {
signer_public_data.postal_address()
},
signer_identity_proof: if holder_is_anon {
None
} else {
Expand Down Expand Up @@ -753,3 +816,16 @@ impl BillService {
Ok(())
}
}

/// if the signer is anonymous, the signatory also needs to be anonymous
fn signatory_for_signer(
signer_is_anon: bool,
signatory_data: Option<BillSignatoryBlockData>,
) -> Option<BillSignatoryBlockData> {
signatory_data.map(|mut d| {
if signer_is_anon {
d.name = None;
}
d
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,10 @@ impl BillService {
(
signatory_identity.key_pair.clone(),
Some(signer_keys.clone()),
Some(signatory_identity.identity.clone().into()),
Some(BillSignatoryBlockData {
node_id: signatory_identity.identity.node_id.clone(),
name: Some(signatory_identity.identity.name.clone()),
}),
)
}
};
Expand Down
107 changes: 103 additions & 4 deletions crates/bcr-ebill-api/src/service/bill_service/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ 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,
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_another, node_id_test_other, private_key_test, private_key_test_another,
signed_identity_proof_test, test_ts, valid_payment_address_testnet,
},
util::get_uuid_v4,
Expand All @@ -31,7 +32,7 @@ use bcr_ebill_core::{
blockchain::{
Block, Blockchain,
bill::{
BillBlock, BillOpCode, PastPaymentStatus, RecourseReason,
BillBlock, BillOpCode, ContactType, PastPaymentStatus, RecourseReason,
block::{
BillEndorseBlockData, BillMintBlockData, BillOfferToSellBlockData,
BillParticipantBlockData, BillRecourseReasonBlockData, BillRejectBlockData,
Expand Down Expand Up @@ -3440,6 +3441,104 @@ async fn endorse_bitcredit_bill_anon_baseline() {
assert!(res.unwrap().blocks()[1].op_code == BillOpCode::Endorse);
}

#[tokio::test]
async fn endorse_bitcredit_bill_anon_company_and_back() {
let mut ctx = get_ctx();
let identity = get_baseline_identity();
let company_node_id = node_id_test_another();
let company_participant =
BillAnonParticipant::from(bill_participant_only_node_id(company_node_id.clone()));
let mut bill = get_baseline_bill(&bill_id_test());
bill.payee = BillParticipant::Ident(bill_identified_participant_only_node_id(
identity.identity.node_id.clone(),
));
ctx.bill_store
.expect_save_bill_to_cache()
.returning(|_, _, _| Ok(()));
let company_participant_clone = company_participant.clone();
ctx.bill_blockchain_store
.expect_get_chain()
.returning(move |_| {
let mut chain = get_genesis_chain(Some(bill.clone()));

// add endorse block from payee to endorsee
let endorse_block = BillBlock::create_block_for_endorse(
bill_id_test(),
chain.get_latest_block(),
&BillEndorseBlockData {
endorsee: BillParticipantBlockData::Anon(
company_participant_clone.clone().into(),
),
// endorsed by payee
endorser: BillParticipantBlockData::Ident(
BillIdentParticipant::new(get_baseline_identity().identity)
.unwrap()
.into(),
),
signatory: None,
signing_timestamp: test_ts() - 14,
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_another())),
&BcrKeys::from_private_key(&private_key_test()),
test_ts() - 14,
)
.unwrap();
assert!(chain.try_add_block(endorse_block));
Ok(chain)
});
// Bill is endorsed event should be sent
ctx.transport_service
.expect_send_bill_is_endorsed_event()
.returning(|_| Ok(()));
ctx.company_store
.expect_get_email_confirmations()
.returning(|_| Ok(vec![signed_identity_proof_test()]))
.times(1);
ctx.company_store.expect_get().returning(|_| {
let mut company = get_baseline_company_data();
company.1.0.id = node_id_test_another();
Ok(company.1.0)
});

// Populates identity block
expect_populates_company_and_identity_block(&mut ctx);

let service = get_service(ctx);

let mut company_ident_participant = bill_participant_only_node_id(company_node_id.clone());
if let BillParticipant::Ident(ref mut bill_ident_participant) = company_ident_participant {
bill_ident_participant.t = ContactType::Company;
};

let res = service
.execute_bill_action(
&bill_id_test(),
BillAction::Endorse(BillParticipant::Ident(
BillIdentParticipant::new(get_baseline_identity().identity).unwrap(),
)),
&company_ident_participant,
&BcrKeys::from_private_key(&private_key_test_another()),
test_ts(),
)
.await;
assert!(res.is_ok());
assert!(res.as_ref().unwrap().blocks().len() == 3);
assert!(res.as_ref().unwrap().blocks()[1].op_code == BillOpCode::Endorse);
assert!(res.as_ref().unwrap().blocks()[2].op_code == BillOpCode::Endorse);
let last_endorse_data: BillEndorseBlockData = res
.unwrap()
.blocks()
.get(2)
.unwrap()
.get_decrypted_block(&BcrKeys::from_private_key(&private_key_test()))
.unwrap();
assert!(last_endorse_data.signatory.as_ref().unwrap().name.is_none()); // name is not set, because company was anon signer
assert!(last_endorse_data.signing_address.is_none()); // address is not set, because company was anon signer
}

#[tokio::test]
async fn endorse_bitcredit_bill_fails_if_waiting_for_offer_to_sell() {
let mut ctx = get_ctx();
Expand Down Expand Up @@ -5622,7 +5721,7 @@ async fn check_bills_in_recourse_payment_company_is_recourser() {
recourse_reason: BillRecourseReasonBlockData::Pay,
signatory: Some(BillSignatoryBlockData {
node_id: get_baseline_identity().identity.node_id.clone(),
name: get_baseline_identity().identity.name.clone(),
name: Some(get_baseline_identity().identity.name.clone()),
}),
signing_timestamp: now,
signing_address: Some(empty_address()),
Expand Down
Loading