Skip to content

Commit f4e79ea

Browse files
authored
Implement Dev Mode for Identity and Company Chains (#665)
1 parent 6fc0691 commit f4e79ea

File tree

14 files changed

+369
-91
lines changed

14 files changed

+369
-91
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* Removed the concept of an `Authorized Signer`
99
* Fix it so that Anon holders of a bill can do recourse (breaking DB and API change)
1010
* `recourser` went from `BillIdentParticipant` to `BillParticipant`
11+
* Added endpoints `identityApi.dev_mode_get_full_identity_chain()` and `companyApi.dev_mode_get_full_company_chain(company_id)` to show the full identity and company chains as JSON in dev mode
1112

1213
# 0.4.8
1314

crates/bcr-ebill-api/src/service/company_service.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use crate::external::file_storage::FileStorageClientApi;
1919
use crate::get_config;
2020
use crate::persistence::company::{CompanyChainStoreApi, CompanyStoreApi};
2121
use crate::persistence::identity::IdentityChainStoreApi;
22+
use crate::service::Error;
2223
use crate::service::notification_service::event::{CompanyChainEvent, IdentityChainEvent};
2324
use crate::service::notification_service::{BcrMetadata, NostrContactData};
2425
use crate::util::BcrKeys;
@@ -30,6 +31,7 @@ use crate::{
3031
util,
3132
};
3233
use async_trait::async_trait;
34+
use bcr_ebill_core::blockchain::company::CompanyBlockPlaintextWrapper;
3335
use bcr_ebill_core::identity::IdentityType;
3436
use bcr_ebill_core::util::base58_encode;
3537
use bcr_ebill_core::util::crypto::DeriveKeypair;
@@ -114,6 +116,12 @@ pub trait CompanyServiceApi: ServiceTraitBounds {
114116

115117
/// Shares derived keys for given company contact information.
116118
async fn share_contact_details(&self, share_to: &NodeId, company_id: NodeId) -> Result<()>;
119+
120+
/// If dev mode is on, return the full company chain with decrypted data
121+
async fn dev_mode_get_full_company_chain(
122+
&self,
123+
id: &NodeId,
124+
) -> Result<Vec<CompanyBlockPlaintextWrapper>>;
117125
}
118126

119127
/// The company service is responsible for managing the companies
@@ -919,6 +927,30 @@ impl CompanyServiceApi for CompanyService {
919927
.await?;
920928
Ok(())
921929
}
930+
931+
async fn dev_mode_get_full_company_chain(
932+
&self,
933+
id: &NodeId,
934+
) -> Result<Vec<CompanyBlockPlaintextWrapper>> {
935+
// if dev mode is off - we return an error
936+
if !get_config().dev_mode_config.on {
937+
error!("Called dev mode operation with dev mode disabled - please enable!");
938+
return Err(Error::InvalidOperation);
939+
}
940+
validate_node_id_network(id)?;
941+
942+
// if there is no such company, we return an error
943+
if !self.store.exists(id).await {
944+
return Err(Error::NotFound);
945+
}
946+
947+
let chain = self.company_blockchain_store.get_chain(id).await?;
948+
let company_keys = self.store.get_key_pair(id).await?;
949+
950+
let plaintext_chain = chain.get_chain_with_plaintext_block_data(&company_keys)?;
951+
952+
Ok(plaintext_chain)
953+
}
922954
}
923955

924956
#[cfg(test)]

crates/bcr-ebill-api/src/service/identity_service.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use super::notification_service::NotificationServiceApi;
33
use super::notification_service::event::IdentityChainEvent;
44
use crate::data::validate_node_id_network;
55
use crate::external::file_storage::FileStorageClientApi;
6+
use crate::service::Error;
67
use crate::service::notification_service::{BcrMetadata, NostrContactData};
78
use crate::util::file::UploadFileType;
89
use crate::{get_config, util};
@@ -17,6 +18,7 @@ use crate::data::{
1718
use crate::persistence::file_upload::FileUploadStoreApi;
1819
use crate::persistence::identity::IdentityChainStoreApi;
1920
use async_trait::async_trait;
21+
use bcr_ebill_core::blockchain::identity::IdentityBlockPlaintextWrapper;
2022
use bcr_ebill_core::contact::{Contact, ContactType};
2123
use bcr_ebill_core::identity::validation::{validate_create_identity, validate_update_identity};
2224
use bcr_ebill_core::identity::{ActiveIdentityState, IdentityType};
@@ -108,6 +110,9 @@ pub trait IdentityServiceApi: ServiceTraitBounds {
108110

109111
/// Shares derived keys for private identity contact information. Recipient is the given node id.
110112
async fn share_contact_details(&self, share_to: &NodeId) -> Result<()>;
113+
114+
/// If dev mode is on, return the full identity chain with decrypted data
115+
async fn dev_mode_get_full_identity_chain(&self) -> Result<Vec<IdentityBlockPlaintextWrapper>>;
111116
}
112117

113118
/// The identity service is responsible for managing the local identity
@@ -746,6 +751,26 @@ impl IdentityServiceApi for IdentityService {
746751
.await?;
747752
Ok(())
748753
}
754+
755+
async fn dev_mode_get_full_identity_chain(&self) -> Result<Vec<IdentityBlockPlaintextWrapper>> {
756+
// if dev mode is off - we return an error
757+
if !get_config().dev_mode_config.on {
758+
error!("Called dev mode operation with dev mode disabled - please enable!");
759+
return Err(Error::InvalidOperation);
760+
}
761+
762+
// if there is identity yet, we return an error
763+
if !self.identity_exists().await {
764+
return Err(Error::NotFound);
765+
}
766+
767+
let chain = self.blockchain_store.get_chain().await?;
768+
let keys = self.store.get_key_pair().await?;
769+
770+
let plaintext_chain = chain.get_chain_with_plaintext_block_data(&keys)?;
771+
772+
Ok(plaintext_chain)
773+
}
749774
}
750775

751776
#[cfg(test)]

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,8 @@ pub enum Error {
5959
/// error returned if the given file upload id is not a temp file we have
6060
#[error("No file found for file upload id")]
6161
NoFileForFileUploadId,
62+
63+
/// errors stemming from trying to do invalid operations
64+
#[error("invalid operation")]
65+
InvalidOperation,
6266
}

crates/bcr-ebill-core/src/blockchain/bill/block.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,13 +1259,19 @@ impl BillBlock {
12591259
&self,
12601260
bill_keys: &BillKeys,
12611261
) -> Result<T> {
1262+
let decrypted_bytes = self.get_decrypted_block_bytes(bill_keys)?;
1263+
let deserialized = from_slice::<T>(&decrypted_bytes)?;
1264+
Ok(deserialized)
1265+
}
1266+
1267+
/// Decrypts the block data using the bill's private key, returning the deserialized data
1268+
pub(super) fn get_decrypted_block_bytes(&self, bill_keys: &BillKeys) -> Result<Vec<u8>> {
12621269
let bytes = util::base58_decode(&self.data)?;
12631270
let block_data: BillBlockData = from_slice(&bytes)?;
12641271
let decoded_data_bytes = util::base58_decode(&block_data.data)?;
12651272
let decrypted_bytes =
12661273
util::crypto::decrypt_ecies(&decoded_data_bytes, &bill_keys.private_key)?;
1267-
let deserialized = from_slice::<T>(&decrypted_bytes)?;
1268-
Ok(deserialized)
1274+
Ok(decrypted_bytes)
12691275
}
12701276

12711277
/// Extracts a list of unique node IDs involved in a block operation.

crates/bcr-ebill-core/src/blockchain/bill/chain.rs

Lines changed: 33 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use super::{OfferToSellWaitingForPayment, RecoursePaymentInfo};
1111
use crate::NodeId;
1212
use crate::bill::{BillKeys, Endorsement, LightSignedBy, PastEndorsee, PastPaymentStatus};
1313
use crate::blockchain::bill::block::BillRejectToBuyBlockData;
14-
use crate::blockchain::{Block, Blockchain, Error};
14+
use crate::blockchain::{Block, Blockchain, Error, borsh_to_json_string};
1515
use crate::constants::{PAYMENT_DEADLINE_SECONDS, RECOURSE_DEADLINE_SECONDS};
1616
use crate::contact::{
1717
BillParticipant, ContactType, LightBillIdentParticipant, LightBillParticipant,
@@ -97,58 +97,51 @@ impl BillBlockPlaintextWrapper {
9797
let mut block = self.block.clone();
9898
let block_data_string: String = match self.block.op_code() {
9999
BillOpCode::Issue => {
100-
Self::borsh_to_json_string::<BillIssueBlockData>(&self.plaintext_data_bytes)?
100+
borsh_to_json_string::<BillIssueBlockData>(&self.plaintext_data_bytes)?
101101
}
102102
BillOpCode::Accept => {
103-
Self::borsh_to_json_string::<BillAcceptBlockData>(&self.plaintext_data_bytes)?
103+
borsh_to_json_string::<BillAcceptBlockData>(&self.plaintext_data_bytes)?
104104
}
105105
BillOpCode::Endorse => {
106-
Self::borsh_to_json_string::<BillEndorseBlockData>(&self.plaintext_data_bytes)?
106+
borsh_to_json_string::<BillEndorseBlockData>(&self.plaintext_data_bytes)?
107+
}
108+
BillOpCode::RequestToAccept => {
109+
borsh_to_json_string::<BillRequestToAcceptBlockData>(&self.plaintext_data_bytes)?
107110
}
108-
BillOpCode::RequestToAccept => Self::borsh_to_json_string::<
109-
BillRequestToAcceptBlockData,
110-
>(&self.plaintext_data_bytes)?,
111111
BillOpCode::RequestToPay => {
112-
Self::borsh_to_json_string::<BillRequestToPayBlockData>(&self.plaintext_data_bytes)?
112+
borsh_to_json_string::<BillRequestToPayBlockData>(&self.plaintext_data_bytes)?
113113
}
114114
BillOpCode::OfferToSell => {
115-
Self::borsh_to_json_string::<BillOfferToSellBlockData>(&self.plaintext_data_bytes)?
115+
borsh_to_json_string::<BillOfferToSellBlockData>(&self.plaintext_data_bytes)?
116116
}
117117
BillOpCode::Sell => {
118-
Self::borsh_to_json_string::<BillSellBlockData>(&self.plaintext_data_bytes)?
118+
borsh_to_json_string::<BillSellBlockData>(&self.plaintext_data_bytes)?
119119
}
120120
BillOpCode::Mint => {
121-
Self::borsh_to_json_string::<BillMintBlockData>(&self.plaintext_data_bytes)?
121+
borsh_to_json_string::<BillMintBlockData>(&self.plaintext_data_bytes)?
122122
}
123123
BillOpCode::RejectToAccept => {
124-
Self::borsh_to_json_string::<BillRejectBlockData>(&self.plaintext_data_bytes)?
124+
borsh_to_json_string::<BillRejectBlockData>(&self.plaintext_data_bytes)?
125125
}
126126
BillOpCode::RejectToPay => {
127-
Self::borsh_to_json_string::<BillRejectBlockData>(&self.plaintext_data_bytes)?
127+
borsh_to_json_string::<BillRejectBlockData>(&self.plaintext_data_bytes)?
128128
}
129129
BillOpCode::RejectToBuy => {
130-
Self::borsh_to_json_string::<BillRejectToBuyBlockData>(&self.plaintext_data_bytes)?
130+
borsh_to_json_string::<BillRejectToBuyBlockData>(&self.plaintext_data_bytes)?
131131
}
132132
BillOpCode::RejectToPayRecourse => {
133-
Self::borsh_to_json_string::<BillRejectBlockData>(&self.plaintext_data_bytes)?
133+
borsh_to_json_string::<BillRejectBlockData>(&self.plaintext_data_bytes)?
134+
}
135+
BillOpCode::RequestRecourse => {
136+
borsh_to_json_string::<BillRequestRecourseBlockData>(&self.plaintext_data_bytes)?
134137
}
135-
BillOpCode::RequestRecourse => Self::borsh_to_json_string::<
136-
BillRequestRecourseBlockData,
137-
>(&self.plaintext_data_bytes)?,
138138
BillOpCode::Recourse => {
139-
Self::borsh_to_json_string::<BillRecourseBlockData>(&self.plaintext_data_bytes)?
139+
borsh_to_json_string::<BillRecourseBlockData>(&self.plaintext_data_bytes)?
140140
}
141141
};
142142
block.data = block_data_string;
143143
serde_json::to_string(&block).map_err(|e| Error::JSON(e.to_string()))
144144
}
145-
146-
fn borsh_to_json_string<T: borsh::BorshDeserialize + serde::Serialize>(
147-
bytes: &[u8],
148-
) -> Result<String> {
149-
let block_data: T = borsh::from_slice(bytes)?;
150-
serde_json::to_string(&block_data).map_err(|e| Error::JSON(e.to_string()))
151-
}
152145
}
153146

154147
/// Gets bill parties from blocks with their plaintext data
@@ -966,48 +959,20 @@ impl BillBlockchain {
966959
let mut result = Vec::with_capacity(self.blocks().len());
967960
for block in self.blocks.iter() {
968961
let plaintext_data_bytes = match block.op_code() {
969-
BillOpCode::Issue => {
970-
borsh::to_vec(&block.get_decrypted_block::<BillIssueBlockData>(bill_keys)?)?
971-
}
972-
BillOpCode::Accept => {
973-
borsh::to_vec(&block.get_decrypted_block::<BillAcceptBlockData>(bill_keys)?)?
974-
}
975-
BillOpCode::Endorse => {
976-
borsh::to_vec(&block.get_decrypted_block::<BillEndorseBlockData>(bill_keys)?)?
977-
}
978-
BillOpCode::RequestToAccept => borsh::to_vec(
979-
&block.get_decrypted_block::<BillRequestToAcceptBlockData>(bill_keys)?,
980-
)?,
981-
BillOpCode::RequestToPay => borsh::to_vec(
982-
&block.get_decrypted_block::<BillRequestToPayBlockData>(bill_keys)?,
983-
)?,
984-
BillOpCode::OfferToSell => borsh::to_vec(
985-
&block.get_decrypted_block::<BillOfferToSellBlockData>(bill_keys)?,
986-
)?,
987-
BillOpCode::Sell => {
988-
borsh::to_vec(&block.get_decrypted_block::<BillSellBlockData>(bill_keys)?)?
989-
}
990-
BillOpCode::Mint => {
991-
borsh::to_vec(&block.get_decrypted_block::<BillMintBlockData>(bill_keys)?)?
992-
}
993-
BillOpCode::RejectToAccept => {
994-
borsh::to_vec(&block.get_decrypted_block::<BillRejectBlockData>(bill_keys)?)?
995-
}
996-
BillOpCode::RejectToPay => {
997-
borsh::to_vec(&block.get_decrypted_block::<BillRejectBlockData>(bill_keys)?)?
998-
}
999-
BillOpCode::RejectToBuy => borsh::to_vec(
1000-
&block.get_decrypted_block::<BillRejectToBuyBlockData>(bill_keys)?,
1001-
)?,
1002-
BillOpCode::RejectToPayRecourse => {
1003-
borsh::to_vec(&block.get_decrypted_block::<BillRejectBlockData>(bill_keys)?)?
1004-
}
1005-
BillOpCode::RequestRecourse => borsh::to_vec(
1006-
&block.get_decrypted_block::<BillRequestRecourseBlockData>(bill_keys)?,
1007-
)?,
1008-
BillOpCode::Recourse => {
1009-
borsh::to_vec(&block.get_decrypted_block::<BillRecourseBlockData>(bill_keys)?)?
1010-
}
962+
BillOpCode::Issue => block.get_decrypted_block_bytes(bill_keys)?,
963+
BillOpCode::Accept => block.get_decrypted_block_bytes(bill_keys)?,
964+
BillOpCode::Endorse => block.get_decrypted_block_bytes(bill_keys)?,
965+
BillOpCode::RequestToAccept => block.get_decrypted_block_bytes(bill_keys)?,
966+
BillOpCode::RequestToPay => block.get_decrypted_block_bytes(bill_keys)?,
967+
BillOpCode::OfferToSell => block.get_decrypted_block_bytes(bill_keys)?,
968+
BillOpCode::Sell => block.get_decrypted_block_bytes(bill_keys)?,
969+
BillOpCode::Mint => block.get_decrypted_block_bytes(bill_keys)?,
970+
BillOpCode::RejectToAccept => block.get_decrypted_block_bytes(bill_keys)?,
971+
BillOpCode::RejectToPay => block.get_decrypted_block_bytes(bill_keys)?,
972+
BillOpCode::RejectToBuy => block.get_decrypted_block_bytes(bill_keys)?,
973+
BillOpCode::RejectToPayRecourse => block.get_decrypted_block_bytes(bill_keys)?,
974+
BillOpCode::RequestRecourse => block.get_decrypted_block_bytes(bill_keys)?,
975+
BillOpCode::Recourse => block.get_decrypted_block_bytes(bill_keys)?,
1011976
};
1012977

1013978
if block.plaintext_hash != util::sha256_hash(&plaintext_data_bytes) {

0 commit comments

Comments
 (0)