diff --git a/.gitignore b/.gitignore index bc5142f..8f6f072 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ deps/ data/ .idea/ .vscode/ +rocksdb diff --git a/Cargo.lock b/Cargo.lock index 42d86f3..07a5e93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2729,6 +2729,7 @@ dependencies = [ "actix", "actix-web", "anyhow", + "clap", "consensus", "env_logger", "log", @@ -4083,6 +4084,7 @@ dependencies = [ "consensus", "env_logger", "futures", + "hex", "log", "mempool", "networking", @@ -4347,6 +4349,7 @@ dependencies = [ "anyhow", "elliptic-curve", "env_logger", + "hex", "log", "lru", "monotree", @@ -4815,6 +4818,7 @@ version = "0.1.0" dependencies = [ "anyhow", "env_logger", + "hex", "log", "monotree", "serde", diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 5105d4c..5f13abf 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use anyhow::Result; use k256::AffinePoint; +use log::info; use serde::Serialize; use storage::{merkle_tree_public::TreeHashType, nullifier::UTXONullifier}; use utxo::{ @@ -70,7 +71,7 @@ impl Account { ephemeral_public_key_sender: AffinePoint, ciphertext: CipherText, nonce: Nonce, - ) -> Vec { + ) -> Result, aes_gcm::Error> { self.key_holder .decrypt_data(ephemeral_public_key_sender, ciphertext, nonce) } @@ -115,6 +116,12 @@ impl Account { Ok(()) } + + pub fn log(&self) { + self.key_holder.log(); + info!("Account address is {:?}", hex::encode(self.address)); + info!("Account balance is {:?}", self.balance); + } } impl Default for Account { diff --git a/accounts/src/key_management/ephemeral_key_holder.rs b/accounts/src/key_management/ephemeral_key_holder.rs index 4ae3229..83b4a95 100644 --- a/accounts/src/key_management/ephemeral_key_holder.rs +++ b/accounts/src/key_management/ephemeral_key_holder.rs @@ -40,8 +40,9 @@ impl EphemeralKeyHolder { data: &[u8], ) -> (CipherText, Nonce) { let key_point = self.calculate_shared_secret_sender(viewing_public_key_receiver); - let key_raw = key_point.to_bytes(); - let key_raw_adjust: [u8; 32] = key_raw.as_slice().try_into().unwrap(); + let binding = key_point.to_bytes(); + let key_raw = &binding.as_slice()[..32]; + let key_raw_adjust: [u8; 32] = key_raw.try_into().unwrap(); let key: Key = key_raw_adjust.into(); diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs index df8e6b3..68686da 100644 --- a/accounts/src/key_management/mod.rs +++ b/accounts/src/key_management/mod.rs @@ -3,6 +3,7 @@ use constants_types::{CipherText, Nonce}; use elliptic_curve::group::GroupEncoding; use ephemeral_key_holder::EphemeralKeyHolder; use k256::AffinePoint; +use log::info; use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder}; use storage::merkle_tree_public::TreeHashType; @@ -62,7 +63,7 @@ impl AddressKeyHolder { ephemeral_public_key_sender: AffinePoint, ciphertext: CipherText, nonce: Nonce, - ) -> Vec { + ) -> Result, aes_gcm::Error> { let key_point = self.calculate_shared_secret_receiver(ephemeral_public_key_sender); let binding = key_point.to_bytes(); let key_raw = &binding.as_slice()[..32]; @@ -72,7 +73,27 @@ impl AddressKeyHolder { let cipher = Aes256Gcm::new(&key); - cipher.decrypt(&nonce, ciphertext.as_slice()).unwrap() + cipher.decrypt(&nonce, ciphertext.as_slice()) + } + + pub fn log(&self) { + info!( + "AddressKeyHolder top_secret_key_holder is {:?}", + self.top_secret_key_holder + ); + info!( + "AddressKeyHolder utxo_secret_key_holder is {:?}", + self.utxo_secret_key_holder + ); + info!("AddressKeyHolder address is {:?}", self.address); + info!( + "AddressKeyHolder nullifer_public_key is {:?}", + self.nullifer_public_key + ); + info!( + "AddressKeyHolder viewing_public_key is {:?}", + self.viewing_public_key + ); } } @@ -149,11 +170,13 @@ mod tests { .expect("encryption failure"); // Attempt decryption - let decrypted_data: Vec = address_key_holder.decrypt_data( - ephemeral_public_key_sender, - CipherText::from(ciphertext), - nonce.clone(), - ); + let decrypted_data: Vec = address_key_holder + .decrypt_data( + ephemeral_public_key_sender, + CipherText::from(ciphertext), + nonce.clone(), + ) + .unwrap(); // Verify decryption is successful and matches original plaintext assert_eq!(decrypted_data, plaintext); @@ -216,11 +239,13 @@ mod tests { // Attempt decryption with an incorrect nonce let incorrect_nonce = Nonce::from_slice(b"wrong nonce"); - let decrypted_data = address_key_holder.decrypt_data( - ephemeral_public_key_sender, - CipherText::from(ciphertext.clone()), - incorrect_nonce.clone(), - ); + let decrypted_data = address_key_holder + .decrypt_data( + ephemeral_public_key_sender, + CipherText::from(ciphertext.clone()), + incorrect_nonce.clone(), + ) + .unwrap(); // The decryption should fail or produce incorrect output due to nonce mismatch assert_ne!(decrypted_data, plaintext); @@ -257,11 +282,13 @@ mod tests { corrupted_ciphertext[0] ^= 1; // Flip a bit in the ciphertext // Attempt decryption - let result = address_key_holder.decrypt_data( - ephemeral_public_key_sender, - CipherText::from(corrupted_ciphertext), - nonce.clone(), - ); + let result = address_key_holder + .decrypt_data( + ephemeral_public_key_sender, + CipherText::from(corrupted_ciphertext), + nonce.clone(), + ) + .unwrap(); // The decryption should fail or produce incorrect output due to tampered ciphertext assert_ne!(result, plaintext); @@ -293,11 +320,13 @@ mod tests { .expect("encryption failure"); // Decrypt the data using the `AddressKeyHolder` instance - let decrypted_data = address_key_holder.decrypt_data( - ephemeral_public_key_sender, - CipherText::from(ciphertext), - nonce.clone(), - ); + let decrypted_data = address_key_holder + .decrypt_data( + ephemeral_public_key_sender, + CipherText::from(ciphertext), + nonce.clone(), + ) + .unwrap(); // Verify the decrypted data matches the original plaintext assert_eq!(decrypted_data, plaintext); diff --git a/node_core/src/config.rs b/node_core/src/config.rs index 435de4c..f282a21 100644 --- a/node_core/src/config.rs +++ b/node_core/src/config.rs @@ -12,4 +12,6 @@ pub struct NodeConfig { pub sequencer_addr: String, ///Sequencer polling duration for new blocks in seconds pub seq_poll_timeout_secs: u64, + ///Port to listen + pub port: u16, } diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index 1d5455b..5dc6e40 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -72,6 +72,8 @@ impl NodeCore { let client = Arc::new(SequencerClient::new(config.clone())?); let genesis_id = client.get_genesis_id().await?; + info!("Gesesis id is {genesis_id:?}"); + let genesis_block = client.get_block(genesis_id.genesis_id).await?.block; let mut storage = NodeChainStore::new_with_genesis(&config.home, genesis_block); @@ -84,6 +86,7 @@ impl NodeCore { if let Ok(block) = client.get_block(next_block).await { storage.dissect_insert_block(block.block)?; + info!("Preprocessed block with id {next_block:?}"); } else { break; } @@ -106,7 +109,15 @@ impl NodeCore { { let mut storage_guard = wrapped_storage_thread.write().await; - storage_guard.dissect_insert_block(block.block)?; + let block_insertion_result = + storage_guard.dissect_insert_block(block.block); + + if block_insertion_result.is_err() { + info!("Block insertion failed due to {block_insertion_result:?}"); + + block_insertion_result?; + } + info!("Processed block with id {next_block:?}"); } wrapped_chain_height_thread.store(next_block, Ordering::Relaxed); @@ -130,6 +141,7 @@ impl NodeCore { pub async fn create_new_account(&mut self) -> AccountAddress { let account = Account::new(); + account.log(); let addr = account.address; @@ -153,6 +165,7 @@ impl NodeCore { let acc_map_read_guard = self.storage.read().await; let accout = acc_map_read_guard.acc_map.get(&acc).unwrap(); + accout.log(); let ephm_key_holder = &accout.produce_ephemeral_key_holder(); @@ -207,17 +220,13 @@ impl NodeCore { pub async fn transfer_utxo_private( &self, utxo: UTXO, + commitment_in: [u8; 32], receivers: Vec<(u128, AccountAddress)>, ) -> (Transaction, Vec<(AccountAddress, [u8; 32])>) { let acc_map_read_guard = self.storage.read().await; let accout = acc_map_read_guard.acc_map.get(&utxo.owner).unwrap(); - - let commitment_in = { - let guard = self.storage.write().await; - - guard.utxo_commitments_store.get_tx(utxo.hash).unwrap().hash - }; + accout.log(); let nullifier = generate_nullifiers( &utxo, @@ -290,6 +299,7 @@ impl NodeCore { let acc_map_read_guard = self.storage.read().await; let accout = acc_map_read_guard.acc_map.get(&acc).unwrap(); + accout.log(); let commitment_secrets = CommitmentSecrets { value: balance, @@ -352,7 +362,7 @@ impl NodeCore { ( TransactionPayload { - tx_kind: TxKind::Private, + tx_kind: TxKind::Shielded, execution_input: serde_json::to_vec(&ActionData::SendMoneyShieldedTx( SendMoneyShieldedTx { acc_sender: acc, @@ -379,17 +389,19 @@ impl NodeCore { pub async fn transfer_utxo_deshielded( &self, utxo: UTXO, + comm_gen_hash: [u8; 32], receivers: Vec<(u128, AccountAddress)>, ) -> Transaction { let acc_map_read_guard = self.storage.read().await; + let commitment_in = acc_map_read_guard + .utxo_commitments_store + .get_tx(comm_gen_hash) + .unwrap() + .hash; + let accout = acc_map_read_guard.acc_map.get(&utxo.owner).unwrap(); - - let commitment_in = { - let guard = self.storage.write().await; - - guard.utxo_commitments_store.get_tx(utxo.hash).unwrap().hash - }; + accout.log(); let nullifier = generate_nullifiers( &utxo, @@ -404,14 +416,14 @@ impl NodeCore { let (resulting_balances, receipt) = prove_send_utxo_deshielded(utxo, receivers); TransactionPayload { - tx_kind: TxKind::Private, - execution_input: vec![], - execution_output: serde_json::to_vec(&ActionData::SendMoneyDeshieldedTx( + tx_kind: TxKind::Deshielded, + execution_input: serde_json::to_vec(&ActionData::SendMoneyDeshieldedTx( SendMoneyDeshieldedTx { receiver_data: resulting_balances, }, )) .unwrap(), + execution_output: vec![], utxo_commitments_spent_hashes: vec![commitment_in], utxo_commitments_created_hashes: vec![], nullifier_created_hashes: vec![nullifier.try_into().unwrap()], @@ -426,15 +438,22 @@ impl NodeCore { &self, acc: AccountAddress, amount: u128, - ) -> Result<(SendTxResponse, [u8; 32])> { + ) -> Result<(SendTxResponse, [u8; 32], [u8; 32])> { let point_before_prove = std::time::Instant::now(); let (tx, utxo_hash) = self.mint_utxo_private(acc, amount).await; + tx.log(); let point_after_prove = std::time::Instant::now(); + let commitment_generated_hash = tx.utxo_commitments_created_hashes[0]; + let timedelta = (point_after_prove - point_before_prove).as_millis(); info!("Mint utxo proof spent {timedelta:?} milliseconds"); - Ok((self.sequencer_client.send_tx(tx).await?, utxo_hash)) + Ok(( + self.sequencer_client.send_tx(tx).await?, + utxo_hash, + commitment_generated_hash, + )) } pub async fn send_public_deposit( @@ -451,10 +470,12 @@ impl NodeCore { pub async fn send_private_send_tx( &self, utxo: UTXO, + comm_hash: [u8; 32], receivers: Vec<(u128, AccountAddress)>, ) -> Result<(SendTxResponse, Vec<([u8; 32], [u8; 32])>)> { let point_before_prove = std::time::Instant::now(); - let (tx, utxo_hashes) = self.transfer_utxo_private(utxo, receivers).await; + let (tx, utxo_hashes) = self.transfer_utxo_private(utxo, comm_hash, receivers).await; + tx.log(); let point_after_prove = std::time::Instant::now(); let timedelta = (point_after_prove - point_before_prove).as_millis(); @@ -471,6 +492,7 @@ impl NodeCore { ) -> Result<(SendTxResponse, Vec<([u8; 32], [u8; 32])>)> { let point_before_prove = std::time::Instant::now(); let (tx, utxo_hashes) = self.transfer_balance_shielded(acc, amount, receivers).await; + tx.log(); let point_after_prove = std::time::Instant::now(); let timedelta = (point_after_prove - point_before_prove).as_millis(); @@ -482,10 +504,14 @@ impl NodeCore { pub async fn send_deshielded_send_tx( &self, utxo: UTXO, + comm_gen_hash: [u8; 32], receivers: Vec<(u128, AccountAddress)>, ) -> Result { let point_before_prove = std::time::Instant::now(); - let tx = self.transfer_utxo_deshielded(utxo, receivers).await; + let tx = self + .transfer_utxo_deshielded(utxo, comm_gen_hash, receivers) + .await; + tx.log(); let point_after_prove = std::time::Instant::now(); let timedelta = (point_after_prove - point_before_prove).as_millis(); @@ -497,8 +523,10 @@ impl NodeCore { ///Mint utxo, make it public pub async fn subscenario_1(&mut self) { let acc_addr = self.create_new_account().await; + info!("Account created {acc_addr:?}"); - let (resp, new_utxo_hash) = self.send_private_mint_tx(acc_addr, 100).await.unwrap(); + let (resp, new_utxo_hash, comm_gen_hash) = + self.send_private_mint_tx(acc_addr, 100).await.unwrap(); info!("Response for mint private is {resp:?}"); info!("Awaiting new blocks"); @@ -508,6 +536,7 @@ impl NodeCore { let mut write_guard = self.storage.write().await; let acc = write_guard.acc_map.get_mut(&acc_addr).unwrap(); + acc.log(); acc.utxo_tree .get_item(new_utxo_hash) @@ -516,10 +545,10 @@ impl NodeCore { .clone() }; - let acc_map_read_guard = self.storage.read().await; - let acc = acc_map_read_guard.acc_map.get(&acc_addr).unwrap(); + new_utxo.log(); + let resp = self - .send_deshielded_send_tx(new_utxo, vec![(100, acc_addr)]) + .send_deshielded_send_tx(new_utxo, comm_gen_hash, vec![(100, acc_addr)]) .await .unwrap(); info!("Response for send deshielded is {resp:?}"); @@ -527,7 +556,16 @@ impl NodeCore { info!("Awaiting new blocks"); tokio::time::sleep(std::time::Duration::from_secs(BLOCK_GEN_DELAY_SECS)).await; - info!("New account public balance is {:?}", acc.balance); + let new_balance = { + let acc_map_read_guard = self.storage.read().await; + + let acc = acc_map_read_guard.acc_map.get(&acc_addr).unwrap(); + acc.log(); + + acc.balance + }; + + info!("New account public balance is {new_balance:?}"); } ///Deposit balance, make it private @@ -540,10 +578,14 @@ impl NodeCore { info!("Awaiting new blocks"); tokio::time::sleep(std::time::Duration::from_secs(BLOCK_GEN_DELAY_SECS)).await; - let acc_map_read_guard = self.storage.read().await; - let acc = acc_map_read_guard.acc_map.get(&acc_addr).unwrap(); + { + let acc_map_read_guard = self.storage.read().await; - info!("New acconut public balance is {:?}", acc.balance); + let acc = acc_map_read_guard.acc_map.get(&acc_addr).unwrap(); + acc.log(); + + info!("New acconut public balance is {:?}", acc.balance); + }; let (resp, new_utxo_hashes) = self .send_shielded_send_tx(acc_addr, 100, vec![(100, acc_addr)]) @@ -560,6 +602,7 @@ impl NodeCore { let mut write_guard = self.storage.write().await; let acc = write_guard.acc_map.get_mut(&acc_addr).unwrap(); + acc.log(); acc.utxo_tree .get_item(new_utxo_hash) @@ -567,15 +610,17 @@ impl NodeCore { .unwrap() .clone() }; + new_utxo.log(); + info!("User received new utxo {new_utxo:?}"); } ///Mint utxo, privately send it to another user pub async fn subscenario_3(&mut self) { let acc_addr = self.create_new_account().await; - let acc_addr_rec = self.create_new_account().await; - let (resp, new_utxo_hash) = self.send_private_mint_tx(acc_addr, 100).await.unwrap(); + let (resp, new_utxo_hash, comm_gen_hash) = + self.send_private_mint_tx(acc_addr, 100).await.unwrap(); info!("Response for mint private is {resp:?}"); info!("Awaiting new blocks"); @@ -585,6 +630,7 @@ impl NodeCore { let mut write_guard = self.storage.write().await; let acc = write_guard.acc_map.get_mut(&acc_addr).unwrap(); + acc.log(); acc.utxo_tree .get_item(new_utxo_hash) @@ -592,9 +638,12 @@ impl NodeCore { .unwrap() .clone() }; + new_utxo.log(); + + let acc_addr_rec = self.create_new_account().await; let (resp, new_utxo_hashes) = self - .send_private_send_tx(new_utxo, vec![(100, acc_addr_rec)]) + .send_private_send_tx(new_utxo, comm_gen_hash, vec![(100, acc_addr_rec)]) .await .unwrap(); info!("Response for send deshielded is {resp:?}"); @@ -608,6 +657,7 @@ impl NodeCore { let mut write_guard = self.storage.write().await; let acc = write_guard.acc_map.get_mut(&acc_addr_rec).unwrap(); + acc.log(); acc.utxo_tree .get_item(new_utxo_hash) @@ -630,10 +680,13 @@ impl NodeCore { info!("Awaiting new blocks"); tokio::time::sleep(std::time::Duration::from_secs(BLOCK_GEN_DELAY_SECS)).await; - let acc_map_read_guard = self.storage.read().await; - let acc = acc_map_read_guard.acc_map.get(&acc_addr).unwrap(); + { + let acc_map_read_guard = self.storage.read().await; + let acc = acc_map_read_guard.acc_map.get(&acc_addr).unwrap(); + acc.log(); - info!("New acconut public balance is {:?}", acc.balance); + info!("New acconut public balance is {:?}", acc.balance); + } let (resp, new_utxo_hashes) = self .send_shielded_send_tx(acc_addr, 100, vec![(100, acc_addr_rec)]) @@ -650,6 +703,7 @@ impl NodeCore { let mut write_guard = self.storage.write().await; let acc = write_guard.acc_map.get_mut(&acc_addr_rec).unwrap(); + acc.log(); acc.utxo_tree .get_item(new_utxo_hash) @@ -666,7 +720,8 @@ impl NodeCore { let acc_addr = self.create_new_account().await; let acc_addr_rec = self.create_new_account().await; - let (resp, new_utxo_hash) = self.send_private_mint_tx(acc_addr, 100).await.unwrap(); + let (resp, new_utxo_hash, comm_gen_hash) = + self.send_private_mint_tx(acc_addr, 100).await.unwrap(); info!("Response for mint private is {resp:?}"); info!("Awaiting new blocks"); @@ -676,6 +731,7 @@ impl NodeCore { let mut write_guard = self.storage.write().await; let acc = write_guard.acc_map.get_mut(&acc_addr).unwrap(); + acc.log(); acc.utxo_tree .get_item(new_utxo_hash) @@ -683,9 +739,10 @@ impl NodeCore { .unwrap() .clone() }; + new_utxo.log(); let resp = self - .send_deshielded_send_tx(new_utxo, vec![(100, acc_addr_rec)]) + .send_deshielded_send_tx(new_utxo, comm_gen_hash, vec![(100, acc_addr_rec)]) .await .unwrap(); info!("Response for send deshielded is {resp:?}"); @@ -693,9 +750,12 @@ impl NodeCore { info!("Awaiting new blocks"); tokio::time::sleep(std::time::Duration::from_secs(BLOCK_GEN_DELAY_SECS)).await; - let read_guard = self.storage.read().await; - let acc_rec = read_guard.acc_map.get(&acc_addr_rec).unwrap(); + { + let read_guard = self.storage.read().await; + let acc_rec = read_guard.acc_map.get(&acc_addr_rec).unwrap(); + acc_rec.log(); - info!("New account public balance is {:?}", acc_rec.balance); + info!("New account public balance is {:?}", acc_rec.balance); + } } } diff --git a/node_core/src/sequencer_client/json.rs b/node_core/src/sequencer_client/json.rs index 4865f81..39105a8 100644 --- a/node_core/src/sequencer_client/json.rs +++ b/node_core/src/sequencer_client/json.rs @@ -67,3 +67,10 @@ impl SequencerRpcRequest { } } } + +#[derive(Debug, Clone, Deserialize)] +pub struct SequencerRpcResponse { + pub jsonrpc: String, + pub result: serde_json::Value, + pub id: u64, +} diff --git a/node_core/src/sequencer_client/mod.rs b/node_core/src/sequencer_client/mod.rs index 0fe041d..50bab57 100644 --- a/node_core/src/sequencer_client/mod.rs +++ b/node_core/src/sequencer_client/mod.rs @@ -3,7 +3,7 @@ use anyhow::Result; use json::{ GetBlockDataRequest, GetBlockDataResponse, GetGenesisIdRequest, GetGenesisIdResponse, RegisterAccountRequest, RegisterAccountResponse, SendTxRequest, SendTxResponse, - SequencerRpcRequest, + SequencerRpcRequest, SequencerRpcResponse, }; use k256::elliptic_curve::group::GroupEncoding; use reqwest::Client; @@ -62,9 +62,9 @@ impl SequencerClient { let call_res = call_builder.json(&request).send().await?; - let response = call_res.json::().await?; + let response = call_res.json::().await?; - Ok(response) + Ok(response.result) } pub async fn get_block( @@ -121,11 +121,14 @@ impl SequencerClient { pub async fn get_genesis_id(&self) -> Result { let genesis_req = GetGenesisIdRequest {}; - let req = serde_json::to_value(genesis_req)?; + let req = serde_json::to_value(genesis_req).unwrap(); - let resp = self.call_method_with_payload("get_genesis", req).await?; + let resp = self + .call_method_with_payload("get_genesis", req) + .await + .unwrap(); - let resp_deser = serde_json::from_value(resp)?; + let resp_deser = serde_json::from_value(resp).unwrap(); Ok(resp_deser) } diff --git a/node_core/src/storage/mod.rs b/node_core/src/storage/mod.rs index 93abee2..869a72e 100644 --- a/node_core/src/storage/mod.rs +++ b/node_core/src/storage/mod.rs @@ -19,6 +19,8 @@ use storage::{ }; use utxo::utxo_core::UTXO; +use crate::ActionData; + pub mod accounts_store; pub mod block_store; @@ -54,6 +56,39 @@ impl NodeChainStore { pub fn dissect_insert_block(&mut self, block: Block) -> Result<()> { for tx in &block.transactions { + if !tx.execution_input.is_empty() { + let public_action = serde_json::from_slice::(&tx.execution_input); + + if let Ok(public_action) = public_action { + match public_action { + ActionData::MintMoneyPublicTx(action) => { + let acc_mut = self.acc_map.get_mut(&action.acc); + + if let Some(acc_mut) = acc_mut { + acc_mut.balance += action.amount as u64; + } + } + ActionData::SendMoneyDeshieldedTx(action) => { + for (balance, acc_addr) in action.receiver_data { + let acc_mut = self.acc_map.get_mut(&acc_addr); + + if let Some(acc_mut) = acc_mut { + acc_mut.balance += balance as u64; + } + } + } + ActionData::SendMoneyShieldedTx(action) => { + let acc_mut = self.acc_map.get_mut(&action.acc_sender); + + if let Some(acc_mut) = acc_mut { + acc_mut.balance = + acc_mut.balance.saturating_sub(action.amount as u64); + } + } + } + } + } + self.utxo_commitments_store.add_tx_multiple( tx.utxo_commitments_created_hashes .clone() @@ -94,12 +129,14 @@ impl NodeChainStore { nonce, ); - let decoded_utxo_try = - serde_json::from_slice::(&decoded_data_curr_acc); + if let Ok(decoded_data_curr_acc) = decoded_data_curr_acc { + let decoded_utxo_try = + serde_json::from_slice::(&decoded_data_curr_acc); - if let Ok(utxo) = decoded_utxo_try { - if &utxo.owner == acc_id { - acc.utxo_tree.insert_item(utxo)?; + if let Ok(utxo) = decoded_utxo_try { + if &utxo.owner == acc_id { + acc.utxo_tree.insert_item(utxo)?; + } } } } diff --git a/node_rpc/src/process.rs b/node_rpc/src/process.rs index 8622f60..1ee0b0c 100644 --- a/node_rpc/src/process.rs +++ b/node_rpc/src/process.rs @@ -1,3 +1,5 @@ +use std::sync::atomic::Ordering; + use actix_web::Error as HttpError; use serde_json::Value; @@ -12,8 +14,9 @@ use crate::{ types::{ err_rpc::cast_seq_client_error_into_rpc_error, rpc_structs::{ - ExecuteSubscenarioRequest, ExecuteSubscenarioResponse, RegisterAccountRequest, - RegisterAccountResponse, SendTxRequest, + ExecuteSubscenarioRequest, ExecuteSubscenarioResponse, GetBlockDataRequest, + GetBlockDataResponse, GetLastBlockRequest, GetLastBlockResponse, + RegisterAccountRequest, RegisterAccountResponse, SendTxRequest, }, }, }; @@ -96,12 +99,46 @@ impl JsonHandler { respond(helperstruct) } + async fn process_get_block_data(&self, request: Request) -> Result { + let req = GetBlockDataRequest::parse(Some(request.params))?; + + let block = { + let guard = self.node_chain_store.lock().await; + + { + let read_guard = guard.storage.read().await; + + read_guard.block_store.get_block_at_id(req.block_id)? + } + }; + + let helperstruct = GetBlockDataResponse { block }; + + respond(helperstruct) + } + + async fn process_get_last_block(&self, request: Request) -> Result { + let _req = GetLastBlockRequest::parse(Some(request.params))?; + + let last_block = { + let guard = self.node_chain_store.lock().await; + + guard.curr_height.load(Ordering::Relaxed) + }; + + let helperstruct = GetLastBlockResponse { last_block }; + + respond(helperstruct) + } + pub async fn process_request_internal(&self, request: Request) -> Result { match request.method.as_ref() { //Todo : Add handling of more JSON RPC methods "register_account" => self.process_register_account(request).await, "execute_subscenario" => self.process_request_execute_subscenario(request).await, "send_tx" => self.process_send_tx(request).await, + "get_block" => self.process_get_block_data(request).await, + "get_last_block" => self.process_get_last_block(request).await, _ => Err(RpcErr(RpcError::method_not_found(request.method))), } } diff --git a/node_rpc/src/types/rpc_structs.rs b/node_rpc/src/types/rpc_structs.rs index ce1a43e..fbb3afe 100644 --- a/node_rpc/src/types/rpc_structs.rs +++ b/node_rpc/src/types/rpc_structs.rs @@ -28,11 +28,15 @@ pub struct ExecuteSubscenarioRequest { #[derive(Serialize, Deserialize, Debug)] pub struct GetGenesisIdRequest {} +#[derive(Serialize, Deserialize, Debug)] +pub struct GetLastBlockRequest {} + parse_request!(RegisterAccountRequest); parse_request!(SendTxRequest); parse_request!(GetBlockDataRequest); parse_request!(GetGenesisIdRequest); parse_request!(ExecuteSubscenarioRequest); +parse_request!(GetLastBlockRequest); #[derive(Serialize, Deserialize, Debug)] pub struct HelloResponse { @@ -63,3 +67,8 @@ pub struct ExecuteSubscenarioResponse { pub struct GetGenesisIdResponse { pub genesis_id: u64, } + +#[derive(Serialize, Deserialize, Debug)] +pub struct GetLastBlockResponse { + pub last_block: u64, +} diff --git a/node_runner/Cargo.toml b/node_runner/Cargo.toml index 6b2e6be..c38f24f 100644 --- a/node_runner/Cargo.toml +++ b/node_runner/Cargo.toml @@ -14,6 +14,10 @@ actix.workspace = true actix-web.workspace = true tokio.workspace = true +[dependencies.clap] +features = ["derive", "env"] +workspace = true + [dependencies.accounts] path = "../accounts" diff --git a/node_runner/configs/debug/node_config.json b/node_runner/configs/debug/node_config.json new file mode 100644 index 0000000..e1dd6b7 --- /dev/null +++ b/node_runner/configs/debug/node_config.json @@ -0,0 +1,7 @@ +{ + "home": ".", + "override_rust_log": null, + "sequencer_addr": "http://127.0.0.1:3040", + "seq_poll_timeout_secs": 10, + "port": 3041 +} \ No newline at end of file diff --git a/node_runner/src/config.rs b/node_runner/src/config.rs new file mode 100644 index 0000000..988b0f2 --- /dev/null +++ b/node_runner/src/config.rs @@ -0,0 +1,14 @@ +use std::path::PathBuf; + +use anyhow::Result; +use node_core::config::NodeConfig; + +use std::fs::File; +use std::io::BufReader; + +pub fn from_file(config_home: PathBuf) -> Result { + let file = File::open(config_home)?; + let reader = BufReader::new(file); + + Ok(serde_json::from_reader(reader)?) +} diff --git a/node_runner/src/lib.rs b/node_runner/src/lib.rs index 8641da5..0bdaeb9 100644 --- a/node_runner/src/lib.rs +++ b/node_runner/src/lib.rs @@ -1,31 +1,40 @@ use std::{path::PathBuf, sync::Arc}; use anyhow::Result; +use clap::Parser; use consensus::ConsensusManager; use log::info; use networking::peer_manager::PeerManager; -use node_core::{config::NodeConfig, NodeCore}; +use node_core::NodeCore; use node_rpc::new_http_server; use rpc_primitives::RpcConfig; use tokio::sync::Mutex; +pub mod config; + +#[derive(Parser, Debug)] +#[clap(version)] +struct Args { + /// Path to configs + home_dir: PathBuf, +} + pub async fn main_runner() -> Result<()> { env_logger::init(); - //ToDo: Change it - let node_config = NodeConfig { - home: PathBuf::new(), - override_rust_log: None, - sequencer_addr: "addr".to_string(), - seq_poll_timeout_secs: 1, - }; + let args = Args::parse(); + let Args { home_dir } = args; - let node_core = NodeCore::start_from_config_update_chain(node_config.clone()).await?; + let app_config = config::from_file(home_dir.join("node_config.json"))?; + + let port = app_config.port; + + let node_core = NodeCore::start_from_config_update_chain(app_config.clone()).await?; let wrapped_node_core = Arc::new(Mutex::new(node_core)); let http_server = new_http_server( - RpcConfig::default(), - node_config.clone(), + RpcConfig::with_port(port), + app_config.clone(), wrapped_node_core.clone(), )?; info!("HTTP server started"); diff --git a/sequencer_core/src/config.rs b/sequencer_core/src/config.rs index 0767146..53b18a9 100644 --- a/sequencer_core/src/config.rs +++ b/sequencer_core/src/config.rs @@ -1,4 +1,4 @@ -use std::{path::PathBuf, time::Duration}; +use std::path::PathBuf; use serde::{Deserialize, Serialize}; @@ -15,5 +15,7 @@ pub struct SequencerConfig { ///Maximum number of transactions in block pub max_num_tx_in_block: usize, ///Interval in which blocks produced - pub block_create_timeout_millis: Duration, + pub block_create_timeout_millis: u64, + ///Port to listen + pub port: u16, } diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 53aec6f..04c1656 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -181,7 +181,7 @@ impl SequencerCore { .store .block_store .get_block_at_id(self.chain_height)? - .prev_block_hash; + .hash; let hashable_data = HashableBlockData { block_id: self.chain_height + 1, diff --git a/sequencer_rpc/Cargo.toml b/sequencer_rpc/Cargo.toml index 57e319b..78df1ed 100644 --- a/sequencer_rpc/Cargo.toml +++ b/sequencer_rpc/Cargo.toml @@ -12,6 +12,7 @@ serde.workspace = true actix.workspace = true actix-cors.workspace = true futures.workspace = true +hex.workspace = true actix-web.workspace = true tokio.workspace = true diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index 8e17f6f..7030913 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -12,8 +12,8 @@ use crate::{ rpc_error_responce_inverter, types::rpc_structs::{ GetBlockDataRequest, GetBlockDataResponse, GetGenesisIdRequest, GetGenesisIdResponse, - HelloRequest, HelloResponse, RegisterAccountRequest, RegisterAccountResponse, - SendTxRequest, SendTxResponse, + GetLastBlockRequest, GetLastBlockResponse, HelloRequest, HelloResponse, + RegisterAccountRequest, RegisterAccountResponse, SendTxRequest, SendTxResponse, }, }; @@ -115,6 +115,20 @@ impl JsonHandler { respond(helperstruct) } + async fn process_get_last_block(&self, request: Request) -> Result { + let _get_last_block_req = GetLastBlockRequest::parse(Some(request.params))?; + + let last_block = { + let state = self.sequencer_state.lock().await; + + state.chain_height + }; + + let helperstruct = GetLastBlockResponse { last_block }; + + respond(helperstruct) + } + pub async fn process_request_internal(&self, request: Request) -> Result { match request.method.as_ref() { "hello" => self.process_temp_hello(request).await, @@ -122,6 +136,7 @@ impl JsonHandler { "send_tx" => self.process_send_tx(request).await, "get_block" => self.process_get_block_data(request).await, "get_genesis" => self.process_get_genesis(request).await, + "get_last_block" => self.process_get_last_block(request).await, _ => Err(RpcErr(RpcError::method_not_found(request.method))), } } diff --git a/sequencer_rpc/src/types/rpc_structs.rs b/sequencer_rpc/src/types/rpc_structs.rs index 3e09507..5b375b4 100644 --- a/sequencer_rpc/src/types/rpc_structs.rs +++ b/sequencer_rpc/src/types/rpc_structs.rs @@ -6,6 +6,8 @@ use sequencer_core::transaction_mempool::TransactionMempool; use serde::{Deserialize, Serialize}; use serde_json::Value; use storage::block::Block; +use storage::block::BlockId; +use storage::transaction::Transaction; #[derive(Serialize, Deserialize, Debug)] pub struct HelloRequest {} @@ -30,11 +32,15 @@ pub struct GetBlockDataRequest { #[derive(Serialize, Deserialize, Debug)] pub struct GetGenesisIdRequest {} +#[derive(Serialize, Deserialize, Debug)] +pub struct GetLastBlockRequest {} + parse_request!(HelloRequest); parse_request!(RegisterAccountRequest); parse_request!(SendTxRequest); parse_request!(GetBlockDataRequest); parse_request!(GetGenesisIdRequest); +parse_request!(GetLastBlockRequest); #[derive(Serialize, Deserialize, Debug)] pub struct HelloResponse { @@ -60,3 +66,8 @@ pub struct GetBlockDataResponse { pub struct GetGenesisIdResponse { pub genesis_id: u64, } + +#[derive(Serialize, Deserialize, Debug)] +pub struct GetLastBlockResponse { + pub last_block: u64, +} diff --git a/sequencer_runner/configs/debug/sequencer_config.json b/sequencer_runner/configs/debug/sequencer_config.json index 91c2ab6..5eccadd 100644 --- a/sequencer_runner/configs/debug/sequencer_config.json +++ b/sequencer_runner/configs/debug/sequencer_config.json @@ -4,5 +4,6 @@ "genesis_id": 1, "is_genesis_random": true, "max_num_tx_in_block": 20, - "block_create_timeout_millis": 10000 + "block_create_timeout_millis": 10000, + "port": 3040 } \ No newline at end of file diff --git a/sequencer_runner/src/lib.rs b/sequencer_runner/src/lib.rs index e3a4507..a222583 100644 --- a/sequencer_runner/src/lib.rs +++ b/sequencer_runner/src/lib.rs @@ -24,6 +24,7 @@ pub async fn main_runner() -> Result<()> { let app_config = config::from_file(home_dir.join("sequencer_config.json"))?; let block_timeout = app_config.block_create_timeout_millis; + let port = app_config.port; if let Some(ref rust_log) = app_config.override_rust_log { info!("RUST_LOG env var set to {rust_log:?}"); @@ -39,7 +40,7 @@ pub async fn main_runner() -> Result<()> { let seq_core_wrapped = Arc::new(Mutex::new(sequencer_core)); - let http_server = new_http_server(RpcConfig::default(), seq_core_wrapped.clone())?; + let http_server = new_http_server(RpcConfig::with_port(port), seq_core_wrapped.clone())?; info!("HTTP server started"); let _http_server_handle = http_server.handle(); tokio::spawn(http_server); @@ -48,7 +49,7 @@ pub async fn main_runner() -> Result<()> { #[allow(clippy::empty_loop)] loop { - tokio::time::sleep(block_timeout).await; + tokio::time::sleep(std::time::Duration::from_millis(block_timeout)).await; info!("Collecting transactions from mempool, block creation"); diff --git a/storage/Cargo.toml b/storage/Cargo.toml index cce6d2c..0da0fc3 100644 --- a/storage/Cargo.toml +++ b/storage/Cargo.toml @@ -12,6 +12,7 @@ serde.workspace = true lru.workspace = true thiserror.workspace = true elliptic-curve.workspace = true +hex.workspace = true rocksdb.workspace = true rs_merkle.workspace = true diff --git a/storage/src/transaction.rs b/storage/src/transaction.rs index 35dd9f5..545b14e 100644 --- a/storage/src/transaction.rs +++ b/storage/src/transaction.rs @@ -1,3 +1,4 @@ +use log::info; use serde::{Deserialize, Serialize}; use sha2::{digest::FixedOutput, Digest}; @@ -89,3 +90,50 @@ impl From for Transaction { } } } + +impl Transaction { + pub fn log(&self) { + info!("Transaction hash is {:?}", hex::encode(self.hash)); + info!("Transaction tx_kind is {:?}", self.tx_kind); + info!( + "Transaction execution_input is {:?}", + hex::encode(self.execution_input.clone()) + ); + info!( + "Transaction execution_output is {:?}", + hex::encode(self.execution_output.clone()) + ); + info!( + "Transaction utxo_commitments_spent_hashes is {:?}", + self.utxo_commitments_spent_hashes + .iter() + .map(|val| hex::encode(val.clone())) + ); + info!( + "Transaction utxo_commitments_created_hashes is {:?}", + self.utxo_commitments_created_hashes + .iter() + .map(|val| hex::encode(val.clone())) + ); + info!( + "Transaction nullifier_created_hashes is {:?}", + self.nullifier_created_hashes + .iter() + .map(|val| hex::encode(val.clone())) + ); + info!( + "Transaction execution_proof_private is {:?}", + self.execution_proof_private + ); + info!( + "Transaction encoded_data is {:?}", + self.encoded_data + .iter() + .map(|val| (hex::encode(val.0.clone()), hex::encode(val.1.clone()))) + ); + info!( + "Transaction ephemeral_pub_key is {:?}", + hex::encode(self.ephemeral_pub_key.clone()) + ); + } +} diff --git a/utxo/Cargo.toml b/utxo/Cargo.toml index 09b9a13..cfee505 100644 --- a/utxo/Cargo.toml +++ b/utxo/Cargo.toml @@ -11,6 +11,7 @@ log.workspace = true serde.workspace = true monotree.workspace = true sha2.workspace = true +hex.workspace = true [dependencies.storage] path = "../storage" diff --git a/utxo/src/utxo_core.rs b/utxo/src/utxo_core.rs index 1d79398..6a03ee4 100644 --- a/utxo/src/utxo_core.rs +++ b/utxo/src/utxo_core.rs @@ -1,4 +1,5 @@ use anyhow::Result; +use log::info; use serde::{Deserialize, Serialize}; use sha2::{digest::FixedOutput, Digest}; use storage::{merkle_tree_public::TreeHashType, nullifier::UTXONullifier, AccountId}; @@ -60,6 +61,27 @@ impl UTXO { pub fn interpret_asset<'de, ToInterpret: Deserialize<'de>>(&'de self) -> Result { Ok(serde_json::from_slice(&self.asset)?) } + + pub fn into_payload(&self) -> UTXOPayload { + UTXOPayload { + owner: self.owner, + asset: self.asset.clone(), + amount: self.amount, + privacy_flag: self.privacy_flag, + } + } + + pub fn log(&self) { + info!("UTXO hash is {:?}", hex::encode(self.hash)); + info!("UTXO owner is {:?}", self.owner); + info!( + "UTXO nullifier is {:?}", + self.nullifier.clone().map(|val| hex::encode(val.utxo_hash)) + ); + info!("UTXO asset is {:?}", hex::encode(self.asset.clone())); + info!("UTXO amount is {:?}", self.amount); + info!("UTXO privacy_flag is {:?}", self.privacy_flag); + } } #[cfg(test)] diff --git a/zkvm/src/lib.rs b/zkvm/src/lib.rs index 72dfa0b..2eaf694 100644 --- a/zkvm/src/lib.rs +++ b/zkvm/src/lib.rs @@ -27,8 +27,9 @@ pub fn prove_send_utxo( owners_parts: Vec<(u128, AccountAddress)>, ) -> (Vec<(UTXO, AccountAddress)>, Receipt) { let mut builder = ExecutorEnv::builder(); + let utxo_payload = spent_utxo.into_payload(); - builder.write(&spent_utxo).unwrap(); + builder.write(&utxo_payload).unwrap(); builder.write(&owners_parts).unwrap(); let env = builder.build().unwrap(); @@ -62,10 +63,11 @@ pub fn prove_send_utxo_shielded( amount, privacy_flag: true, }); + let utxo_payload = temp_utxo_to_spend.into_payload(); let mut builder = ExecutorEnv::builder(); - builder.write(&temp_utxo_to_spend).unwrap(); + builder.write(&utxo_payload).unwrap(); builder.write(&owners_parts).unwrap(); let env = builder.build().unwrap(); @@ -93,8 +95,9 @@ pub fn prove_send_utxo_deshielded( owners_parts: Vec<(u128, AccountAddress)>, ) -> (Vec<(u128, AccountAddress)>, Receipt) { let mut builder = ExecutorEnv::builder(); + let utxo_payload = spent_utxo.into_payload(); - builder.write(&spent_utxo).unwrap(); + builder.write(&utxo_payload).unwrap(); builder.write(&owners_parts).unwrap(); let env = builder.build().unwrap(); @@ -140,7 +143,9 @@ pub fn execute_send_utxo( ) -> (UTXO, Vec<(UTXO, AccountAddress)>) { let mut builder = ExecutorEnv::builder(); - builder.write(&spent_utxo).unwrap(); + let utxo_payload = spent_utxo.into_payload(); + + builder.write(&utxo_payload).unwrap(); builder.write(&owners_parts).unwrap(); let env = builder.build().unwrap(); diff --git a/zkvm/test_methods/guest/Cargo.lock b/zkvm/test_methods/guest/Cargo.lock index 20a7a7a..0ee4887 100644 --- a/zkvm/test_methods/guest/Cargo.lock +++ b/zkvm/test_methods/guest/Cargo.lock @@ -845,9 +845,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.134" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" dependencies = [ "itoa", "memchr",