diff --git a/crates/node/Cargo.toml b/crates/node/Cargo.toml index a8dc97086..eda8d0614 100644 --- a/crates/node/Cargo.toml +++ b/crates/node/Cargo.toml @@ -26,11 +26,11 @@ calimero-crypto = { path = "../crypto" } calimero-blobstore = { path = "../store/blobs" } calimero-network = { path = "../network" } calimero-node-primitives = { path = "../node-primitives" } -calimero-primitives = { path = "../primitives" } +calimero-primitives = { path = "../primitives", features = ["borsh"] } calimero-runtime = { path = "../runtime" } calimero-server = { path = "../server", features = ["jsonrpc", "websocket", "admin"] } calimero-store = { path = "../store", features = ["datatypes"] } -calimero-context-config = { path = "../context/config" } +calimero-context-config = { path = "../context/config" } [lints] workspace = true diff --git a/crates/node/src/interactive_cli.rs b/crates/node/src/interactive_cli.rs index 2d720da4e..d8bddbbc3 100644 --- a/crates/node/src/interactive_cli.rs +++ b/crates/node/src/interactive_cli.rs @@ -12,6 +12,7 @@ pub mod peers; pub mod state; pub mod store; +use calimero_primitives::blobs::BlobId; use clap::{Parser, Subcommand}; use crate::Node; @@ -34,6 +35,7 @@ pub enum SubCommand { Peers(peers::PeersCommand), // Store(store::StoreCommand), State(state::StateCommand), + Connect, } pub async fn handle_line(node: &mut Node, line: String) -> eyre::Result<()> { @@ -59,6 +61,14 @@ pub async fn handle_line(node: &mut Node, line: String) -> eyre::Result<()> { SubCommand::Peers(peers) => peers.run(node.network_client.clone().into()).await?, SubCommand::State(state) => state.run(node)?, // SubCommand::Store(store) => store.run(node)?, + SubCommand::Connect => { + let addr = + "/ip4/18.156.18.6/udp/4001/quic-v1/p2p/12D3KooWMgoF9xzyeKJHtRvrYwdomheRbHPELagWZwTLmXb6bCVC"; + + let res = node.network_client.dial(addr.parse()?).await; + + dbg!(res); + } } Ok(()) diff --git a/crates/node/src/sync.rs b/crates/node/src/sync.rs index 1d92f9db6..cf4f00c94 100644 --- a/crates/node/src/sync.rs +++ b/crates/node/src/sync.rs @@ -16,6 +16,7 @@ use crate::types::{InitPayload, StreamMessage}; use crate::Node; mod blobs; +mod key_share; mod state; #[derive(Copy, Clone, Debug)] @@ -118,6 +119,9 @@ impl Node { let mut stream = self.network_client.open_stream(chosen_peer).await?; + self.initiate_key_share_process(&mut context, our_identity, &mut stream) + .await?; + if !self.ctx_manager.has_blob_available(application.blob)? { self.initiate_blob_share_process( &context, @@ -223,6 +227,10 @@ impl Node { ) .await? } + InitPayload::KeyShare {} => { + self.handle_key_share_request(context, their_identity, stream) + .await? + } }; Ok(Some(())) diff --git a/crates/node/src/sync/key_share.rs b/crates/node/src/sync/key_share.rs new file mode 100644 index 000000000..bcc6c86bb --- /dev/null +++ b/crates/node/src/sync/key_share.rs @@ -0,0 +1,92 @@ +use calimero_crypto::SharedKey; +use calimero_network::stream::Stream; +use calimero_primitives::context::Context; +use calimero_primitives::identity::PublicKey; +use eyre::{bail, OptionExt}; +use rand::seq::IteratorRandom; +use rand::thread_rng; +use tracing::debug; + +use crate::sync::{recv, send, Sequencer}; +use crate::types::{InitPayload, MessagePayload, StreamMessage}; +use crate::Node; + +impl Node { + pub(super) async fn initiate_key_share_process( + &self, + context: &mut Context, + our_identity: PublicKey, + stream: &mut Stream, + ) -> eyre::Result<()> { + send( + stream, + &StreamMessage::Init { + context_id: context.id, + party_id: our_identity, + payload: InitPayload::KeyShare {}, + }, + None, + ) + .await?; + + let Some(ack) = recv(stream, self.sync_config.timeout, None).await? else { + bail!("connection closed while awaiting state sync handshake"); + }; + + let sender_key = match ack { + StreamMessage::Message { + payload: MessagePayload::KeyShare { sender_key }, + .. + } => sender_key, + unexpected @ (StreamMessage::Init { .. } + | StreamMessage::Message { .. } + | StreamMessage::OpaqueError) => { + bail!("unexpected message: {:?}", unexpected) + } + }; + + // Do I store "his" SenderKey somewhere? + + Ok(()) + } + + pub(super) async fn handle_key_share_request( + &self, + context: Context, + their_identity: PublicKey, + stream: &mut Stream, + ) -> eyre::Result<()> { + debug!( + context_id=%context.id, + their_identity=%their_identity, + "Received key share request", + ); + + let identities = self.ctx_manager.get_context_owned_identities(context.id)?; + + let Some(our_identity) = identities.into_iter().choose(&mut thread_rng()) else { + bail!("no identities found for context: {}", context.id); + }; + + let sender_key = self + .ctx_manager + .get_sender_key(&context.id, &our_identity)? + .ok_or_eyre("expected own identity to have sender key")?; + + let mut sequencer = Sequencer::default(); + + let shared_key = SharedKey::new(&sender_key, &our_identity); + + send( + stream, + &StreamMessage::Message { + sequence_id: sequencer.next(), + payload: MessagePayload::KeyShare { sender_key }, + }, + Some(shared_key), // or None? + ) + .await?; + + Ok(()) + } +} diff --git a/crates/node/src/sync/state.rs b/crates/node/src/sync/state.rs index 388c46e7c..b176adf8d 100644 --- a/crates/node/src/sync/state.rs +++ b/crates/node/src/sync/state.rs @@ -144,7 +144,8 @@ impl Node { application_id: context.application_id, }, }, - Some(shared_key), + None, // I think it should be None here, + // because the first recv in the function above has to have some way of decrypting it? ) .await?; diff --git a/crates/node/src/types.rs b/crates/node/src/types.rs index 223be38c5..824dbe289 100644 --- a/crates/node/src/types.rs +++ b/crates/node/src/types.rs @@ -7,7 +7,7 @@ use calimero_primitives::application::ApplicationId; use calimero_primitives::blobs::BlobId; use calimero_primitives::context::ContextId; use calimero_primitives::hash::Hash; -use calimero_primitives::identity::PublicKey; +use calimero_primitives::identity::{PrivateKey, PublicKey}; use serde::Deserialize; #[derive(Debug, BorshSerialize, BorshDeserialize)] @@ -47,12 +47,14 @@ pub enum InitPayload { root_hash: Hash, application_id: ApplicationId, }, + KeyShare {}, } - +// this I was encrypting #[derive(Debug, BorshSerialize, BorshDeserialize)] pub enum MessagePayload<'a> { StateSync { artifact: Cow<'a, [u8]> }, BlobShare { chunk: Cow<'a, [u8]> }, + KeyShare { sender_key: PrivateKey }, } #[derive(Deserialize)] diff --git a/crates/primitives/src/identity.rs b/crates/primitives/src/identity.rs index 3fe06c866..483796c4c 100644 --- a/crates/primitives/src/identity.rs +++ b/crates/primitives/src/identity.rs @@ -11,6 +11,10 @@ use crate::context::ContextId; use crate::hash::{Hash, HashError}; #[derive(Eq, Copy, Clone, Debug, PartialEq, Serialize, Deserialize)] +#[cfg_attr( + feature = "borsh", + derive(borsh::BorshDeserialize, borsh::BorshSerialize) +)] pub struct PrivateKey(Hash); impl From<[u8; 32]> for PrivateKey { diff --git a/file.patch b/file.patch new file mode 100644 index 000000000..95e0fa137 --- /dev/null +++ b/file.patch @@ -0,0 +1,36 @@ +diff --git a/crates/node/src/interactive_cli.rs b/crates/node/src/interactive_cli.rs +index 2d720da4..d8bddbbc 100644 +--- a/crates/node/src/interactive_cli.rs ++++ b/crates/node/src/interactive_cli.rs +@@ -12,6 +12,7 @@ pub mod peers; + pub mod state; + pub mod store; + ++use calimero_primitives::blobs::BlobId; + use clap::{Parser, Subcommand}; + + use crate::Node; +@@ -34,6 +35,7 @@ pub enum SubCommand { + Peers(peers::PeersCommand), + // Store(store::StoreCommand), + State(state::StateCommand), ++ Connect, + } + + pub async fn handle_line(node: &mut Node, line: String) -> eyre::Result<()> { +@@ -59,6 +61,14 @@ pub async fn handle_line(node: &mut Node, line: String) -> eyre::Result<()> { + SubCommand::Peers(peers) => peers.run(node.network_client.clone().into()).await?, + SubCommand::State(state) => state.run(node)?, + // SubCommand::Store(store) => store.run(node)?, ++ SubCommand::Connect => { ++ let addr = ++ "/ip4/18.156.18.6/udp/4001/quic-v1/p2p/12D3KooWMgoF9xzyeKJHtRvrYwdomheRbHPELagWZwTLmXb6bCVC"; ++ ++ let res = node.network_client.dial(addr.parse()?).await; ++ ++ dbg!(res); ++ } + } + + Ok(()) + } \ No newline at end of file