Skip to content
Merged
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
1 change: 0 additions & 1 deletion crates/bcr-ebill-api/src/persistence/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ pub use bcr_ebill_persistence::contact;
pub use bcr_ebill_persistence::db;
pub use bcr_ebill_persistence::file_upload;
pub use bcr_ebill_persistence::identity;
pub use bcr_ebill_persistence::nostr;
pub use bcr_ebill_persistence::notification;

/// A container for all persistence related dependencies.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -914,10 +914,10 @@ mod tests {
};
use super::*;
use crate::tests::tests::{
MockBillChainStoreApiMock, MockBillStoreApiMock, MockChainKeyService,
MockNostrChainEventStore, MockNostrContactStore, MockNostrEventOffsetStoreApiMock,
MockChainKeyService, MockNostrChainEventStore, MockNostrContactStore,
MockNostrQueuedMessageStore, MockNotificationStoreApiMock, TEST_NODE_ID_SECP_AS_NPUB_HEX,
bill_id_test, node_id_test, node_id_test_other, node_id_test_other2, private_key_test,
bill_id_test, get_mock_db_ctx, node_id_test, node_id_test_other, node_id_test_other2,
private_key_test,
};

fn check_chain_payload(event: &EventEnvelope, bill_event_type: BillEventType) -> bool {
Expand Down Expand Up @@ -2179,11 +2179,7 @@ mod tests {
async fn test_create_nostr_consumer() {
let clients = vec![Arc::new(get_mock_nostr_client().await)];
let contact_service = Arc::new(MockContactServiceApi::new());
let store = Arc::new(MockNostrEventOffsetStoreApiMock::new());
let notification_store = Arc::new(MockNotificationStoreApiMock::new());
let push_service = Arc::new(MockPushService::new());
let bill_store = Arc::new(MockBillStoreApiMock::new());
let bill_blockchain_store = Arc::new(MockBillChainStoreApiMock::new());
let mut nostr_contact_store = MockNostrContactStore::new();
nostr_contact_store.expect_by_node_id().returning(|_| {
Ok(Some(NostrContact {
Expand All @@ -2194,19 +2190,14 @@ mod tests {
handshake_status: HandshakeStatus::None,
}))
});
let chain_key_store = Arc::new(MockChainKeyService::new());
let chain_event_store = Arc::new(MockNostrChainEventStore::new());
let chain_key_service = Arc::new(MockChainKeyService::new());
let mock_db_context = get_mock_db_ctx(Some(nostr_contact_store));
let _ = create_nostr_consumer(
clients,
contact_service,
store,
notification_store,
push_service,
bill_blockchain_store,
bill_store,
Arc::new(nostr_contact_store),
chain_key_store,
chain_event_store,
chain_key_service,
mock_db_context,
)
.await;
}
Expand Down
66 changes: 40 additions & 26 deletions crates/bcr-ebill-api/src/service/notification_service/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,17 @@ use std::collections::HashMap;
use std::sync::Arc;

use crate::persistence::identity::IdentityStoreApi;
use crate::persistence::nostr::NostrEventOffsetStoreApi;
use crate::persistence::notification::NotificationStoreApi;
use crate::{Config, get_config};
use crate::{Config, DbContext, get_config};
use bcr_ebill_core::NodeId;
use bcr_ebill_core::util::BcrKeys;
use bcr_ebill_persistence::bill::{BillChainStoreApi, BillStoreApi};
use bcr_ebill_persistence::company::CompanyStoreApi;
use bcr_ebill_persistence::nostr::{
NostrChainEventStoreApi, NostrContactStoreApi, NostrQueuedMessageStoreApi,
};
use bcr_ebill_persistence::nostr::{NostrChainEventStoreApi, NostrQueuedMessageStoreApi};
use bcr_ebill_transport::chain_keys::ChainKeyServiceApi;
use bcr_ebill_transport::handler::{
BillActionEventHandler, BillChainEventHandler, BillChainEventProcessor, BillInviteEventHandler,
LoggingEventHandler, NotificationHandlerApi,
CompanyChainEventHandler, CompanyChainEventProcessor, CompanyInviteEventHandler,
LoggingEventHandler, NostrContactProcessor, NostrContactProcessorApi, NotificationHandlerApi,
};
use bcr_ebill_transport::{Error, EventType, Result};
use bcr_ebill_transport::{NotificationServiceApi, PushApi};
Expand Down Expand Up @@ -118,31 +115,38 @@ pub async fn create_notification_service(
pub async fn create_nostr_consumer(
clients: Vec<Arc<NostrClient>>,
contact_service: Arc<dyn ContactServiceApi>,
nostr_event_offset_store: Arc<dyn NostrEventOffsetStoreApi>,
notification_store: Arc<dyn NotificationStoreApi>,
push_service: Arc<dyn PushApi>,
bill_blockchain_store: Arc<dyn BillChainStoreApi>,
bill_store: Arc<dyn BillStoreApi>,
nostr_contact_store: Arc<dyn NostrContactStoreApi>,
chain_key_service: Arc<dyn ChainKeyServiceApi>,
chain_event_store: Arc<dyn NostrChainEventStoreApi>,
db_context: DbContext,
) -> Result<NostrConsumer> {
// we need one nostr client for nostr interactions
let transport = match clients.iter().find(|c| c.is_primary()) {
Some(client) => client.clone(),
None => panic!("Cant create Nostr consumer as there is no nostr client available"),
};

let processor = Arc::new(BillChainEventProcessor::new(
bill_blockchain_store.clone(),
bill_store.clone(),
let nostr_contact_processor = Arc::new(NostrContactProcessor::new(
transport.clone(),
nostr_contact_store,
db_context.nostr_contact_store.clone(),
get_config().bitcoin_network(),
));

let bill_processor = Arc::new(BillChainEventProcessor::new(
db_context.bill_blockchain_store.clone(),
db_context.bill_store.clone(),
nostr_contact_processor.clone(),
get_config().bitcoin_network(),
));

let company_processor = Arc::new(CompanyChainEventProcessor::new(
db_context.company_chain_store.clone(),
db_context.company_store.clone(),
nostr_contact_processor.clone(),
get_config().bitcoin_network(),
));

// on startup, we make sure the configured default mint exists
processor
nostr_contact_processor
.ensure_nostr_contact(&get_config().mint_config.default_mint_node_id)
.await;

Expand All @@ -153,27 +157,37 @@ pub async fn create_nostr_consumer(
event_types: EventType::all(),
}),
Box::new(BillActionEventHandler::new(
notification_store,
db_context.notification_store.clone(),
push_service,
processor.clone(),
bill_processor.clone(),
)),
Box::new(BillInviteEventHandler::new(
transport.clone(),
processor.clone(),
chain_event_store.clone(),
bill_processor.clone(),
db_context.nostr_chain_event_store.clone(),
)),
Box::new(BillChainEventHandler::new(
processor.clone(),
bill_store.clone(),
chain_event_store.clone(),
bill_processor.clone(),
db_context.bill_store.clone(),
db_context.nostr_chain_event_store.clone(),
)),
Box::new(CompanyInviteEventHandler::new(
transport.clone(),
company_processor.clone(),
db_context.nostr_chain_event_store.clone(),
)),
Box::new(CompanyChainEventHandler::new(
db_context.company_store.clone(),
company_processor.clone(),
db_context.nostr_chain_event_store.clone(),
)),
];
debug!("initializing nostr consumer for {} clients", clients.len());
let consumer = NostrConsumer::new(
clients,
contact_service,
handlers,
nostr_event_offset_store,
db_context.nostr_event_offset_store.clone(),
chain_key_service,
);
Ok(consumer)
Expand Down
10 changes: 7 additions & 3 deletions crates/bcr-ebill-api/src/service/notification_service/nostr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ async fn handle_direct_message<T: NostrSigner>(
if let Some((envelope, sender, _, _)) = unwrap_direct_message(event.clone(), signer).await {
let sender_npub = sender.to_bech32();
let sender_pub_key = sender.to_hex();
trace!(
debug!(
"Processing event: {envelope:?} from {sender_npub:?} (hex: {sender_pub_key}) on client {client_id}"
);
handle_event(envelope, client_id, event_handlers, event).await?;
Expand All @@ -617,12 +617,16 @@ async fn handle_public_event(
handlers: &Arc<Vec<Box<dyn NotificationHandlerApi>>>,
) -> Result<bool> {
if let Some(encrypted_data) = unwrap_public_chain_event(event.clone())? {
debug!(
"Received public chain event: {} {}",
encrypted_data.chain_type, encrypted_data.id
);
if let Ok(Some(chain_keys)) = chain_key_store
.get_chain_keys(&encrypted_data.id, encrypted_data.chain_type)
.await
{
let decrypted = decrypt_public_chain_event(&encrypted_data.payload, &chain_keys)?;
trace!("Handling public chain event: {decrypted:?}");
debug!("Handling public chain event: {:?}", decrypted.event_type);
handle_event(decrypted.clone(), node_id, handlers, event.clone()).await?;
}
Ok(true)
Expand Down Expand Up @@ -715,14 +719,14 @@ mod tests {
use bcr_ebill_core::NodeId;
use bcr_ebill_core::contact::BillParticipant;
use bcr_ebill_core::{ServiceTraitBounds, notification::BillEventType};
use bcr_ebill_persistence::NostrEventOffset;
use bcr_ebill_transport::handler::NotificationHandlerApi;
use bcr_ebill_transport::{Event, EventEnvelope, EventType};
use mockall::predicate;
use tokio::time;

use super::super::test_utils::get_mock_relay;
use super::{NostrClient, NostrConfig, NostrConsumer};
use crate::persistence::nostr::NostrEventOffset;
use crate::service::{
contact_service::MockContactServiceApi,
notification_service::{NotificationJsonTransportApi, test_utils::*},
Expand Down
24 changes: 22 additions & 2 deletions crates/bcr-ebill-api/src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[cfg(test)]
#[allow(clippy::module_inception)]
pub mod tests {
use crate::{CONFIG, MintConfig, NostrConfig, data::bill::BillKeys};
use crate::{CONFIG, DbContext, MintConfig, NostrConfig, data::bill::BillKeys};
use async_trait::async_trait;
use bcr_ebill_core::{
NodeId, OptionalPostalAddress, PostalAddress, PublicKey, SecretKey, ServiceTraitBounds,
Expand Down Expand Up @@ -40,11 +40,11 @@ pub mod tests {
event::{company_events::CompanyChainEvent, identity_events::IdentityChainEvent},
transport::NostrContactData,
};
use std::path::Path;
use std::{
collections::{HashMap, HashSet},
str::FromStr,
};
use std::{path::Path, sync::Arc};

// Need to wrap mocks, because traits are in a different crate
mockall::mock! {
Expand Down Expand Up @@ -451,6 +451,26 @@ pub mod tests {
}
}

pub fn get_mock_db_ctx(nostr_contact_store: Option<MockNostrContactStore>) -> DbContext {
DbContext {
contact_store: Arc::new(MockContactStoreApiMock::new()),
bill_store: Arc::new(MockBillStoreApiMock::new()),
bill_blockchain_store: Arc::new(MockBillChainStoreApiMock::new()),
identity_store: Arc::new(MockIdentityStoreApiMock::new()),
identity_chain_store: Arc::new(MockIdentityChainStoreApiMock::new()),
company_chain_store: Arc::new(MockCompanyChainStoreApiMock::new()),
company_store: Arc::new(MockCompanyStoreApiMock::new()),
file_upload_store: Arc::new(MockFileUploadStoreApiMock::new()),
nostr_event_offset_store: Arc::new(MockNostrEventOffsetStoreApiMock::new()),
notification_store: Arc::new(MockNotificationStoreApiMock::new()),
backup_store: Arc::new(MockBackupStoreApiMock::new()),
queued_message_store: Arc::new(MockNostrQueuedMessageStore::new()),
nostr_contact_store: Arc::new(nostr_contact_store.unwrap_or_default()),
mint_store: Arc::new(MockMintStore::new()),
nostr_chain_event_store: Arc::new(MockNostrChainEventStore::new()),
}
}

pub fn init_test_cfg() {
match CONFIG.get() {
Some(_) => (),
Expand Down
34 changes: 33 additions & 1 deletion crates/bcr-ebill-core/src/blockchain/company/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ impl From<Company> for CompanyCreateBlockData {
}
}

#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, PartialEq)]
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, Default, PartialEq)]
pub struct CompanyUpdateBlockData {
pub name: Option<String>,
pub email: Option<String>,
Expand Down Expand Up @@ -132,6 +132,15 @@ pub struct CompanyRemoveSignatoryBlockData {
pub signatory: NodeId,
}

#[derive(Debug)]
pub enum CompanyBlockPayload {
Create(CompanyCreateBlockData),
Update(CompanyUpdateBlockData),
SignBill(CompanySignCompanyBillBlockData),
AddSignatory(CompanyAddSignatoryBlockData),
RemoveSignatory(CompanyRemoveSignatoryBlockData),
}

impl Block for CompanyBlock {
type OpCode = CompanyOpCode;
type BlockDataToHash = CompanyBlockDataToHash;
Expand Down Expand Up @@ -408,6 +417,29 @@ impl CompanyBlock {
Ok(block)
}

pub fn get_block_data(&self, company_keys: &CompanyKeys) -> Result<CompanyBlockPayload> {
let data = self.get_decrypted_block(company_keys)?;
let result: CompanyBlockPayload = match self.op_code {
CompanyOpCode::Create => CompanyBlockPayload::Create(from_slice(&data)?),
CompanyOpCode::Update => CompanyBlockPayload::Update(from_slice(&data)?),
CompanyOpCode::AddSignatory => CompanyBlockPayload::AddSignatory(from_slice(&data)?),
CompanyOpCode::RemoveSignatory => {
CompanyBlockPayload::RemoveSignatory(from_slice(&data)?)
}
CompanyOpCode::SignCompanyBill => CompanyBlockPayload::SignBill(from_slice(&data)?),
};
Ok(result)
}

fn get_decrypted_block(&self, company_keys: &CompanyKeys) -> Result<Vec<u8>> {
let bytes = util::base58_decode(&self.data)?;
let block_data: CompanyBlockData = from_slice(&bytes)?;
let decoded_data_bytes = util::base58_decode(&block_data.data)?;
let decrypted_bytes =
util::crypto::decrypt_ecies(&decoded_data_bytes, &company_keys.private_key)?;
Ok(decrypted_bytes)
}

fn encrypt_data_create_block_and_validate<T: borsh::BorshSerialize>(
company_id: NodeId,
previous_block: &Self,
Expand Down
Loading
Loading