diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 071fa8d..6ebfca7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,7 @@ on: push: branches: - - master + - main paths-ignore: - "**.md" - "!.github/workflows/*.yml" @@ -21,15 +21,14 @@ jobs: name: ubuntu-latest-pipeline steps: - uses: actions/checkout@v3 - - name: Install stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - components: rustfmt, clippy + + - name: Install active toolchain + run: rustup install + + - name: Install nightly toolchain for rustfmt + run: rustup install nightly --profile minimal --component rustfmt + - name: lint - ubuntu-latest - if: success() || failure() run: chmod 777 ./ci_scripts/lint-ubuntu.sh && ./ci_scripts/lint-ubuntu.sh - name: test ubuntu-latest if: success() || failure() diff --git a/ci_scripts/lint-ubuntu.sh b/ci_scripts/lint-ubuntu.sh index 16d46a2..dcfcfc6 100755 --- a/ci_scripts/lint-ubuntu.sh +++ b/ci_scripts/lint-ubuntu.sh @@ -1,8 +1,8 @@ set -e -cargo install taplo-cli --locked +cargo +nightly fmt -- --check -cargo fmt -- --check +cargo install taplo-cli --locked taplo fmt --check RISC0_SKIP_BUILD=1 cargo clippy --workspace --all-targets -- -D warnings diff --git a/common/src/block.rs b/common/src/block.rs index 456c879..baba1e4 100644 --- a/common/src/block.rs +++ b/common/src/block.rs @@ -6,7 +6,7 @@ use crate::transaction::EncodedTransaction; pub type HashType = [u8; 32]; #[derive(Debug, Clone)] -///Our own hasher. +/// Our own hasher. /// Currently it is SHA256 hasher wrapper. May change in a future. pub struct OwnHasher {} diff --git a/common/src/lib.rs b/common/src/lib.rs index 7976479..b64e6ef 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -4,8 +4,8 @@ pub mod rpc_primitives; pub mod sequencer_client; pub mod transaction; -//Module for tests utility functions -//TODO: Compile only for tests +// Module for tests utility functions +// TODO: Compile only for tests pub mod test_utils; pub type HashType = [u8; 32]; diff --git a/common/src/rpc_primitives/errors.rs b/common/src/rpc_primitives/errors.rs index fc52dd0..1f79981 100644 --- a/common/src/rpc_primitives/errors.rs +++ b/common/src/rpc_primitives/errors.rs @@ -1,6 +1,7 @@ -use serde_json::{Value, to_value}; use std::fmt; +use serde_json::{Value, to_value}; + #[derive(serde::Serialize)] pub struct RpcParseError(pub String); diff --git a/common/src/rpc_primitives/message.rs b/common/src/rpc_primitives/message.rs index e8e4186..8207267 100644 --- a/common/src/rpc_primitives/message.rs +++ b/common/src/rpc_primitives/message.rs @@ -9,11 +9,14 @@ //! //! The main entrypoint here is the [Message](enum.Message.html). The others are just building //! blocks and you should generally work with `Message` instead. -use serde::de::{Deserializer, Error, Unexpected, Visitor}; -use serde::ser::{SerializeStruct, Serializer}; -use serde_json::{Result as JsonResult, Value}; use std::fmt::{Formatter, Result as FmtResult}; +use serde::{ + de::{Deserializer, Error, Unexpected, Visitor}, + ser::{SerializeStruct, Serializer}, +}; +use serde_json::{Result as JsonResult, Value}; + use super::errors::RpcError; #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -69,6 +72,7 @@ impl Request { id: self.id.clone(), }) } + /// Answer the request with an error. pub fn error(&self, error: RpcError) -> Message { Message::Response(Response { @@ -207,6 +211,7 @@ impl Message { id, }) } + /// Create a top-level error (without an ID). pub fn error(error: RpcError) -> Self { Message::Response(Response { @@ -215,6 +220,7 @@ impl Message { id: Value::Null, }) } + /// A constructor for a notification. pub fn notification(method: String, params: Value) -> Self { Message::Notification(Notification { @@ -223,6 +229,7 @@ impl Message { params, }) } + /// A constructor for a response. pub fn response(id: Value, result: Result) -> Self { Message::Response(Response { @@ -231,6 +238,7 @@ impl Message { id, }) } + /// Returns id or Null if there is no id. pub fn id(&self) -> Value { match self { @@ -315,10 +323,7 @@ impl From for Vec { #[cfg(test)] mod tests { - use serde_json::Value; - use serde_json::de::from_slice; - use serde_json::json; - use serde_json::ser::to_vec; + use serde_json::{Value, de::from_slice, json, ser::to_vec}; use super::*; diff --git a/common/src/rpc_primitives/mod.rs b/common/src/rpc_primitives/mod.rs index ffa8564..ee64fb4 100644 --- a/common/src/rpc_primitives/mod.rs +++ b/common/src/rpc_primitives/mod.rs @@ -1,5 +1,3 @@ -use std::time::Duration; - use serde::{Deserialize, Serialize}; pub mod errors; @@ -7,21 +5,6 @@ pub mod message; pub mod parser; pub mod requests; -#[derive(Serialize, Deserialize, Clone, Copy, Debug)] -pub struct RpcPollingConfig { - pub polling_interval: Duration, - pub polling_timeout: Duration, -} - -impl Default for RpcPollingConfig { - fn default() -> Self { - Self { - polling_interval: Duration::from_millis(500), - polling_timeout: Duration::from_secs(10), - } - } -} - #[derive(Serialize, Deserialize, Clone, Debug)] pub struct RpcLimitsConfig { /// Maximum byte size of the json payload. @@ -40,7 +23,6 @@ impl Default for RpcLimitsConfig { pub struct RpcConfig { pub addr: String, pub cors_allowed_origins: Vec, - pub polling_config: RpcPollingConfig, #[serde(default)] pub limits_config: RpcLimitsConfig, } @@ -50,7 +32,6 @@ impl Default for RpcConfig { RpcConfig { addr: "0.0.0.0:3040".to_owned(), cors_allowed_origins: vec!["*".to_owned()], - polling_config: RpcPollingConfig::default(), limits_config: RpcLimitsConfig::default(), } } diff --git a/common/src/rpc_primitives/requests.rs b/common/src/rpc_primitives/requests.rs index 91596e6..7149472 100644 --- a/common/src/rpc_primitives/requests.rs +++ b/common/src/rpc_primitives/requests.rs @@ -1,20 +1,21 @@ use std::collections::HashMap; -use crate::parse_request; - -use super::errors::RpcParseError; -use super::parser::RpcRequest; -use super::parser::parse_params; use nssa_core::program::ProgramId; use serde::{Deserialize, Serialize}; use serde_json::Value; +use super::{ + errors::RpcParseError, + parser::{RpcRequest, parse_params}, +}; +use crate::parse_request; + #[derive(Serialize, Deserialize, Debug)] pub struct HelloRequest {} #[derive(Serialize, Deserialize, Debug)] pub struct RegisterAccountRequest { - pub address: [u8; 32], + pub account_id: [u8; 32], } #[derive(Serialize, Deserialize, Debug)] @@ -38,7 +39,7 @@ pub struct GetInitialTestnetAccountsRequest {} #[derive(Serialize, Deserialize, Debug)] pub struct GetAccountBalanceRequest { - pub address: String, + pub account_id: String, } #[derive(Serialize, Deserialize, Debug)] @@ -48,12 +49,12 @@ pub struct GetTransactionByHashRequest { #[derive(Serialize, Deserialize, Debug)] pub struct GetAccountsNoncesRequest { - pub addresses: Vec, + pub account_ids: Vec, } #[derive(Serialize, Deserialize, Debug)] pub struct GetAccountRequest { - pub address: String, + pub account_id: String, } #[derive(Serialize, Deserialize, Debug)] diff --git a/common/src/sequencer_client/json.rs b/common/src/sequencer_client/json.rs index 59895bf..d47aea4 100644 --- a/common/src/sequencer_client/json.rs +++ b/common/src/sequencer_client/json.rs @@ -1,13 +1,13 @@ use serde::{Deserialize, Serialize}; -//Requests +// Requests #[derive(Serialize, Deserialize, Debug)] pub struct SendTxRequest { pub transaction: Vec, } -//Responses +// Responses #[derive(Serialize, Deserialize, Debug)] pub struct SendTxResponse { @@ -15,7 +15,7 @@ pub struct SendTxResponse { pub tx_hash: String, } -//General +// General #[derive(Debug, Clone, Serialize)] pub struct SequencerRpcRequest { @@ -31,7 +31,7 @@ impl SequencerRpcRequest { jsonrpc: "2.0".to_string(), method, params: payload, - //ToDo: Correct checking of id + // ToDo: Correct checking of id id: 1, } } @@ -45,9 +45,9 @@ pub struct SequencerRpcResponse { } #[derive(Debug, Serialize, Deserialize, Clone)] -///Helperstruct for account serialization +/// Helperstruct for account serialization pub struct AccountInitialData { - ///Hex encoded `AccountAddress` - pub addr: String, + /// Hex encoded account id + pub account_id: String, pub balance: u64, } diff --git a/common/src/sequencer_client/mod.rs b/common/src/sequencer_client/mod.rs index b1386c3..a31806e 100644 --- a/common/src/sequencer_client/mod.rs +++ b/common/src/sequencer_client/mod.rs @@ -1,24 +1,26 @@ use std::collections::HashMap; -use super::rpc_primitives::requests::{ - GetAccountBalanceRequest, GetAccountBalanceResponse, GetBlockDataRequest, GetBlockDataResponse, - GetGenesisIdRequest, GetGenesisIdResponse, GetInitialTestnetAccountsRequest, -}; use anyhow::Result; use json::{SendTxRequest, SendTxResponse, SequencerRpcRequest, SequencerRpcResponse}; use nssa_core::program::ProgramId; use reqwest::Client; use serde_json::Value; -use crate::error::{SequencerClientError, SequencerRpcError}; -use crate::rpc_primitives::requests::{ - GetAccountRequest, GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse, - GetLastBlockRequest, GetLastBlockResponse, GetProgramIdsRequest, GetProgramIdsResponse, - GetProofForCommitmentRequest, GetProofForCommitmentResponse, GetTransactionByHashRequest, - GetTransactionByHashResponse, +use super::rpc_primitives::requests::{ + GetAccountBalanceRequest, GetAccountBalanceResponse, GetBlockDataRequest, GetBlockDataResponse, + GetGenesisIdRequest, GetGenesisIdResponse, GetInitialTestnetAccountsRequest, +}; +use crate::{ + error::{SequencerClientError, SequencerRpcError}, + rpc_primitives::requests::{ + GetAccountRequest, GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse, + GetLastBlockRequest, GetLastBlockResponse, GetProgramIdsRequest, GetProgramIdsResponse, + GetProofForCommitmentRequest, GetProofForCommitmentResponse, GetTransactionByHashRequest, + GetTransactionByHashResponse, + }, + sequencer_client::json::AccountInitialData, + transaction::{EncodedTransaction, NSSATransaction}, }; -use crate::sequencer_client::json::AccountInitialData; -use crate::transaction::{EncodedTransaction, NSSATransaction}; pub mod json; @@ -62,7 +64,7 @@ impl SequencerClient { } } - ///Get block data at `block_id` from sequencer + /// Get block data at `block_id` from sequencer pub async fn get_block( &self, block_id: u64, @@ -78,7 +80,7 @@ impl SequencerClient { Ok(resp_deser) } - ///Get last known `blokc_id` from sequencer + /// Get last known `blokc_id` from sequencer pub async fn get_last_block(&self) -> Result { let block_req = GetLastBlockRequest {}; @@ -91,12 +93,13 @@ impl SequencerClient { Ok(resp_deser) } - ///Get account public balance for `address`. `address` must be a valid hex-string for 32 bytes. + /// Get account public balance for `account_id`. `account_id` must be a valid hex-string for 32 + /// bytes. pub async fn get_account_balance( &self, - address: String, + account_id: String, ) -> Result { - let block_req = GetAccountBalanceRequest { address }; + let block_req = GetAccountBalanceRequest { account_id }; let req = serde_json::to_value(block_req)?; @@ -109,12 +112,13 @@ impl SequencerClient { Ok(resp_deser) } - ///Get accounts nonces for `addresses`. `addresses` must be a list of valid hex-strings for 32 bytes. + /// Get accounts nonces for `account_ids`. `account_ids` must be a list of valid hex-strings for + /// 32 bytes. pub async fn get_accounts_nonces( &self, - addresses: Vec, + account_ids: Vec, ) -> Result { - let block_req = GetAccountsNoncesRequest { addresses }; + let block_req = GetAccountsNoncesRequest { account_ids }; let req = serde_json::to_value(block_req)?; @@ -129,9 +133,9 @@ impl SequencerClient { pub async fn get_account( &self, - address: String, + account_id: String, ) -> Result { - let block_req = GetAccountRequest { address }; + let block_req = GetAccountRequest { account_id }; let req = serde_json::to_value(block_req)?; @@ -142,7 +146,7 @@ impl SequencerClient { Ok(resp_deser) } - ///Get transaction details for `hash`. + /// Get transaction details for `hash`. pub async fn get_transaction_by_hash( &self, hash: String, @@ -160,7 +164,7 @@ impl SequencerClient { Ok(resp_deser) } - ///Send transaction to sequencer + /// Send transaction to sequencer pub async fn send_tx_public( &self, transaction: nssa::PublicTransaction, @@ -180,7 +184,7 @@ impl SequencerClient { Ok(resp_deser) } - ///Send transaction to sequencer + /// Send transaction to sequencer pub async fn send_tx_private( &self, transaction: nssa::PrivacyPreservingTransaction, @@ -200,7 +204,7 @@ impl SequencerClient { Ok(resp_deser) } - ///Get genesis id from sequencer + /// Get genesis id from sequencer pub async fn get_genesis_id(&self) -> Result { let genesis_req = GetGenesisIdRequest {}; @@ -216,7 +220,7 @@ impl SequencerClient { Ok(resp_deser) } - ///Get initial testnet accounts from sequencer + /// Get initial testnet accounts from sequencer pub async fn get_initial_testnet_accounts( &self, ) -> Result, SequencerClientError> { @@ -234,7 +238,7 @@ impl SequencerClient { Ok(resp_deser) } - ///Get proof for commitment + /// Get proof for commitment pub async fn get_proof_for_commitment( &self, commitment: nssa_core::Commitment, diff --git a/common/src/test_utils.rs b/common/src/test_utils.rs index 9d68db8..7e3c0ba 100644 --- a/common/src/test_utils.rs +++ b/common/src/test_utils.rs @@ -3,15 +3,15 @@ use crate::{ transaction::{EncodedTransaction, NSSATransaction}, }; -//Helpers +// Helpers pub fn sequencer_sign_key_for_testing() -> nssa::PrivateKey { nssa::PrivateKey::try_new([37; 32]).unwrap() } -//Dummy producers +// Dummy producers -///Produce dummy block with +/// Produce dummy block with /// /// `id` - block id, provide zero for genesis /// @@ -35,12 +35,16 @@ pub fn produce_dummy_block( pub fn produce_dummy_empty_transaction() -> EncodedTransaction { let program_id = nssa::program::Program::authenticated_transfer_program().id(); - let addresses = vec![]; + let account_ids = vec![]; let nonces = vec![]; let instruction_data: u128 = 0; - let message = - nssa::public_transaction::Message::try_new(program_id, addresses, nonces, instruction_data) - .unwrap(); + let message = nssa::public_transaction::Message::try_new( + program_id, + account_ids, + nonces, + instruction_data, + ) + .unwrap(); let private_key = nssa::PrivateKey::try_new([1; 32]).unwrap(); let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[&private_key]); @@ -56,12 +60,16 @@ pub fn create_transaction_native_token_transfer( balance_to_move: u128, signing_key: nssa::PrivateKey, ) -> EncodedTransaction { - let addresses = vec![nssa::Address::new(from), nssa::Address::new(to)]; + let account_ids = vec![nssa::AccountId::new(from), nssa::AccountId::new(to)]; let nonces = vec![nonce]; let program_id = nssa::program::Program::authenticated_transfer_program().id(); - let message = - nssa::public_transaction::Message::try_new(program_id, addresses, nonces, balance_to_move) - .unwrap(); + let message = nssa::public_transaction::Message::try_new( + program_id, + account_ids, + nonces, + balance_to_move, + ) + .unwrap(); let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[&signing_key]); let nssa_tx = nssa::PublicTransaction::new(message, witness_set); diff --git a/common/src/transaction.rs b/common/src/transaction.rs index 1bcf661..372bc95 100644 --- a/common/src/transaction.rs +++ b/common/src/transaction.rs @@ -1,7 +1,6 @@ use borsh::{BorshDeserialize, BorshSerialize}; use log::info; use serde::{Deserialize, Serialize}; - use sha2::{Digest, digest::FixedOutput}; pub type HashType = [u8; 32]; @@ -41,10 +40,10 @@ pub enum TxKind { } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] -///General transaction object +/// General transaction object pub struct EncodedTransaction { pub tx_kind: TxKind, - ///Encoded blobs of data + /// Encoded blobs of data pub encoded_transaction_data: Vec, } diff --git a/integration_tests/configs/debug/sequencer/sequencer_config.json b/integration_tests/configs/debug/sequencer/sequencer_config.json index 8275703..db1c7f2 100644 --- a/integration_tests/configs/debug/sequencer/sequencer_config.json +++ b/integration_tests/configs/debug/sequencer/sequencer_config.json @@ -9,11 +9,11 @@ "port": 3040, "initial_accounts": [ { - "addr": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", + "account_id": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", "balance": 10000 }, { - "addr": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", + "account_id": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", "balance": 20000 } ], diff --git a/integration_tests/configs/debug/wallet/wallet_config.json b/integration_tests/configs/debug/wallet/wallet_config.json index 8b0b303..82f2864 100644 --- a/integration_tests/configs/debug/wallet/wallet_config.json +++ b/integration_tests/configs/debug/wallet/wallet_config.json @@ -8,7 +8,7 @@ "initial_accounts": [ { "Public": { - "address": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", + "account_id": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", "pub_sign_key": [ 16, 162, @@ -47,7 +47,7 @@ }, { "Public": { - "address": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", + "account_id": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", "pub_sign_key": [ 113, 121, @@ -86,7 +86,7 @@ }, { "Private": { - "address": "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw", + "account_id": "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw", "account": { "program_owner": [ 0, @@ -315,7 +315,7 @@ }, { "Private": { - "address": "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX", + "account_id": "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX", "account": { "program_owner": [ 0, diff --git a/integration_tests/src/lib.rs b/integration_tests/src/lib.rs index 75e39b8..dc7188b 100644 --- a/integration_tests/src/lib.rs +++ b/integration_tests/src/lib.rs @@ -1,8 +1,8 @@ -use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; use std::path::PathBuf; use actix_web::dev::ServerHandle; use anyhow::Result; +use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; use clap::Parser; use common::{ sequencer_client::SequencerClient, @@ -44,19 +44,19 @@ pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12; pub const NSSA_PROGRAM_FOR_TEST_DATA_CHANGER: &[u8] = include_bytes!("data_changer.bin"); -fn make_public_account_input_from_str(addr: &str) -> String { - format!("Public/{addr}") +fn make_public_account_input_from_str(account_id: &str) -> String { + format!("Public/{account_id}") } -fn make_private_account_input_from_str(addr: &str) -> String { - format!("Private/{addr}") +fn make_private_account_input_from_str(account_id: &str) -> String { + format!("Private/{account_id}") } #[allow(clippy::type_complexity)] pub async fn pre_test( home_dir: PathBuf, ) -> Result<(ServerHandle, JoinHandle>, TempDir)> { - wallet::execute_setup("test_pass".to_string()).await?; + wallet::execute_setup("test_pass".to_owned()).await?; let home_dir_sequencer = home_dir.join("sequencer"); @@ -98,13 +98,13 @@ pub async fn post_test(residual: (ServerHandle, JoinHandle>, TempDir) let wallet_home = wallet::helperfunctions::get_home().unwrap(); let persistent_data_home = wallet_home.join("storage.json"); - //Removing persistent accounts after run to not affect other executions - //Not necessary an error, if fails as there is tests for failure scenario + // Removing persistent accounts after run to not affect other executions + // Not necessary an error, if fails as there is tests for failure scenario let _ = std::fs::remove_file(persistent_data_home) .inspect_err(|err| warn!("Failed to remove persistent data with err {err:#?}")); - //At this point all of the references to sequencer_core must be lost. - //So they are dropped and tempdirs will be dropped too, + // At this point all of the references to sequencer_core must be lost. + // So they are dropped and tempdirs will be dropped too, } pub async fn main_tests_runner() -> Result<()> { @@ -176,14 +176,14 @@ mod tests { use crate::{make_private_account_input_from_str, make_public_account_input_from_str}; #[test] - fn correct_addr_from_prefix() { - let addr1 = "cafecafe"; - let addr2 = "deadbeaf"; + fn correct_account_id_from_prefix() { + let account_id1 = "cafecafe"; + let account_id2 = "deadbeaf"; - let addr1_pub = make_public_account_input_from_str(addr1); - let addr2_priv = make_private_account_input_from_str(addr2); + let account_id1_pub = make_public_account_input_from_str(account_id1); + let account_id2_priv = make_private_account_input_from_str(account_id2); - assert_eq!(addr1_pub, "Public/cafecafe".to_string()); - assert_eq!(addr2_priv, "Private/deadbeaf".to_string()); + assert_eq!(account_id1_pub, "Public/cafecafe".to_string()); + assert_eq!(account_id2_priv, "Private/deadbeaf".to_string()); } } diff --git a/integration_tests/src/main.rs b/integration_tests/src/main.rs index 5df600a..583df2a 100644 --- a/integration_tests/src/main.rs +++ b/integration_tests/src/main.rs @@ -1,5 +1,4 @@ use anyhow::Result; - use integration_tests::main_tests_runner; pub const NUM_THREADS: usize = 8; diff --git a/integration_tests/src/test_suite_map.rs b/integration_tests/src/test_suite_map.rs index 4399407..9f61810 100644 --- a/integration_tests/src/test_suite_map.rs +++ b/integration_tests/src/test_suite_map.rs @@ -1,4 +1,3 @@ -use anyhow::Result; use std::{ collections::HashMap, path::PathBuf, @@ -8,10 +7,11 @@ use std::{ }; use actix_web::dev::ServerHandle; +use anyhow::Result; use common::{PINATA_BASE58, sequencer_client::SequencerClient}; use key_protocol::key_management::key_tree::chain_index::ChainIndex; use log::info; -use nssa::{Address, ProgramDeploymentTransaction, program::Program}; +use nssa::{AccountId, ProgramDeploymentTransaction, program::Program}; use nssa_core::{NullifierPublicKey, encryption::shared_key_derivation::Secp256k1Point}; use sequencer_runner::startup_sequencer; use tempfile::TempDir; @@ -33,10 +33,10 @@ use crate::{ ACC_RECEIVER, ACC_RECEIVER_PRIVATE, ACC_SENDER, ACC_SENDER_PRIVATE, NSSA_PROGRAM_FOR_TEST_DATA_CHANGER, TIME_TO_WAIT_FOR_BLOCK_SECONDS, fetch_privacy_preserving_tx, make_private_account_input_from_str, - make_public_account_input_from_str, replace_home_dir_with_temp_dir_in_configs, - tps_test_utils::TpsTestManager, + make_public_account_input_from_str, post_test, pre_test, + replace_home_dir_with_temp_dir_in_configs, tps_test_utils::TpsTestManager, + verify_commitment_is_in_state, }; -use crate::{post_test, pre_test, verify_commitment_is_in_state}; type TestFunction = fn(PathBuf) -> Pin>>; @@ -100,24 +100,24 @@ pub fn prepare_function_map() -> HashMap { last_synced_block: _, } = fetch_persistent_storage().await.unwrap(); - let mut new_persistent_account_addr = String::new(); + let mut new_persistent_account_id = String::new(); for per_acc in persistent_accounts { - if (per_acc.address().to_string() != ACC_RECEIVER) - && (per_acc.address().to_string() != ACC_SENDER) + if (per_acc.account_id().to_string() != ACC_RECEIVER) + && (per_acc.account_id().to_string() != ACC_SENDER) { - new_persistent_account_addr = per_acc.address().to_string(); + new_persistent_account_id = per_acc.account_id().to_string(); } } - if new_persistent_account_addr == String::new() { + if new_persistent_account_id == String::new() { panic!("Failed to produce new account, not present in persistent accounts"); } let command = Command::AuthTransfer(AuthTransferSubcommand::Send { from: make_public_account_input_from_str(ACC_SENDER), to: Some(make_public_account_input_from_str( - &new_persistent_account_addr, + &new_persistent_account_id, )), to_npk: None, to_ipk: None, @@ -135,7 +135,7 @@ pub fn prepare_function_map() -> HashMap { .await .unwrap(); let acc_2_balance = seq_client - .get_account_balance(new_persistent_account_addr) + .get_account_balance(new_persistent_account_id) .await .unwrap(); @@ -280,8 +280,8 @@ pub fn prepare_function_map() -> HashMap { assert_eq!(account.nonce, 0); } - /// This test creates a new token using the token program. After creating the token, the test executes a - /// token transfer to a new account. + /// This test creates a new token using the token program. After creating the token, the test + /// executes a token transfer to a new account. #[nssa_integration_test] pub async fn test_success_token_program() { info!("########## test_success_token_program ##########"); @@ -289,7 +289,7 @@ pub fn prepare_function_map() -> HashMap { // Create new account for the token definition let SubcommandReturnValue::RegisterAccount { - addr: definition_addr, + account_id: definition_account_id, } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( NewSubcommand::Public { cci: ChainIndex::root(), @@ -301,20 +301,21 @@ pub fn prepare_function_map() -> HashMap { panic!("invalid subcommand return value"); }; // Create new account for the token supply holder - let SubcommandReturnValue::RegisterAccount { addr: supply_addr } = - wallet::execute_subcommand(Command::Account(AccountSubcommand::New( - NewSubcommand::Public { - cci: ChainIndex::root(), - }, - ))) - .await - .unwrap() + let SubcommandReturnValue::RegisterAccount { + account_id: supply_account_id, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Public { + cci: ChainIndex::root(), + }, + ))) + .await + .unwrap() else { panic!("invalid subcommand return value"); }; // Create new account for receiving a token transaction let SubcommandReturnValue::RegisterAccount { - addr: recipient_addr, + account_id: recipient_account_id, } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( NewSubcommand::Public { cci: ChainIndex::root(), @@ -328,8 +329,10 @@ pub fn prepare_function_map() -> HashMap { // Create new token let subcommand = TokenProgramAgnosticSubcommand::New { - definition_addr: make_public_account_input_from_str(&definition_addr.to_string()), - supply_addr: make_public_account_input_from_str(&supply_addr.to_string()), + definition_account_id: make_public_account_input_from_str( + &definition_account_id.to_string(), + ), + supply_account_id: make_public_account_input_from_str(&supply_account_id.to_string()), name: "A NAME".to_string(), total_supply: 37, }; @@ -343,7 +346,7 @@ pub fn prepare_function_map() -> HashMap { // Check the status of the token definition account is the expected after the execution let definition_acc = seq_client - .get_account(definition_addr.to_string()) + .get_account(definition_account_id.to_string()) .await .unwrap() .account; @@ -358,9 +361,10 @@ pub fn prepare_function_map() -> HashMap { ] ); - // Check the status of the token holding account with the total supply is the expected after the execution + // Check the status of the token holding account with the total supply is the expected after + // the execution let supply_acc = seq_client - .get_account(supply_addr.to_string()) + .get_account(supply_account_id.to_string()) .await .unwrap() .account; @@ -368,23 +372,23 @@ pub fn prepare_function_map() -> HashMap { // The account must be owned by the token program assert_eq!(supply_acc.program_owner, Program::token().id()); // The data of a token definition account has the following layout: - // [ 0x01 || corresponding_token_definition_id (32 bytes) || balance (little endian 16 bytes) ] - // First byte of the data equal to 1 means it's a token holding account + // [ 0x01 || corresponding_token_definition_id (32 bytes) || balance (little endian 16 + // bytes) ] First byte of the data equal to 1 means it's a token holding account assert_eq!(supply_acc.data[0], 1); // Bytes from 1 to 33 represent the id of the token this account is associated with. // In this example, this is a token account of the newly created token, so it is expected - // to be equal to the address of the token definition account. - assert_eq!(&supply_acc.data[1..33], definition_addr.to_bytes()); + // to be equal to the account_id of the token definition account. + assert_eq!(&supply_acc.data[1..33], definition_account_id.to_bytes()); assert_eq!( u128::from_le_bytes(supply_acc.data[33..].try_into().unwrap()), 37 ); - // Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr` + // Transfer 7 tokens from `supply_acc` to the account at account_id `recipient_account_id` let subcommand = TokenProgramAgnosticSubcommand::Send { - from: make_public_account_input_from_str(&supply_addr.to_string()), + from: make_public_account_input_from_str(&supply_account_id.to_string()), to: Some(make_public_account_input_from_str( - &recipient_addr.to_string(), + &recipient_account_id.to_string(), )), to_npk: None, to_ipk: None, @@ -397,9 +401,10 @@ pub fn prepare_function_map() -> HashMap { info!("Waiting for next block creation"); tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - // Check the status of the account at `supply_addr` is the expected after the execution + // Check the status of the account at `supply_account_id` is the expected after the + // execution let supply_acc = seq_client - .get_account(supply_addr.to_string()) + .get_account(supply_account_id.to_string()) .await .unwrap() .account; @@ -408,15 +413,16 @@ pub fn prepare_function_map() -> HashMap { // First byte equal to 1 means it's a token holding account assert_eq!(supply_acc.data[0], 1); // Bytes from 1 to 33 represent the id of the token this account is associated with. - assert_eq!(&supply_acc.data[1..33], definition_addr.to_bytes()); + assert_eq!(&supply_acc.data[1..33], definition_account_id.to_bytes()); assert_eq!( u128::from_le_bytes(supply_acc.data[33..].try_into().unwrap()), 30 ); - // Check the status of the account at `recipient_addr` is the expected after the execution + // Check the status of the account at `recipient_account_id` is the expected after the + // execution let recipient_acc = seq_client - .get_account(recipient_addr.to_string()) + .get_account(recipient_account_id.to_string()) .await .unwrap() .account; @@ -426,15 +432,16 @@ pub fn prepare_function_map() -> HashMap { // First byte equal to 1 means it's a token holding account assert_eq!(recipient_acc.data[0], 1); // Bytes from 1 to 33 represent the id of the token this account is associated with. - assert_eq!(&recipient_acc.data[1..33], definition_addr.to_bytes()); + assert_eq!(&recipient_acc.data[1..33], definition_account_id.to_bytes()); assert_eq!( u128::from_le_bytes(recipient_acc.data[33..].try_into().unwrap()), 7 ); } - /// This test creates a new private token using the token program. After creating the token, the test executes a - /// private token transfer to a new account. All accounts are owned except definition. + /// This test creates a new private token using the token program. After creating the token, the + /// test executes a private token transfer to a new account. All accounts are owned except + /// definition. #[nssa_integration_test] pub async fn test_success_token_program_private_owned() { info!("########## test_success_token_program_private_owned ##########"); @@ -442,7 +449,7 @@ pub fn prepare_function_map() -> HashMap { // Create new account for the token definition (public) let SubcommandReturnValue::RegisterAccount { - addr: definition_addr, + account_id: definition_account_id, } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( NewSubcommand::Public { cci: ChainIndex::root(), @@ -454,20 +461,21 @@ pub fn prepare_function_map() -> HashMap { panic!("invalid subcommand return value"); }; // Create new account for the token supply holder (private) - let SubcommandReturnValue::RegisterAccount { addr: supply_addr } = - wallet::execute_subcommand(Command::Account(AccountSubcommand::New( - NewSubcommand::Private { - cci: ChainIndex::root(), - }, - ))) - .await - .unwrap() + let SubcommandReturnValue::RegisterAccount { + account_id: supply_account_id, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Private { + cci: ChainIndex::root(), + }, + ))) + .await + .unwrap() else { panic!("invalid subcommand return value"); }; // Create new account for receiving a token transaction let SubcommandReturnValue::RegisterAccount { - addr: recipient_addr, + account_id: recipient_account_id, } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( NewSubcommand::Private { cci: ChainIndex::root(), @@ -481,8 +489,10 @@ pub fn prepare_function_map() -> HashMap { // Create new token let subcommand = TokenProgramAgnosticSubcommand::New { - definition_addr: make_public_account_input_from_str(&definition_addr.to_string()), - supply_addr: make_private_account_input_from_str(&supply_addr.to_string()), + definition_account_id: make_public_account_input_from_str( + &definition_account_id.to_string(), + ), + supply_account_id: make_private_account_input_from_str(&supply_account_id.to_string()), name: "A NAME".to_string(), total_supply: 37, }; @@ -498,7 +508,7 @@ pub fn prepare_function_map() -> HashMap { // Check the status of the token definition account is the expected after the execution let definition_acc = seq_client - .get_account(definition_addr.to_string()) + .get_account(definition_account_id.to_string()) .await .unwrap() .account; @@ -519,15 +529,15 @@ pub fn prepare_function_map() -> HashMap { .unwrap(); let new_commitment1 = wallet_storage - .get_private_account_commitment(&supply_addr) + .get_private_account_commitment(&supply_account_id) .unwrap(); assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); - // Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr` + // Transfer 7 tokens from `supply_acc` to the account at account_id `recipient_account_id` let subcommand = TokenProgramAgnosticSubcommand::Send { - from: make_private_account_input_from_str(&supply_addr.to_string()), + from: make_private_account_input_from_str(&supply_account_id.to_string()), to: Some(make_private_account_input_from_str( - &recipient_addr.to_string(), + &recipient_account_id.to_string(), )), to_npk: None, to_ipk: None, @@ -547,20 +557,21 @@ pub fn prepare_function_map() -> HashMap { .unwrap(); let new_commitment1 = wallet_storage - .get_private_account_commitment(&supply_addr) + .get_private_account_commitment(&supply_account_id) .unwrap(); assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); let new_commitment2 = wallet_storage - .get_private_account_commitment(&recipient_addr) + .get_private_account_commitment(&recipient_account_id) .unwrap(); assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); - // Transfer additional 7 tokens from `supply_acc` to the account at address `recipient_addr` + // Transfer additional 7 tokens from `supply_acc` to the account at account_id + // `recipient_account_id` let subcommand = TokenProgramAgnosticSubcommand::Send { - from: make_private_account_input_from_str(&supply_addr.to_string()), + from: make_private_account_input_from_str(&supply_account_id.to_string()), to: Some(make_private_account_input_from_str( - &recipient_addr.to_string(), + &recipient_account_id.to_string(), )), to_npk: None, to_ipk: None, @@ -580,18 +591,18 @@ pub fn prepare_function_map() -> HashMap { .unwrap(); let new_commitment1 = wallet_storage - .get_private_account_commitment(&supply_addr) + .get_private_account_commitment(&supply_account_id) .unwrap(); assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); let new_commitment2 = wallet_storage - .get_private_account_commitment(&recipient_addr) + .get_private_account_commitment(&recipient_account_id) .unwrap(); assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); } - /// This test creates a new private token using the token program. After creating the token, the test executes a - /// private token transfer to a new account. + /// This test creates a new private token using the token program. After creating the token, the + /// test executes a private token transfer to a new account. #[nssa_integration_test] pub async fn test_success_token_program_private_claiming_path() { info!("########## test_success_token_program_private_claiming_path ##########"); @@ -599,7 +610,7 @@ pub fn prepare_function_map() -> HashMap { // Create new account for the token definition (public) let SubcommandReturnValue::RegisterAccount { - addr: definition_addr, + account_id: definition_account_id, } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( NewSubcommand::Public { cci: ChainIndex::root(), @@ -611,20 +622,21 @@ pub fn prepare_function_map() -> HashMap { panic!("invalid subcommand return value"); }; // Create new account for the token supply holder (private) - let SubcommandReturnValue::RegisterAccount { addr: supply_addr } = - wallet::execute_subcommand(Command::Account(AccountSubcommand::New( - NewSubcommand::Private { - cci: ChainIndex::root(), - }, - ))) - .await - .unwrap() + let SubcommandReturnValue::RegisterAccount { + account_id: supply_account_id, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Private { + cci: ChainIndex::root(), + }, + ))) + .await + .unwrap() else { panic!("invalid subcommand return value"); }; // Create new account for receiving a token transaction let SubcommandReturnValue::RegisterAccount { - addr: recipient_addr, + account_id: recipient_account_id, } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( NewSubcommand::Private { cci: ChainIndex::root(), @@ -638,8 +650,10 @@ pub fn prepare_function_map() -> HashMap { // Create new token let subcommand = TokenProgramAgnosticSubcommand::New { - definition_addr: make_public_account_input_from_str(&definition_addr.to_string()), - supply_addr: make_private_account_input_from_str(&supply_addr.to_string()), + definition_account_id: make_public_account_input_from_str( + &definition_account_id.to_string(), + ), + supply_account_id: make_private_account_input_from_str(&supply_account_id.to_string()), name: "A NAME".to_string(), total_supply: 37, }; @@ -655,7 +669,7 @@ pub fn prepare_function_map() -> HashMap { // Check the status of the token definition account is the expected after the execution let definition_acc = seq_client - .get_account(definition_addr.to_string()) + .get_account(definition_account_id.to_string()) .await .unwrap() .account; @@ -676,19 +690,19 @@ pub fn prepare_function_map() -> HashMap { .unwrap(); let new_commitment1 = wallet_storage - .get_private_account_commitment(&supply_addr) + .get_private_account_commitment(&supply_account_id) .unwrap(); assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); let (recipient_keys, _) = wallet_storage .storage .user_data - .get_private_account(&recipient_addr) + .get_private_account(&recipient_account_id) .unwrap(); - // Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr` + // Transfer 7 tokens from `supply_acc` to the account at account_id `recipient_account_id` let subcommand = TokenProgramAgnosticSubcommand::Send { - from: make_private_account_input_from_str(&supply_addr.to_string()), + from: make_private_account_input_from_str(&supply_account_id.to_string()), to: None, to_npk: Some(hex::encode(recipient_keys.nullifer_public_key.0)), to_ipk: Some(hex::encode( @@ -718,18 +732,19 @@ pub fn prepare_function_map() -> HashMap { .unwrap(); let new_commitment1 = wallet_storage - .get_private_account_commitment(&supply_addr) + .get_private_account_commitment(&supply_account_id) .unwrap(); assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); let new_commitment2 = wallet_storage - .get_private_account_commitment(&recipient_addr) + .get_private_account_commitment(&recipient_account_id) .unwrap(); assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); } - /// This test creates a new public token using the token program. After creating the token, the test executes a - /// shielded token transfer to a new account. All accounts are owned except definition. + /// This test creates a new public token using the token program. After creating the token, the + /// test executes a shielded token transfer to a new account. All accounts are owned except + /// definition. #[nssa_integration_test] pub async fn test_success_token_program_shielded_owned() { info!("########## test_success_token_program_shielded_owned ##########"); @@ -737,7 +752,7 @@ pub fn prepare_function_map() -> HashMap { // Create new account for the token definition (public) let SubcommandReturnValue::RegisterAccount { - addr: definition_addr, + account_id: definition_account_id, } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( NewSubcommand::Public { cci: ChainIndex::root(), @@ -749,20 +764,21 @@ pub fn prepare_function_map() -> HashMap { panic!("invalid subcommand return value"); }; // Create new account for the token supply holder (public) - let SubcommandReturnValue::RegisterAccount { addr: supply_addr } = - wallet::execute_subcommand(Command::Account(AccountSubcommand::New( - NewSubcommand::Public { - cci: ChainIndex::root(), - }, - ))) - .await - .unwrap() + let SubcommandReturnValue::RegisterAccount { + account_id: supply_account_id, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Public { + cci: ChainIndex::root(), + }, + ))) + .await + .unwrap() else { panic!("invalid subcommand return value"); }; // Create new account for receiving a token transaction let SubcommandReturnValue::RegisterAccount { - addr: recipient_addr, + account_id: recipient_account_id, } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( NewSubcommand::Private { cci: ChainIndex::root(), @@ -776,8 +792,10 @@ pub fn prepare_function_map() -> HashMap { // Create new token let subcommand = TokenProgramAgnosticSubcommand::New { - definition_addr: make_public_account_input_from_str(&definition_addr.to_string()), - supply_addr: make_public_account_input_from_str(&supply_addr.to_string()), + definition_account_id: make_public_account_input_from_str( + &definition_account_id.to_string(), + ), + supply_account_id: make_public_account_input_from_str(&supply_account_id.to_string()), name: "A NAME".to_string(), total_supply: 37, }; @@ -793,7 +811,7 @@ pub fn prepare_function_map() -> HashMap { // Check the status of the token definition account is the expected after the execution let definition_acc = seq_client - .get_account(definition_addr.to_string()) + .get_account(definition_account_id.to_string()) .await .unwrap() .account; @@ -808,11 +826,11 @@ pub fn prepare_function_map() -> HashMap { ] ); - // Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr` + // Transfer 7 tokens from `supply_acc` to the account at account_id `recipient_account_id` let subcommand = TokenProgramAgnosticSubcommand::Send { - from: make_public_account_input_from_str(&supply_addr.to_string()), + from: make_public_account_input_from_str(&supply_account_id.to_string()), to: Some(make_private_account_input_from_str( - &recipient_addr.to_string(), + &recipient_account_id.to_string(), )), to_npk: None, to_ipk: None, @@ -832,15 +850,16 @@ pub fn prepare_function_map() -> HashMap { .unwrap(); let new_commitment2 = wallet_storage - .get_private_account_commitment(&recipient_addr) + .get_private_account_commitment(&recipient_account_id) .unwrap(); assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); - // Transfer additional 7 tokens from `supply_acc` to the account at address `recipient_addr` + // Transfer additional 7 tokens from `supply_acc` to the account at account_id + // `recipient_account_id` let subcommand = TokenProgramAgnosticSubcommand::Send { - from: make_public_account_input_from_str(&supply_addr.to_string()), + from: make_public_account_input_from_str(&supply_account_id.to_string()), to: Some(make_private_account_input_from_str( - &recipient_addr.to_string(), + &recipient_account_id.to_string(), )), to_npk: None, to_ipk: None, @@ -860,13 +879,14 @@ pub fn prepare_function_map() -> HashMap { .unwrap(); let new_commitment2 = wallet_storage - .get_private_account_commitment(&recipient_addr) + .get_private_account_commitment(&recipient_account_id) .unwrap(); assert!(verify_commitment_is_in_state(new_commitment2, &seq_client).await); } - /// This test creates a new private token using the token program. After creating the token, the test executes a - /// deshielded token transfer to a new account. All accounts are owned except definition. + /// This test creates a new private token using the token program. After creating the token, the + /// test executes a deshielded token transfer to a new account. All accounts are owned + /// except definition. #[nssa_integration_test] pub async fn test_success_token_program_deshielded_owned() { info!("########## test_success_token_program_deshielded_owned ##########"); @@ -874,7 +894,7 @@ pub fn prepare_function_map() -> HashMap { // Create new account for the token definition (public) let SubcommandReturnValue::RegisterAccount { - addr: definition_addr, + account_id: definition_account_id, } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( NewSubcommand::Public { cci: ChainIndex::root(), @@ -886,20 +906,21 @@ pub fn prepare_function_map() -> HashMap { panic!("invalid subcommand return value"); }; // Create new account for the token supply holder (private) - let SubcommandReturnValue::RegisterAccount { addr: supply_addr } = - wallet::execute_subcommand(Command::Account(AccountSubcommand::New( - NewSubcommand::Private { - cci: ChainIndex::root(), - }, - ))) - .await - .unwrap() + let SubcommandReturnValue::RegisterAccount { + account_id: supply_account_id, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Private { + cci: ChainIndex::root(), + }, + ))) + .await + .unwrap() else { panic!("invalid subcommand return value"); }; // Create new account for receiving a token transaction let SubcommandReturnValue::RegisterAccount { - addr: recipient_addr, + account_id: recipient_account_id, } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( NewSubcommand::Public { cci: ChainIndex::root(), @@ -913,8 +934,10 @@ pub fn prepare_function_map() -> HashMap { // Create new token let subcommand = TokenProgramAgnosticSubcommand::New { - definition_addr: make_public_account_input_from_str(&definition_addr.to_string()), - supply_addr: make_private_account_input_from_str(&supply_addr.to_string()), + definition_account_id: make_public_account_input_from_str( + &definition_account_id.to_string(), + ), + supply_account_id: make_private_account_input_from_str(&supply_account_id.to_string()), name: "A NAME".to_string(), total_supply: 37, }; @@ -930,7 +953,7 @@ pub fn prepare_function_map() -> HashMap { // Check the status of the token definition account is the expected after the execution let definition_acc = seq_client - .get_account(definition_addr.to_string()) + .get_account(definition_account_id.to_string()) .await .unwrap() .account; @@ -951,15 +974,15 @@ pub fn prepare_function_map() -> HashMap { .unwrap(); let new_commitment1 = wallet_storage - .get_private_account_commitment(&supply_addr) + .get_private_account_commitment(&supply_account_id) .unwrap(); assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); - // Transfer 7 tokens from `supply_acc` to the account at address `recipient_addr` + // Transfer 7 tokens from `supply_acc` to the account at account_id `recipient_account_id` let subcommand = TokenProgramAgnosticSubcommand::Send { - from: make_private_account_input_from_str(&supply_addr.to_string()), + from: make_private_account_input_from_str(&supply_account_id.to_string()), to: Some(make_public_account_input_from_str( - &recipient_addr.to_string(), + &recipient_account_id.to_string(), )), to_npk: None, to_ipk: None, @@ -979,15 +1002,16 @@ pub fn prepare_function_map() -> HashMap { .unwrap(); let new_commitment1 = wallet_storage - .get_private_account_commitment(&supply_addr) + .get_private_account_commitment(&supply_account_id) .unwrap(); assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); - // Transfer additional 7 tokens from `supply_acc` to the account at address `recipient_addr` + // Transfer additional 7 tokens from `supply_acc` to the account at account_id + // `recipient_account_id` let subcommand = TokenProgramAgnosticSubcommand::Send { - from: make_private_account_input_from_str(&supply_addr.to_string()), + from: make_private_account_input_from_str(&supply_account_id.to_string()), to: Some(make_public_account_input_from_str( - &recipient_addr.to_string(), + &recipient_account_id.to_string(), )), to_npk: None, to_ipk: None, @@ -1007,7 +1031,7 @@ pub fn prepare_function_map() -> HashMap { .unwrap(); let new_commitment1 = wallet_storage - .get_private_account_commitment(&supply_addr) + .get_private_account_commitment(&supply_account_id) .unwrap(); assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); } @@ -1015,8 +1039,8 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_success_private_transfer_to_another_owned_account() { info!("########## test_success_private_transfer_to_another_owned_account ##########"); - let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); - let to: Address = ACC_RECEIVER_PRIVATE.parse().unwrap(); + let from: AccountId = ACC_SENDER_PRIVATE.parse().unwrap(); + let to: AccountId = ACC_RECEIVER_PRIVATE.parse().unwrap(); let command = Command::AuthTransfer(AuthTransferSubcommand::Send { from: make_private_account_input_from_str(&from.to_string()), @@ -1051,7 +1075,7 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_success_private_transfer_to_another_foreign_account() { info!("########## test_success_private_transfer_to_another_foreign_account ##########"); - let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); + let from: AccountId = ACC_SENDER_PRIVATE.parse().unwrap(); let to_npk = NullifierPublicKey([42; 32]); let to_npk_string = hex::encode(to_npk.0); let to_ipk = Secp256k1Point::from_scalar(to_npk.0); @@ -1099,14 +1123,17 @@ pub fn prepare_function_map() -> HashMap { info!( "########## test_success_private_transfer_to_another_owned_account_claiming_path ##########" ); - let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); + let from: AccountId = ACC_SENDER_PRIVATE.parse().unwrap(); let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: ChainIndex::root(), })); let sub_ret = wallet::execute_subcommand(command).await.unwrap(); - let SubcommandReturnValue::RegisterAccount { addr: to_addr } = sub_ret else { + let SubcommandReturnValue::RegisterAccount { + account_id: to_account_id, + } = sub_ret + else { panic!("FAILED TO REGISTER ACCOUNT"); }; @@ -1119,7 +1146,7 @@ pub fn prepare_function_map() -> HashMap { let (to_keys, _) = wallet_storage .storage .user_data - .get_private_account(&to_addr) + .get_private_account(&to_account_id) .cloned() .unwrap(); @@ -1154,91 +1181,87 @@ pub fn prepare_function_map() -> HashMap { assert!(verify_commitment_is_in_state(commitment, &seq_client).await); } - let to_res_acc = wallet_storage.get_account_private(&to_addr).unwrap(); + let to_res_acc = wallet_storage.get_account_private(&to_account_id).unwrap(); assert_eq!(to_res_acc.balance, 100); info!("Success!"); } - #[nssa_integration_test] - pub async fn test_success_private_transfer_to_another_owned_account_cont_run_path() { - info!( - "########## test_success_private_transfer_to_another_owned_account_cont_run_path ##########" - ); - let continious_run_handle = tokio::spawn(wallet::execute_continious_run()); + // #[nssa_integration_test] + // pub async fn test_success_private_transfer_to_another_owned_account_cont_run_path() { + // info!( + // "########## test_success_private_transfer_to_another_owned_account_cont_run_path + // ##########" ); + // let continious_run_handle = tokio::spawn(wallet::execute_continious_run()); - let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); + // let from: AccountId = ACC_SENDER_PRIVATE.parse().unwrap(); - let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { - cci: ChainIndex::root(), - })); + // let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private {})); - let sub_ret = wallet::execute_subcommand(command).await.unwrap(); - let SubcommandReturnValue::RegisterAccount { addr: to_addr } = sub_ret else { - panic!("FAILED TO REGISTER ACCOUNT"); - }; + // let sub_ret = wallet::execute_subcommand(command).await.unwrap(); + // let SubcommandReturnValue::RegisterAccount { + // account_id: to_account_id, + // } = sub_ret + // else { + // panic!("FAILED TO REGISTER ACCOUNT"); + // }; - let wallet_config = fetch_config().await.unwrap(); - let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config.clone()) - .await - .unwrap(); + // let wallet_config = fetch_config().await.unwrap(); + // let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); + // let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config.clone()) + // .await + // .unwrap(); - let (to_keys, _) = wallet_storage - .storage - .user_data - .get_private_account(&to_addr) - .cloned() - .unwrap(); + // let (to_keys, _) = wallet_storage + // .storage + // .user_data + // .user_private_accounts + // .get(&to_account_id) + // .cloned() + // .unwrap(); - let command = Command::AuthTransfer(AuthTransferSubcommand::Send { - from: make_private_account_input_from_str(&from.to_string()), - to: None, - to_npk: Some(hex::encode(to_keys.nullifer_public_key.0)), - to_ipk: Some(hex::encode(to_keys.incoming_viewing_public_key.0)), - amount: 100, - }); + // let command = Command::AuthTransfer(AuthTransferSubcommand::Send { + // from: make_private_account_input_from_str(&from.to_string()), + // to: None, + // to_npk: Some(hex::encode(to_keys.nullifer_public_key.0)), + // to_ipk: Some(hex::encode(to_keys.incoming_viewing_public_key.0)), + // amount: 100, + // }); - let sub_ret = wallet::execute_subcommand(command).await.unwrap(); - let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else { - panic!("FAILED TO SEND TX"); - }; + // let sub_ret = wallet::execute_subcommand(command).await.unwrap(); + // let SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash } = sub_ret else { + // panic!("FAILED TO SEND TX"); + // }; - let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash.clone()).await; + // let tx = fetch_privacy_preserving_tx(&seq_client, tx_hash.clone()).await; + // println!("Waiting for next blocks to check if continoius run fetch account"); + // tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + // tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - println!("Waiting for next blocks to check if continoius run fetch account"); - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; - tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; + // let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) + // .await + // .unwrap(); - let wallet_storage = WalletCore::start_from_config_update_chain(wallet_config) - .await - .unwrap(); + // assert_eq!(tx.message.new_commitments.len(), 2); + // for commitment in tx.message.new_commitments.into_iter() { + // assert!(verify_commitment_is_in_state(commitment, &seq_client).await); + // } - let new_commitment1 = wallet_storage - .get_private_account_commitment(&from) - .unwrap(); - assert_eq!(tx.message.new_commitments[0], new_commitment1); + // let to_res_acc = wallet_storage.get_account_private(&to_account_id).unwrap(); - assert_eq!(tx.message.new_commitments.len(), 2); - for commitment in tx.message.new_commitments.into_iter() { - assert!(verify_commitment_is_in_state(commitment, &seq_client).await); - } + // assert_eq!(to_res_acc.balance, 100); - let to_res_acc = wallet_storage.get_account_private(&to_addr).unwrap(); + // continious_run_handle.abort(); - assert_eq!(to_res_acc.balance, 100); - - continious_run_handle.abort(); - - info!("Success!"); - } + // info!("Success!"); + // } #[nssa_integration_test] pub async fn test_success_deshielded_transfer_to_another_account() { info!("########## test_success_deshielded_transfer_to_another_account ##########"); - let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); - let to: Address = ACC_RECEIVER.parse().unwrap(); + let from: AccountId = ACC_SENDER_PRIVATE.parse().unwrap(); + let to: AccountId = ACC_RECEIVER.parse().unwrap(); let command = Command::AuthTransfer(AuthTransferSubcommand::Send { from: make_private_account_input_from_str(&from.to_string()), @@ -1286,8 +1309,8 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_success_shielded_transfer_to_another_owned_account() { info!("########## test_success_shielded_transfer_to_another_owned_account ##########"); - let from: Address = ACC_SENDER.parse().unwrap(); - let to: Address = ACC_RECEIVER_PRIVATE.parse().unwrap(); + let from: AccountId = ACC_SENDER.parse().unwrap(); + let to: AccountId = ACC_RECEIVER_PRIVATE.parse().unwrap(); let command = Command::AuthTransfer(AuthTransferSubcommand::Send { from: make_public_account_input_from_str(&from.to_string()), @@ -1331,7 +1354,7 @@ pub fn prepare_function_map() -> HashMap { let to_npk = NullifierPublicKey([42; 32]); let to_npk_string = hex::encode(to_npk.0); let to_ipk = Secp256k1Point::from_scalar(to_npk.0); - let from: Address = ACC_SENDER.parse().unwrap(); + let from: AccountId = ACC_SENDER.parse().unwrap(); let command = Command::AuthTransfer(AuthTransferSubcommand::Send { from: make_public_account_input_from_str(&from.to_string()), @@ -1373,11 +1396,12 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_pinata() { info!("########## test_pinata ##########"); - let pinata_addr = PINATA_BASE58; + let pinata_account_id = PINATA_BASE58; + let pinata_prize = 150; let solution = 989106; let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim { - to_addr: make_public_account_input_from_str(ACC_SENDER), + to_account_id: make_public_account_input_from_str(ACC_SENDER), solution, }); @@ -1386,7 +1410,7 @@ pub fn prepare_function_map() -> HashMap { let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); let pinata_balance_pre = seq_client - .get_account_balance(pinata_addr.to_string()) + .get_account_balance(pinata_account_id.to_string()) .await .unwrap() .balance; @@ -1398,7 +1422,7 @@ pub fn prepare_function_map() -> HashMap { info!("Checking correct balance move"); let pinata_balance_post = seq_client - .get_account_balance(pinata_addr.to_string()) + .get_account_balance(pinata_account_id.to_string()) .await .unwrap() .balance; @@ -1432,12 +1456,13 @@ pub fn prepare_function_map() -> HashMap { // The program is the data changer and takes one account as input. // We pass an uninitialized account and we expect after execution to be owned by the data - // changer program (NSSA account claiming mechanism) with data equal to [0] (due to program logic) + // changer program (NSSA account claiming mechanism) with data equal to [0] (due to program + // logic) let data_changer = Program::new(bytecode).unwrap(); - let address: Address = "11".repeat(16).parse().unwrap(); + let account_id: AccountId = "11".repeat(16).parse().unwrap(); let message = nssa::public_transaction::Message::try_new( data_changer.id(), - vec![address], + vec![account_id], vec![], (), ) @@ -1450,7 +1475,7 @@ pub fn prepare_function_map() -> HashMap { tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await; let post_state_account = seq_client - .get_account(address.to_string()) + .get_account(account_id.to_string()) .await .unwrap() .account; @@ -1468,14 +1493,14 @@ pub fn prepare_function_map() -> HashMap { let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: ChainIndex::root(), })); - let SubcommandReturnValue::RegisterAccount { addr } = + let SubcommandReturnValue::RegisterAccount { account_id } = wallet::execute_subcommand(command).await.unwrap() else { panic!("Error creating account"); }; let command = Command::AuthTransfer(AuthTransferSubcommand::Init { - addr: make_public_account_input_from_str(&addr.to_string()), + account_id: make_public_account_input_from_str(&account_id.to_string()), }); wallet::execute_subcommand(command).await.unwrap(); @@ -1483,7 +1508,7 @@ pub fn prepare_function_map() -> HashMap { let wallet_config = fetch_config().await.unwrap(); let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); let account = seq_client - .get_account(addr.to_string()) + .get_account(account_id.to_string()) .await .unwrap() .account; @@ -1503,12 +1528,12 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_pinata_private_receiver() { info!("########## test_pinata_private_receiver ##########"); - let pinata_addr = PINATA_BASE58; + let pinata_account_id = PINATA_BASE58; let pinata_prize = 150; let solution = 989106; let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim { - to_addr: make_private_account_input_from_str(ACC_SENDER_PRIVATE), + to_account_id: make_private_account_input_from_str(ACC_SENDER_PRIVATE), solution, }); @@ -1517,7 +1542,7 @@ pub fn prepare_function_map() -> HashMap { let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); let pinata_balance_pre = seq_client - .get_account_balance(pinata_addr.to_string()) + .get_account_balance(pinata_account_id.to_string()) .await .unwrap() .balance; @@ -1533,7 +1558,7 @@ pub fn prepare_function_map() -> HashMap { info!("Checking correct balance move"); let pinata_balance_post = seq_client - .get_account_balance(pinata_addr.to_string()) + .get_account_balance(pinata_account_id.to_string()) .await .unwrap() .balance; @@ -1559,26 +1584,27 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_pinata_private_receiver_new_account() { - info!("########## test_pinata_private_receiver ##########"); - let pinata_addr = PINATA_BASE58; + info!("########## test_pinata_private_receiver_new_account ##########"); + let pinata_account_id = PINATA_BASE58; let pinata_prize = 150; let solution = 989106; // Create new account for the token supply holder (private) - let SubcommandReturnValue::RegisterAccount { addr: winner_addr } = - wallet::execute_subcommand(Command::Account(AccountSubcommand::New( - NewSubcommand::Private { - cci: ChainIndex::root(), - }, - ))) - .await - .unwrap() + let SubcommandReturnValue::RegisterAccount { + account_id: winner_account_id, + } = wallet::execute_subcommand(Command::Account(AccountSubcommand::New( + NewSubcommand::Private { + cci: ChainIndex::root(), + }, + ))) + .await + .unwrap() else { panic!("invalid subcommand return value"); }; let command = Command::Pinata(PinataProgramAgnosticSubcommand::Claim { - to_addr: make_private_account_input_from_str(&winner_addr.to_string()), + to_account_id: make_private_account_input_from_str(&winner_account_id.to_string()), solution, }); @@ -1587,7 +1613,7 @@ pub fn prepare_function_map() -> HashMap { let seq_client = SequencerClient::new(wallet_config.sequencer_addr.clone()).unwrap(); let pinata_balance_pre = seq_client - .get_account_balance(pinata_addr.to_string()) + .get_account_balance(pinata_account_id.to_string()) .await .unwrap() .balance; @@ -1599,7 +1625,7 @@ pub fn prepare_function_map() -> HashMap { info!("Checking correct balance move"); let pinata_balance_post = seq_client - .get_account_balance(pinata_addr.to_string()) + .get_account_balance(pinata_account_id.to_string()) .await .unwrap() .balance; @@ -1611,7 +1637,7 @@ pub fn prepare_function_map() -> HashMap { .unwrap(); let new_commitment1 = wallet_storage - .get_private_account_commitment(&winner_addr) + .get_private_account_commitment(&winner_account_id) .unwrap(); assert!(verify_commitment_is_in_state(new_commitment1, &seq_client).await); @@ -1627,7 +1653,7 @@ pub fn prepare_function_map() -> HashMap { let wallet_config = fetch_config().await.unwrap(); let old_seq_poll_retry_delay_millis = wallet_config.seq_poll_retry_delay_millis; - //Change config field + // Change config field let command = Command::Config(ConfigSubcommand::Set { key: "seq_poll_retry_delay_millis".to_string(), value: "1000".to_string(), @@ -1638,7 +1664,7 @@ pub fn prepare_function_map() -> HashMap { assert_eq!(wallet_config.seq_poll_retry_delay_millis, 1000); - //Return how it was at the beginning + // Return how it was at the beginning let command = Command::Config(ConfigSubcommand::Set { key: "seq_poll_retry_delay_millis".to_string(), value: old_seq_poll_retry_delay_millis.to_string(), @@ -1651,14 +1677,17 @@ pub fn prepare_function_map() -> HashMap { #[nssa_integration_test] pub async fn test_keys_restoration() { info!("########## test_keys_restoration ##########"); - let from: Address = ACC_SENDER_PRIVATE.parse().unwrap(); + let from: AccountId = ACC_SENDER_PRIVATE.parse().unwrap(); let command = Command::Account(AccountSubcommand::New(NewSubcommand::Private { cci: ChainIndex::root(), })); let sub_ret = wallet::execute_subcommand(command).await.unwrap(); - let SubcommandReturnValue::RegisterAccount { addr: to_addr1 } = sub_ret else { + let SubcommandReturnValue::RegisterAccount { + account_id: to_account_id1, + } = sub_ret + else { panic!("FAILED TO REGISTER ACCOUNT"); }; @@ -1667,13 +1696,18 @@ pub fn prepare_function_map() -> HashMap { })); let sub_ret = wallet::execute_subcommand(command).await.unwrap(); - let SubcommandReturnValue::RegisterAccount { addr: to_addr2 } = sub_ret else { + let SubcommandReturnValue::RegisterAccount { + account_id: to_account_id2, + } = sub_ret + else { panic!("FAILED TO REGISTER ACCOUNT"); }; let command = Command::AuthTransfer(AuthTransferSubcommand::Send { from: make_private_account_input_from_str(&from.to_string()), - to: Some(make_private_account_input_from_str(&to_addr1.to_string())), + to: Some(make_private_account_input_from_str( + &to_account_id1.to_string(), + )), to_npk: None, to_ipk: None, amount: 100, @@ -1683,7 +1717,9 @@ pub fn prepare_function_map() -> HashMap { let command = Command::AuthTransfer(AuthTransferSubcommand::Send { from: make_private_account_input_from_str(&from.to_string()), - to: Some(make_private_account_input_from_str(&to_addr2.to_string())), + to: Some(make_private_account_input_from_str( + &to_account_id2.to_string(), + )), to_npk: None, to_ipk: None, amount: 100, @@ -1691,14 +1727,17 @@ pub fn prepare_function_map() -> HashMap { wallet::execute_subcommand(command).await.unwrap(); - let from: Address = ACC_SENDER.parse().unwrap(); + let from: AccountId = ACC_SENDER.parse().unwrap(); let command = Command::Account(AccountSubcommand::New(NewSubcommand::Public { cci: ChainIndex::root(), })); let sub_ret = wallet::execute_subcommand(command).await.unwrap(); - let SubcommandReturnValue::RegisterAccount { addr: to_addr3 } = sub_ret else { + let SubcommandReturnValue::RegisterAccount { + account_id: to_account_id3, + } = sub_ret + else { panic!("FAILED TO REGISTER ACCOUNT"); }; @@ -1707,13 +1746,18 @@ pub fn prepare_function_map() -> HashMap { })); let sub_ret = wallet::execute_subcommand(command).await.unwrap(); - let SubcommandReturnValue::RegisterAccount { addr: to_addr4 } = sub_ret else { + let SubcommandReturnValue::RegisterAccount { + account_id: to_account_id4, + } = sub_ret + else { panic!("FAILED TO REGISTER ACCOUNT"); }; let command = Command::AuthTransfer(AuthTransferSubcommand::Send { from: make_public_account_input_from_str(&from.to_string()), - to: Some(make_public_account_input_from_str(&to_addr3.to_string())), + to: Some(make_public_account_input_from_str( + &to_account_id3.to_string(), + )), to_npk: None, to_ipk: None, amount: 100, @@ -1723,7 +1767,9 @@ pub fn prepare_function_map() -> HashMap { let command = Command::AuthTransfer(AuthTransferSubcommand::Send { from: make_public_account_input_from_str(&from.to_string()), - to: Some(make_public_account_input_from_str(&to_addr4.to_string())), + to: Some(make_public_account_input_from_str( + &to_account_id4.to_string(), + )), to_npk: None, to_ipk: None, amount: 100, @@ -1747,7 +1793,7 @@ pub fn prepare_function_map() -> HashMap { .storage .user_data .private_key_tree - .get_node(to_addr1) + .get_node(to_account_id1) .is_some() ); assert!( @@ -1755,7 +1801,7 @@ pub fn prepare_function_map() -> HashMap { .storage .user_data .private_key_tree - .get_node(to_addr2) + .get_node(to_account_id2) .is_some() ); assert!( @@ -1763,7 +1809,7 @@ pub fn prepare_function_map() -> HashMap { .storage .user_data .public_key_tree - .get_node(to_addr3) + .get_node(to_account_id3) .is_some() ); assert!( @@ -1771,7 +1817,7 @@ pub fn prepare_function_map() -> HashMap { .storage .user_data .public_key_tree - .get_node(to_addr4) + .get_node(to_account_id4) .is_some() ); @@ -1829,7 +1875,7 @@ pub async fn tps_test() { for (i, tx_hash) in tx_hashes.iter().enumerate() { loop { if now.elapsed().as_millis() > target_time.as_millis() { - panic!("TPS test failed by timout"); + panic!("TPS test failed by timeout"); } let tx_obj = seq_client diff --git a/integration_tests/src/tps_test_utils.rs b/integration_tests/src/tps_test_utils.rs index 1e31c02..d06a08f 100644 --- a/integration_tests/src/tps_test_utils.rs +++ b/integration_tests/src/tps_test_utils.rs @@ -2,8 +2,7 @@ use std::time::Duration; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use nssa::{ - Account, AccountId, Address, PrivacyPreservingTransaction, PrivateKey, PublicKey, - PublicTransaction, + Account, AccountId, PrivacyPreservingTransaction, PrivateKey, PublicKey, PublicTransaction, privacy_preserving_transaction::{self as pptx, circuit}, program::Program, public_transaction as putx, @@ -15,13 +14,13 @@ use nssa_core::{ use sequencer_core::config::{AccountInitialData, CommitmentsInitialData, SequencerConfig}; pub(crate) struct TpsTestManager { - public_keypairs: Vec<(PrivateKey, Address)>, + public_keypairs: Vec<(PrivateKey, AccountId)>, target_tps: u64, } impl TpsTestManager { - /// Generates public account keypairs. These are used to populate the config and to generate valid - /// public transactions for the tps test. + /// Generates public account keypairs. These are used to populate the config and to generate + /// valid public transactions for the tps test. pub(crate) fn new(target_tps: u64, number_transactions: usize) -> Self { let public_keypairs = (1..(number_transactions + 2)) .map(|i| { @@ -29,8 +28,8 @@ impl TpsTestManager { private_key_bytes[..8].copy_from_slice(&i.to_le_bytes()); let private_key = PrivateKey::try_new(private_key_bytes).unwrap(); let public_key = PublicKey::new_from_private_key(&private_key); - let address = Address::from(&public_key); - (private_key, address) + let account_id = AccountId::from(&public_key); + (private_key, account_id) }) .collect::>(); Self { @@ -44,7 +43,6 @@ impl TpsTestManager { Duration::from_secs_f64(number_transactions as f64 / self.target_tps as f64) } - /// /// Build a batch of public transactions to submit to the node. pub fn build_public_txs(&self) -> Vec { // Create valid public transactions @@ -71,15 +69,15 @@ impl TpsTestManager { } /// Generates a sequencer configuration with initial balance in a number of public accounts. - /// The transactions generated with the function `build_public_txs` will be valid in a node started - /// with the config from this method. + /// The transactions generated with the function `build_public_txs` will be valid in a node + /// started with the config from this method. pub(crate) fn generate_tps_test_config(&self) -> SequencerConfig { // Create public public keypairs let initial_public_accounts = self .public_keypairs .iter() - .map(|(_, addr)| AccountInitialData { - addr: addr.to_string(), + .map(|(_, account_id)| AccountInitialData { + account_id: account_id.to_string(), balance: 10, }) .collect(); diff --git a/key_protocol/src/key_management/ephemeral_key_holder.rs b/key_protocol/src/key_management/ephemeral_key_holder.rs index 4d4fe9d..7a84ec5 100644 --- a/key_protocol/src/key_management/ephemeral_key_holder.rs +++ b/key_protocol/src/key_management/ephemeral_key_holder.rs @@ -6,7 +6,8 @@ use rand::{RngCore, rngs::OsRng}; use sha2::Digest; #[derive(Debug)] -///Ephemeral secret key holder. Non-clonable as intended for one-time use. Produces ephemeral public keys. Can produce shared secret for sender. +/// Ephemeral secret key holder. Non-clonable as intended for one-time use. Produces ephemeral +/// public keys. Can produce shared secret for sender. pub struct EphemeralKeyHolder { ephemeral_secret_key: EphemeralSecretKey, } diff --git a/key_protocol/src/key_management/key_tree/chain_index.rs b/key_protocol/src/key_management/key_tree/chain_index.rs index b7190d1..31a6a07 100644 --- a/key_protocol/src/key_management/key_tree/chain_index.rs +++ b/key_protocol/src/key_management/key_tree/chain_index.rs @@ -17,7 +17,7 @@ impl FromStr for ChainIndex { type Err = ChainIndexError; fn from_str(s: &str) -> Result { - if !s.starts_with("/") { + if !s.starts_with('/') { return Err(ChainIndexError::NoRootFound); } @@ -42,19 +42,25 @@ impl FromStr for ChainIndex { impl Display for ChainIndex { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "/")?; - if *self != Self::root() { - for cci in &self.0[..(self.0.len() - 1)] { - write!(f, "{cci}/")?; - } - write!(f, "{}", self.0.last().unwrap())?; + for cci in &self.0[..(self.0.len().saturating_sub(1))] { + write!(f, "{cci}/")?; + } + if let Some(last) = self.0.last() { + write!(f, "{}", last)?; } Ok(()) } } +impl Default for ChainIndex { + fn default() -> Self { + ChainIndex::from_str("/").expect("Root parsing failure") + } +} + impl ChainIndex { pub fn root() -> Self { - ChainIndex::from_str("/").unwrap() + ChainIndex::default() } pub fn chain(&self) -> &[u32] { @@ -63,7 +69,7 @@ impl ChainIndex { pub fn next_in_line(&self) -> ChainIndex { let mut chain = self.0.clone(); - //ToDo: Add overflow check + // ToDo: Add overflow check if let Some(last_p) = chain.last_mut() { *last_p += 1 } @@ -71,7 +77,7 @@ impl ChainIndex { ChainIndex(chain) } - pub fn n_th_child(&self, child_id: u32) -> ChainIndex { + pub fn nth_child(&self, child_id: u32) -> ChainIndex { let mut chain = self.0.clone(); chain.push(child_id); @@ -108,6 +114,23 @@ mod tests { assert_eq!(chain_id.chain(), &[257]); } + #[test] + fn test_chain_id_deser_failure_no_root() { + let chain_index_error = ChainIndex::from_str("257").err().unwrap(); + + assert!(matches!(chain_index_error, ChainIndexError::NoRootFound)); + } + + #[test] + fn test_chain_id_deser_failure_int_parsing_failure() { + let chain_index_error = ChainIndex::from_str("/hello").err().unwrap(); + + assert!(matches!( + chain_index_error, + ChainIndexError::ParseIntError(_) + )); + } + #[test] fn test_chain_id_next_in_line_correct() { let chain_id = ChainIndex::from_str("/257").unwrap(); @@ -119,7 +142,7 @@ mod tests { #[test] fn test_chain_id_child_correct() { let chain_id = ChainIndex::from_str("/257").unwrap(); - let child = chain_id.n_th_child(3); + let child = chain_id.nth_child(3); assert_eq!(child, ChainIndex::from_str("/257/3").unwrap()); } diff --git a/key_protocol/src/key_management/key_tree/keys_private.rs b/key_protocol/src/key_management/key_tree/keys_private.rs index 84b44fa..c91f03e 100644 --- a/key_protocol/src/key_management/key_tree/keys_private.rs +++ b/key_protocol/src/key_management/key_tree/keys_private.rs @@ -12,7 +12,7 @@ use crate::key_management::{ pub struct ChildKeysPrivate { pub value: (KeyChain, nssa::Account), pub ccc: [u8; 32], - ///Can be None if root + /// Can be [`None`] if root pub cci: Option, } @@ -20,8 +20,14 @@ impl KeyNode for ChildKeysPrivate { fn root(seed: [u8; 64]) -> Self { let hash_value = hmac_sha512::HMAC::mac(seed, "NSSA_master_priv"); - let ssk = SecretSpendingKey(*hash_value.first_chunk::<32>().unwrap()); - let ccc = *hash_value.last_chunk::<32>().unwrap(); + let ssk = SecretSpendingKey( + *hash_value + .first_chunk::<32>() + .expect("hash_value is 64 bytes, must be safe to get first 32"), + ); + let ccc = *hash_value + .last_chunk::<32>() + .expect("hash_value is 64 bytes, must be safe to get last 32"); let nsk = ssk.generate_nullifier_secret_key(); let isk = ssk.generate_incoming_viewing_secret_key(); @@ -49,7 +55,7 @@ impl KeyNode for ChildKeysPrivate { } } - fn n_th_child(&self, cci: u32) -> Self { + fn nth_child(&self, cci: u32) -> Self { let parent_pt = Scalar::from_repr( self.value .0 @@ -57,9 +63,9 @@ impl KeyNode for ChildKeysPrivate { .outgoing_viewing_secret_key .into(), ) - .unwrap() + .expect("Key generated as scalar, must be valid representation") + Scalar::from_repr(self.value.0.private_key_holder.nullifier_secret_key.into()) - .unwrap() + .expect("Key generated as scalar, must be valid representation") * Scalar::from_repr( self.value .0 @@ -67,7 +73,7 @@ impl KeyNode for ChildKeysPrivate { .incoming_viewing_secret_key .into(), ) - .unwrap(); + .expect("Key generated as scalar, must be valid representation"); let mut input = vec![]; input.extend_from_slice(b"NSSA_seed_priv"); @@ -76,8 +82,14 @@ impl KeyNode for ChildKeysPrivate { let hash_value = hmac_sha512::HMAC::mac(input, self.ccc); - let ssk = SecretSpendingKey(*hash_value.first_chunk::<32>().unwrap()); - let ccc = *hash_value.last_chunk::<32>().unwrap(); + let ssk = SecretSpendingKey( + *hash_value + .first_chunk::<32>() + .expect("hash_value is 64 bytes, must be safe to get first 32"), + ); + let ccc = *hash_value + .last_chunk::<32>() + .expect("hash_value is 64 bytes, must be safe to get last 32"); let nsk = ssk.generate_nullifier_secret_key(); let isk = ssk.generate_incoming_viewing_secret_key(); @@ -109,12 +121,12 @@ impl KeyNode for ChildKeysPrivate { &self.ccc } - fn child_index(&self) -> &Option { - &self.cci + fn child_index(&self) -> Option { + self.cci } - fn address(&self) -> nssa::Address { - nssa::Address::from(&self.value.0.nullifer_public_key) + fn account_id(&self) -> nssa::AccountId { + nssa::AccountId::from(&self.value.0.nullifer_public_key) } } @@ -137,7 +149,7 @@ mod tests { #[test] fn test_keys_deterministic_generation() { let root_keys = ChildKeysPrivate::root([42; 64]); - let child_keys = root_keys.n_th_child(5); + let child_keys = root_keys.nth_child(5); assert_eq!(root_keys.cci, None); assert_eq!(child_keys.cci, Some(5)); diff --git a/key_protocol/src/key_management/key_tree/keys_public.rs b/key_protocol/src/key_management/key_tree/keys_public.rs index 7ca6247..ddccdfa 100644 --- a/key_protocol/src/key_management/key_tree/keys_public.rs +++ b/key_protocol/src/key_management/key_tree/keys_public.rs @@ -7,7 +7,7 @@ pub struct ChildKeysPublic { pub csk: nssa::PrivateKey, pub cpk: nssa::PublicKey, pub ccc: [u8; 32], - ///Can be None if root + /// Can be [`None`] if root pub cci: Option, } @@ -27,15 +27,22 @@ impl KeyNode for ChildKeysPublic { } } - fn n_th_child(&self, cci: u32) -> Self { + fn nth_child(&self, cci: u32) -> Self { let mut hash_input = vec![]; hash_input.extend_from_slice(self.csk.value()); hash_input.extend_from_slice(&cci.to_le_bytes()); let hash_value = hmac_sha512::HMAC::mac(&hash_input, self.ccc); - let csk = nssa::PrivateKey::try_new(*hash_value.first_chunk::<32>().unwrap()).unwrap(); - let ccc = *hash_value.last_chunk::<32>().unwrap(); + let csk = nssa::PrivateKey::try_new( + *hash_value + .first_chunk::<32>() + .expect("hash_value is 64 bytes, must be safe to get first 32"), + ) + .unwrap(); + let ccc = *hash_value + .last_chunk::<32>() + .expect("hash_value is 64 bytes, must be safe to get last 32"); let cpk = nssa::PublicKey::new_from_private_key(&csk); Self { @@ -50,12 +57,12 @@ impl KeyNode for ChildKeysPublic { &self.ccc } - fn child_index(&self) -> &Option { - &self.cci + fn child_index(&self) -> Option { + self.cci } - fn address(&self) -> nssa::Address { - nssa::Address::from(&self.cpk) + fn account_id(&self) -> nssa::AccountId { + nssa::AccountId::from(&self.cpk) } } @@ -72,7 +79,7 @@ mod tests { #[test] fn test_keys_deterministic_generation() { let root_keys = ChildKeysPublic::root([42; 64]); - let child_keys = root_keys.n_th_child(5); + let child_keys = root_keys.nth_child(5); assert_eq!(root_keys.cci, None); assert_eq!(child_keys.cci, Some(5)); diff --git a/key_protocol/src/key_management/key_tree/mod.rs b/key_protocol/src/key_management/key_tree/mod.rs index d6600fe..7f91143 100644 --- a/key_protocol/src/key_management/key_tree/mod.rs +++ b/key_protocol/src/key_management/key_tree/mod.rs @@ -21,120 +21,122 @@ pub mod keys_public; pub mod traits; #[derive(Debug, Serialize, Deserialize, Clone)] -pub struct KeyTree { - pub key_map: BTreeMap, - pub addr_map: HashMap, +pub struct KeyTree { + pub key_map: BTreeMap, + pub account_id_map: HashMap, } pub type KeyTreePublic = KeyTree; pub type KeyTreePrivate = KeyTree; -impl KeyTree { +impl KeyTree { pub fn new(seed: &SeedHolder) -> Self { - let seed_fit: [u8; 64] = seed.seed.clone().try_into().unwrap(); + let seed_fit: [u8; 64] = seed + .seed + .clone() + .try_into() + .expect("SeedHolder seed is 64 bytes long"); - let root_keys = Node::root(seed_fit); - let address = root_keys.address(); + let root_keys = N::root(seed_fit); + let account_id = root_keys.account_id(); - let mut key_map = BTreeMap::new(); - let mut addr_map = HashMap::new(); + let key_map = BTreeMap::from_iter([(ChainIndex::root(), root_keys)]); + let account_id_map = HashMap::from_iter([(account_id, ChainIndex::root())]); - key_map.insert(ChainIndex::root(), root_keys); - addr_map.insert(address, ChainIndex::root()); - - Self { key_map, addr_map } + Self { + key_map, + account_id_map, + } } - pub fn new_from_root(root: Node) -> Self { - let mut key_map = BTreeMap::new(); - let mut addr_map = HashMap::new(); + pub fn new_from_root(root: N) -> Self { + let account_id_map = HashMap::from_iter([(root.account_id(), ChainIndex::root())]); + let key_map = BTreeMap::from_iter([(ChainIndex::root(), root)]); - addr_map.insert(root.address(), ChainIndex::root()); - key_map.insert(ChainIndex::root(), root); - - Self { key_map, addr_map } + Self { + key_map, + account_id_map, + } } - //ToDo: Add function to create a tree from list of nodes with consistency check. + // ToDo: Add function to create a tree from list of nodes with consistency check. pub fn find_next_last_child_of_id(&self, parent_id: &ChainIndex) -> Option { if !self.key_map.contains_key(parent_id) { return None; } - let leftmost_child = parent_id.n_th_child(u32::MIN); + let leftmost_child = parent_id.nth_child(u32::MIN); if !self.key_map.contains_key(&leftmost_child) { - Some(0) - } else { - let mut right = u32::MAX - 1; - let mut left_border = u32::MIN; - let mut right_border = u32::MAX; + return Some(0); + } - loop { - let rightmost_child = parent_id.n_th_child(right); + let mut right = u32::MAX - 1; + let mut left_border = u32::MIN; + let mut right_border = u32::MAX; - let rightmost_ref = self.key_map.get(&rightmost_child); - let rightmost_ref_next = self.key_map.get(&rightmost_child.next_in_line()); + loop { + let rightmost_child = parent_id.nth_child(right); - match (&rightmost_ref, &rightmost_ref_next) { - (Some(_), Some(_)) => { - left_border = right; - right = (right + right_border) / 2; - } - (Some(_), None) => { - break Some(right + 1); - } - (None, None) => { - right_border = right; - right = (left_border + right) / 2; - } - (None, Some(_)) => { - unreachable!(); - } + let rightmost_ref = self.key_map.get(&rightmost_child); + let rightmost_ref_next = self.key_map.get(&rightmost_child.next_in_line()); + + match (&rightmost_ref, &rightmost_ref_next) { + (Some(_), Some(_)) => { + left_border = right; + right = (right + right_border) / 2; + } + (Some(_), None) => { + break Some(right + 1); + } + (None, None) => { + right_border = right; + right = (left_border + right) / 2; + } + (None, Some(_)) => { + unreachable!(); } } } } - pub fn generate_new_node(&mut self, parent_cci: ChainIndex) -> Option { - if !self.key_map.contains_key(&parent_cci) { - return None; - } + pub fn generate_new_node(&mut self, parent_cci: ChainIndex) -> Option { + let father_keys = self.key_map.get(&parent_cci)?; + let next_child_id = self + .find_next_last_child_of_id(&parent_cci) + .expect("Can be None only if parent is not present"); + let next_cci = parent_cci.nth_child(next_child_id); - let father_keys = self.key_map.get(&parent_cci).unwrap(); - let next_child_id = self.find_next_last_child_of_id(&parent_cci).unwrap(); - let next_cci = parent_cci.n_th_child(next_child_id); + let child_keys = father_keys.nth_child(next_child_id); - let child_keys = father_keys.n_th_child(next_child_id); - - let address = child_keys.address(); + let account_id = child_keys.account_id(); self.key_map.insert(next_cci.clone(), child_keys); - self.addr_map.insert(address, next_cci); + self.account_id_map.insert(account_id, next_cci); - Some(address) + Some(account_id) } - pub fn get_node(&self, addr: nssa::Address) -> Option<&Node> { - self.addr_map - .get(&addr) + pub fn get_node(&self, account_id: nssa::AccountId) -> Option<&N> { + self.account_id_map + .get(&account_id) .and_then(|chain_id| self.key_map.get(chain_id)) } - pub fn get_node_mut(&mut self, addr: nssa::Address) -> Option<&mut Node> { - self.addr_map - .get(&addr) + pub fn get_node_mut(&mut self, account_id: nssa::AccountId) -> Option<&mut N> { + self.account_id_map + .get(&account_id) .and_then(|chain_id| self.key_map.get_mut(chain_id)) } - pub fn insert(&mut self, addr: nssa::Address, chain_index: ChainIndex, node: Node) { - self.addr_map.insert(addr, chain_index.clone()); + pub fn insert(&mut self, account_id: nssa::AccountId, chain_index: ChainIndex, node: N) { + self.account_id_map.insert(account_id, chain_index.clone()); self.key_map.insert(chain_index, node); } - pub fn remove(&mut self, addr: nssa::Address) -> Option { - let chain_index = self.addr_map.remove(&addr).unwrap(); + pub fn remove(&mut self, addr: nssa::AccountId) -> Option { + let chain_index = self.account_id_map.remove(&addr).unwrap(); self.key_map.remove(&chain_index) } @@ -144,7 +146,7 @@ impl KeyTree { while let Some(curr_id) = id_stack.pop() { self.generate_new_node(curr_id.clone()); - let mut next_id = curr_id.n_th_child(0); + let mut next_id = curr_id.nth_child(0); while (next_id.depth()) < depth - 1 { id_stack.push(next_id.clone()); @@ -163,11 +165,11 @@ impl KeyTree { && node.value.1 == nssa::Account::default() && curr_id != ChainIndex::root() { - let addr = node.address(); + let addr = node.account_id(); self.remove(addr); } - let mut next_id = curr_id.n_th_child(0); + let mut next_id = curr_id.nth_child(0); while (next_id.depth()) < depth - 1 { id_stack.push(next_id.clone()); @@ -187,7 +189,7 @@ impl KeyTree { while let Some(curr_id) = id_stack.pop() { if let Some(node) = self.key_map.get(&curr_id) { - let address = node.address(); + let address = node.account_id(); let node_acc = client.get_account(address.to_string()).await?.account; if node_acc == nssa::Account::default() && curr_id != ChainIndex::root() { @@ -195,7 +197,7 @@ impl KeyTree { } } - let mut next_id = curr_id.n_th_child(0); + let mut next_id = curr_id.nth_child(0); while (next_id.depth()) < depth - 1 { id_stack.push(next_id.clone()); @@ -211,7 +213,7 @@ impl KeyTree { mod tests { use std::str::FromStr; - use nssa::Address; + use nssa::AccountId; use super::*; @@ -228,7 +230,7 @@ mod tests { let tree = KeyTreePublic::new(&seed_holder); assert!(tree.key_map.contains_key(&ChainIndex::root())); - assert!(tree.addr_map.contains_key(&Address::new([ + assert!(tree.account_id_map.contains_key(&AccountId::new([ 46, 223, 229, 177, 59, 18, 189, 219, 153, 31, 249, 90, 112, 230, 180, 164, 80, 25, 106, 159, 14, 238, 1, 192, 91, 8, 210, 165, 199, 41, 60, 104, ]))); diff --git a/key_protocol/src/key_management/key_tree/traits.rs b/key_protocol/src/key_management/key_tree/traits.rs index 662481a..5770c47 100644 --- a/key_protocol/src/key_management/key_tree/traits.rs +++ b/key_protocol/src/key_management/key_tree/traits.rs @@ -1,11 +1,14 @@ +/// Trait, that reperesents a Node in hierarchical key tree pub trait KeyNode { + /// Tree root node fn root(seed: [u8; 64]) -> Self; - fn n_th_child(&self, cci: u32) -> Self; + /// `cci`'s child of node + fn nth_child(&self, cci: u32) -> Self; fn chain_code(&self) -> &[u8; 32]; - fn child_index(&self) -> &Option; + fn child_index(&self) -> Option; - fn address(&self) -> nssa::Address; + fn account_id(&self) -> nssa::AccountId; } diff --git a/key_protocol/src/key_management/mod.rs b/key_protocol/src/key_management/mod.rs index 8a58d4a..5f89653 100644 --- a/key_protocol/src/key_management/mod.rs +++ b/key_protocol/src/key_management/mod.rs @@ -12,7 +12,7 @@ pub mod key_tree; pub mod secret_holders; #[derive(Serialize, Deserialize, Clone, Debug)] -///Entrypoint to key management +/// Entrypoint to key management pub struct KeyChain { pub secret_spending_key: SecretSpendingKey, pub private_key_holder: PrivateKeyHolder, @@ -22,8 +22,8 @@ pub struct KeyChain { impl KeyChain { pub fn new_os_random() -> Self { - //Currently dropping SeedHolder at the end of initialization. - //Now entirely sure if we need it in the future. + // Currently dropping SeedHolder at the end of initialization. + // Now entirely sure if we need it in the future. let seed_holder = SeedHolder::new_os_random(); let secret_spending_key = seed_holder.produce_top_secret_key_holder(); @@ -41,8 +41,8 @@ impl KeyChain { } pub fn new_mnemonic(passphrase: String) -> Self { - //Currently dropping SeedHolder at the end of initialization. - //Now entirely sure if we need it in the future. + // Currently dropping SeedHolder at the end of initialization. + // Not entirely sure if we need it in the future. let seed_holder = SeedHolder::new_mnemonic(passphrase); let secret_spending_key = seed_holder.produce_top_secret_key_holder(); @@ -76,8 +76,7 @@ impl KeyChain { mod tests { use aes_gcm::aead::OsRng; use base58::ToBase58; - use k256::AffinePoint; - use k256::elliptic_curve::group::GroupEncoding; + use k256::{AffinePoint, elliptic_curve::group::GroupEncoding}; use rand::RngCore; use super::*; @@ -85,15 +84,18 @@ mod tests { #[test] fn test_new_os_random() { // Ensure that a new KeyChain instance can be created without errors. - let address_key_holder = KeyChain::new_os_random(); + let account_id_key_holder = KeyChain::new_os_random(); // Check that key holder fields are initialized with expected types - assert_ne!(address_key_holder.nullifer_public_key.as_ref(), &[0u8; 32]); + assert_ne!( + account_id_key_holder.nullifer_public_key.as_ref(), + &[0u8; 32] + ); } #[test] fn test_calculate_shared_secret_receiver() { - let address_key_holder = KeyChain::new_os_random(); + let account_id_key_holder = KeyChain::new_os_random(); // Generate a random ephemeral public key sender let mut scalar = [0; 32]; @@ -102,7 +104,7 @@ mod tests { // Calculate shared secret let _shared_secret = - address_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender); + account_id_key_holder.calculate_shared_secret_receiver(ephemeral_public_key_sender); } #[test] @@ -119,7 +121,7 @@ mod tests { let public_key = nssa::PublicKey::new_from_private_key(&pub_account_signing_key); - let address = nssa::Address::from(&public_key); + let account = nssa::AccountId::from(&public_key); println!("======Prerequisites======"); println!(); @@ -140,7 +142,7 @@ mod tests { println!("======Public data======"); println!(); - println!("Address{:?}", address.value().to_base58()); + println!("Account {:?}", account.value().to_base58()); println!( "Nulifier public key {:?}", hex::encode(nullifer_public_key.to_byte_array()) diff --git a/key_protocol/src/key_management/secret_holders.rs b/key_protocol/src/key_management/secret_holders.rs index e60a9f5..c7ac6e9 100644 --- a/key_protocol/src/key_management/secret_holders.rs +++ b/key_protocol/src/key_management/secret_holders.rs @@ -8,23 +8,26 @@ use rand::{RngCore, rngs::OsRng}; use serde::{Deserialize, Serialize}; use sha2::{Digest, digest::FixedOutput}; +const NSSA_ENTROPY_BYTES: [u8; 32] = [0; 32]; + #[derive(Debug)] -///Seed holder. Non-clonable to ensure that different holders use different seeds. +/// Seed holder. Non-clonable to ensure that different holders use different seeds. /// Produces `TopSecretKeyHolder` objects. pub struct SeedHolder { - //ToDo: Needs to be vec as serde derives is not implemented for [u8; 64] + // ToDo: Needs to be vec as serde derives is not implemented for [u8; 64] pub(crate) seed: Vec, } #[derive(Serialize, Deserialize, Debug, Clone)] -///Secret spending key object. Can produce `PrivateKeyHolder` objects. +/// Secret spending key object. Can produce `PrivateKeyHolder` objects. pub struct SecretSpendingKey(pub(crate) [u8; 32]); pub type IncomingViewingSecretKey = Scalar; pub type OutgoingViewingSecretKey = Scalar; #[derive(Serialize, Deserialize, Debug, Clone)] -///Private key holder. Produces public keys. Can produce address. Can produce shared secret for recepient. +/// Private key holder. Produces public keys. Can produce account_id. Can produce shared secret for +/// recepient. pub struct PrivateKeyHolder { pub nullifier_secret_key: NullifierSecretKey, pub(crate) incoming_viewing_secret_key: IncomingViewingSecretKey, @@ -36,7 +39,8 @@ impl SeedHolder { let mut enthopy_bytes: [u8; 32] = [0; 32]; OsRng.fill_bytes(&mut enthopy_bytes); - let mnemonic = Mnemonic::from_entropy(&enthopy_bytes).unwrap(); + let mnemonic = Mnemonic::from_entropy(&enthopy_bytes) + .expect("Enthropy must be a multiple of 32 bytes"); let seed_wide = mnemonic.to_seed("mnemonic"); Self { @@ -45,10 +49,8 @@ impl SeedHolder { } pub fn new_mnemonic(passphrase: String) -> Self { - //Enthropy bytes must be deterministic as well - let enthopy_bytes: [u8; 32] = [0; 32]; - - let mnemonic = Mnemonic::from_entropy(&enthopy_bytes).unwrap(); + let mnemonic = Mnemonic::from_entropy(&NSSA_ENTROPY_BYTES) + .expect("Enthropy must be a multiple of 32 bytes"); let seed_wide = mnemonic.to_seed(passphrase); Self { @@ -63,7 +65,7 @@ impl SeedHolder { hash = hmac_sha512::HMAC::mac(hash, "NSSA_seed"); } - //Safe unwrap + // Safe unwrap *hash.first_chunk::<32>().unwrap() } diff --git a/key_protocol/src/key_protocol_core/mod.rs b/key_protocol/src/key_protocol_core/mod.rs index 6ea75db..ac5ee48 100644 --- a/key_protocol/src/key_protocol_core/mod.rs +++ b/key_protocol/src/key_protocol_core/mod.rs @@ -14,11 +14,11 @@ pub type PublicKey = AffinePoint; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct NSSAUserData { - ///Default public accounts - pub default_pub_account_signing_keys: HashMap, - ///Default private accounts + /// Default public accounts + pub default_pub_account_signing_keys: HashMap, + /// Default private accounts pub default_user_private_accounts: - HashMap, + HashMap, /// Tree of public keys pub public_key_tree: KeyTreePublic, /// Tree of private keys @@ -27,13 +27,14 @@ pub struct NSSAUserData { impl NSSAUserData { fn valid_public_key_transaction_pairing_check( - accounts_keys_map: &HashMap, + accounts_keys_map: &HashMap, ) -> bool { let mut check_res = true; - for (addr, key) in accounts_keys_map { - let expected_addr = nssa::Address::from(&nssa::PublicKey::new_from_private_key(key)); - if &expected_addr != addr { - println!("{}, {}", expected_addr, addr); + for (account_id, key) in accounts_keys_map { + let expected_account_id = + nssa::AccountId::from(&nssa::PublicKey::new_from_private_key(key)); + if &expected_account_id != account_id { + println!("{}, {}", expected_account_id, account_id); check_res = false; } } @@ -41,13 +42,13 @@ impl NSSAUserData { } fn valid_private_key_transaction_pairing_check( - accounts_keys_map: &HashMap, + accounts_keys_map: &HashMap, ) -> bool { let mut check_res = true; - for (addr, (key, _)) in accounts_keys_map { - let expected_addr = nssa::Address::from(&key.nullifer_public_key); - if expected_addr != *addr { - println!("{}, {}", expected_addr, addr); + for (account_id, (key, _)) in accounts_keys_map { + let expected_account_id = nssa::AccountId::from(&key.nullifer_public_key); + if expected_account_id != *account_id { + println!("{}, {}", expected_account_id, account_id); check_res = false; } } @@ -55,9 +56,9 @@ impl NSSAUserData { } pub fn new_with_accounts( - default_accounts_keys: HashMap, + default_accounts_keys: HashMap, default_accounts_key_chains: HashMap< - nssa::Address, + nssa::AccountId, (KeyChain, nssa_core::account::Account), >, public_key_tree: KeyTreePublic, @@ -65,13 +66,13 @@ impl NSSAUserData { ) -> Result { if !Self::valid_public_key_transaction_pairing_check(&default_accounts_keys) { anyhow::bail!( - "Key transaction pairing check not satisfied, there is addresses, which is not derived from keys" + "Key transaction pairing check not satisfied, there is account_ids, which is not derived from keys" ); } if !Self::valid_private_key_transaction_pairing_check(&default_accounts_key_chains) { anyhow::bail!( - "Key transaction pairing check not satisfied, there is addresses, which is not derived from keys" + "Key transaction pairing check not satisfied, there is account_ids, which is not derived from keys" ); } @@ -85,63 +86,65 @@ impl NSSAUserData { /// Generated new private key for public transaction signatures /// - /// Returns the address of new account + /// Returns the account_id of new account pub fn generate_new_public_transaction_private_key( &mut self, parent_cci: ChainIndex, - ) -> nssa::Address { + ) -> nssa::AccountId { self.public_key_tree.generate_new_node(parent_cci).unwrap() } /// Returns the signing key for public transaction signatures pub fn get_pub_account_signing_key( &self, - address: &nssa::Address, + account_id: &nssa::AccountId, ) -> Option<&nssa::PrivateKey> { - //First seek in defaults - if let Some(key) = self.default_pub_account_signing_keys.get(address) { + // First seek in defaults + if let Some(key) = self.default_pub_account_signing_keys.get(account_id) { Some(key) - //Then seek in tree + // Then seek in tree } else { - self.public_key_tree.get_node(*address).map(Into::into) + self.public_key_tree.get_node(*account_id).map(Into::into) } } /// Generated new private key for privacy preserving transactions /// - /// Returns the address of new account + /// Returns the account_id of new account pub fn generate_new_privacy_preserving_transaction_key_chain( &mut self, parent_cci: ChainIndex, - ) -> nssa::Address { + ) -> nssa::AccountId { self.private_key_tree.generate_new_node(parent_cci).unwrap() } /// Returns the signing key for public transaction signatures pub fn get_private_account( &self, - address: &nssa::Address, + account_id: &nssa::AccountId, ) -> Option<&(KeyChain, nssa_core::account::Account)> { - //First seek in defaults - if let Some(key) = self.default_user_private_accounts.get(address) { + // First seek in defaults + if let Some(key) = self.default_user_private_accounts.get(account_id) { Some(key) - //Then seek in tree + // Then seek in tree } else { - self.private_key_tree.get_node(*address).map(Into::into) + self.private_key_tree.get_node(*account_id).map(Into::into) } } /// Returns the signing key for public transaction signatures pub fn get_private_account_mut( &mut self, - address: &nssa::Address, + account_id: &nssa::AccountId, ) -> Option<&mut (KeyChain, nssa_core::account::Account)> { - //First seek in defaults - if let Some(key) = self.default_user_private_accounts.get_mut(address) { + // First seek in defaults + if let Some(key) = self.default_user_private_accounts.get_mut(account_id) { Some(key) - //Then seek in tree + // Then seek in tree } else { - self.private_key_tree.get_node_mut(*address).map(Into::into) + self.private_key_tree + .get_node_mut(*account_id) + .map(Into::into) } } } @@ -166,21 +169,27 @@ mod tests { fn test_new_account() { let mut user_data = NSSAUserData::default(); - let addr_pub = user_data.generate_new_public_transaction_private_key(ChainIndex::root()); - let addr_private = + let account_id_pub = + user_data.generate_new_public_transaction_private_key(ChainIndex::root()); + let account_id_private = user_data.generate_new_privacy_preserving_transaction_key_chain(ChainIndex::root()); - let is_private_key_generated = user_data.get_pub_account_signing_key(&addr_pub).is_some(); + let is_private_key_generated = user_data + .get_pub_account_signing_key(&account_id_pub) + .is_some(); assert!(is_private_key_generated); - let is_key_chain_generated = user_data.get_private_account(&addr_private).is_some(); + let is_key_chain_generated = user_data.get_private_account(&account_id_private).is_some(); assert!(is_key_chain_generated); - let addr_private_str = addr_private.to_string(); - println!("{addr_private_str:#?}"); - let key_chain = &user_data.get_private_account(&addr_private).unwrap().0; + let account_id_private_str = account_id_private.to_string(); + println!("{account_id_private_str:#?}"); + let key_chain = &user_data + .get_private_account(&account_id_private) + .unwrap() + .0; println!("{key_chain:#?}"); } } diff --git a/mempool/Cargo.toml b/mempool/Cargo.toml index c47d2b0..4601438 100644 --- a/mempool/Cargo.toml +++ b/mempool/Cargo.toml @@ -4,3 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] +tokio = { workspace = true, features = ["sync"] } + +[dev-dependencies] +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } diff --git a/mempool/src/lib.rs b/mempool/src/lib.rs index ab1c5d3..ff6163f 100644 --- a/mempool/src/lib.rs +++ b/mempool/src/lib.rs @@ -1,231 +1,99 @@ -use std::collections::VecDeque; +use tokio::sync::mpsc::{Receiver, Sender}; -pub struct MemPool { - items: VecDeque, +pub struct MemPool { + receiver: Receiver, } -impl MemPool { - pub fn new() -> Self { - Self { - items: VecDeque::new(), - } +impl MemPool { + pub fn new(max_size: usize) -> (Self, MemPoolHandle) { + let (sender, receiver) = tokio::sync::mpsc::channel(max_size); + + let mem_pool = Self { receiver }; + let sender = MemPoolHandle::new(sender); + (mem_pool, sender) } - pub fn pop_last(&mut self) -> Option { - self.items.pop_front() - } + pub fn pop(&mut self) -> Option { + use tokio::sync::mpsc::error::TryRecvError; - pub fn peek_last(&self) -> Option<&Item> { - self.items.front() - } - - pub fn push_item(&mut self, item: Item) { - self.items.push_back(item); - } - - pub fn len(&self) -> usize { - self.items.len() - } - - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - pub fn pop_size(&mut self, size: usize) -> Vec { - let mut ret_vec = vec![]; - - for _ in 0..size { - let item = self.pop_last(); - - match item { - Some(item) => ret_vec.push(item), - None => break, + match self.receiver.try_recv() { + Ok(item) => Some(item), + Err(TryRecvError::Empty) => None, + Err(TryRecvError::Disconnected) => { + panic!("Mempool senders disconnected, cannot receive items, this is a bug") } } - - ret_vec - } - - pub fn drain_size(&mut self, remainder: usize) -> Vec { - self.pop_size(self.len().saturating_sub(remainder)) } } -impl Default for MemPool { - fn default() -> Self { - Self::new() +pub struct MemPoolHandle { + sender: Sender, +} + +impl MemPoolHandle { + fn new(sender: Sender) -> Self { + Self { sender } + } + + /// Send an item to the mempool blocking if max size is reached + pub async fn push(&self, item: T) -> Result<(), tokio::sync::mpsc::error::SendError> { + self.sender.send(item).await } } #[cfg(test)] mod tests { - use std::vec; + use tokio::test; use super::*; - pub type ItemId = u64; - - #[derive(Debug, PartialEq, Eq)] - pub struct TestItem { - id: ItemId, - } - - fn test_item_with_id(id: u64) -> TestItem { - TestItem { id } + #[test] + async fn test_mempool_new() { + let (mut pool, _handle): (MemPool, _) = MemPool::new(10); + assert_eq!(pool.pop(), None); } #[test] - fn test_create_empty_mempool() { - let _: MemPool = MemPool::new(); + async fn test_push_and_pop() { + let (mut pool, handle) = MemPool::new(10); + + handle.push(1).await.unwrap(); + + let item = pool.pop(); + assert_eq!(item, Some(1)); + assert_eq!(pool.pop(), None); } #[test] - fn test_mempool_new() { - let pool: MemPool = MemPool::new(); - assert!(pool.is_empty()); - assert_eq!(pool.len(), 0); + async fn test_multiple_push_pop() { + let (mut pool, handle) = MemPool::new(10); + + handle.push(1).await.unwrap(); + handle.push(2).await.unwrap(); + handle.push(3).await.unwrap(); + + assert_eq!(pool.pop(), Some(1)); + assert_eq!(pool.pop(), Some(2)); + assert_eq!(pool.pop(), Some(3)); + assert_eq!(pool.pop(), None); } #[test] - fn test_push_item() { - let mut pool = MemPool::new(); - pool.push_item(test_item_with_id(1)); - assert!(!pool.is_empty()); - assert_eq!(pool.len(), 1); + async fn test_pop_empty() { + let (mut pool, _handle): (MemPool, _) = MemPool::new(10); + assert_eq!(pool.pop(), None); } #[test] - fn test_pop_last() { - let mut pool = MemPool::new(); - pool.push_item(test_item_with_id(1)); - pool.push_item(test_item_with_id(2)); - let item = pool.pop_last(); - assert_eq!(item, Some(test_item_with_id(1))); - assert_eq!(pool.len(), 1); - } + async fn test_max_size() { + let (mut pool, handle) = MemPool::new(2); - #[test] - fn test_peek_last() { - let mut pool = MemPool::new(); - pool.push_item(test_item_with_id(1)); - pool.push_item(test_item_with_id(2)); - let item = pool.peek_last(); - assert_eq!(item, Some(&test_item_with_id(1))); - } + handle.push(1).await.unwrap(); + handle.push(2).await.unwrap(); - #[test] - fn test_pop_size() { - let mut pool = MemPool::new(); - pool.push_item(test_item_with_id(1)); - pool.push_item(test_item_with_id(2)); - pool.push_item(test_item_with_id(3)); - - let items = pool.pop_size(2); - assert_eq!(items, vec![test_item_with_id(1), test_item_with_id(2)]); - assert_eq!(pool.len(), 1); - } - - #[test] - fn test_drain_size() { - let mut pool = MemPool::new(); - pool.push_item(test_item_with_id(1)); - pool.push_item(test_item_with_id(2)); - pool.push_item(test_item_with_id(3)); - pool.push_item(test_item_with_id(4)); - - let items = pool.drain_size(2); - assert_eq!(items, vec![test_item_with_id(1), test_item_with_id(2)]); - assert_eq!(pool.len(), 2); - } - - #[test] - fn test_default() { - let pool: MemPool = MemPool::default(); - assert!(pool.is_empty()); - assert_eq!(pool.len(), 0); - } - - #[test] - fn test_is_empty() { - let mut pool = MemPool::new(); - assert!(pool.is_empty()); - pool.push_item(test_item_with_id(1)); - assert!(!pool.is_empty()); - } - - #[test] - fn test_push_pop() { - let mut mempool: MemPool = MemPool::new(); - - let items = vec![ - test_item_with_id(1), - test_item_with_id(2), - test_item_with_id(3), - ]; - - for item in items { - mempool.push_item(item); - } - assert_eq!(mempool.len(), 3); - - let item = mempool.pop_last(); - - assert_eq!(item, Some(TestItem { id: 1 })); - assert_eq!(mempool.len(), 2); - - let item = mempool.pop_last(); - - assert_eq!(item, Some(TestItem { id: 2 })); - assert_eq!(mempool.len(), 1); - - let item = mempool.pop_last(); - - assert_eq!(item, Some(TestItem { id: 3 })); - assert_eq!(mempool.len(), 0); - - let item = mempool.pop_last(); - - assert_eq!(item, None); - } - - #[test] - fn test_pop_many() { - let mut mempool: MemPool = MemPool::new(); - - let mut items = vec![]; - - for i in 1..11 { - items.push(test_item_with_id(i)); - } - - for item in items { - mempool.push_item(item); - } - - assert_eq!(mempool.len(), 10); - - let items1 = mempool.pop_size(4); - assert_eq!( - items1, - vec![ - test_item_with_id(1), - test_item_with_id(2), - test_item_with_id(3), - test_item_with_id(4) - ] - ); - assert_eq!(mempool.len(), 6); - - let items2 = mempool.drain_size(2); - assert_eq!( - items2, - vec![ - test_item_with_id(5), - test_item_with_id(6), - test_item_with_id(7), - test_item_with_id(8) - ] - ); - assert_eq!(mempool.len(), 2); + // This should block if buffer is full, but we'll use try_send in a real scenario + // For now, just verify we can pop items + assert_eq!(pool.pop(), Some(1)); + assert_eq!(pool.pop(), Some(2)); } } diff --git a/nssa/core/Cargo.toml b/nssa/core/Cargo.toml index 5712eaf..67f40b2 100644 --- a/nssa/core/Cargo.toml +++ b/nssa/core/Cargo.toml @@ -12,6 +12,7 @@ chacha20 = { version = "0.9", default-features = false } k256 = { version = "0.13.3", optional = true } base58 = { version = "0.2.0", optional = true } anyhow = { version = "1.0.98", optional = true } +borsh.workspace = true [features] default = [] diff --git a/nssa/core/src/account.rs b/nssa/core/src/account.rs index f5e38b3..f32d05d 100644 --- a/nssa/core/src/account.rs +++ b/nssa/core/src/account.rs @@ -1,11 +1,20 @@ -use crate::{address::Address, program::ProgramId}; +#[cfg(feature = "host")] +use std::{fmt::Display, str::FromStr}; + +#[cfg(feature = "host")] +use base58::{FromBase58, ToBase58}; +use borsh::{BorshDeserialize, BorshSerialize}; use serde::{Deserialize, Serialize}; +use crate::program::ProgramId; + pub type Nonce = u128; pub type Data = Vec; /// Account to be used both in public and private contexts -#[derive(Serialize, Deserialize, Clone, Default, PartialEq, Eq)] +#[derive( + Serialize, Deserialize, Clone, Default, PartialEq, Eq, BorshSerialize, BorshDeserialize, +)] #[cfg_attr(any(feature = "host", test), derive(Debug))] pub struct Account { pub program_owner: ProgramId, @@ -14,8 +23,6 @@ pub struct Account { pub nonce: Nonce, } -pub type AccountId = Address; - #[derive(Serialize, Deserialize, Clone)] #[cfg_attr(any(feature = "host", test), derive(Debug, PartialEq, Eq))] pub struct AccountWithMetadata { @@ -35,11 +42,68 @@ impl AccountWithMetadata { } } +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash, BorshSerialize, BorshDeserialize)] +#[cfg_attr( + any(feature = "host", test), + derive(Debug, Copy, PartialOrd, Ord, Default) +)] +pub struct AccountId { + value: [u8; 32], +} + +impl AccountId { + pub fn new(value: [u8; 32]) -> Self { + Self { value } + } + + pub fn value(&self) -> &[u8; 32] { + &self.value + } +} + +impl AsRef<[u8]> for AccountId { + fn as_ref(&self) -> &[u8] { + &self.value + } +} + +#[cfg(feature = "host")] +#[derive(Debug, thiserror::Error)] +pub enum AccountIdError { + #[error("invalid base58")] + InvalidBase58(#[from] anyhow::Error), + #[error("invalid length: expected 32 bytes, got {0}")] + InvalidLength(usize), +} + +#[cfg(feature = "host")] +impl FromStr for AccountId { + type Err = AccountIdError; + + fn from_str(s: &str) -> Result { + let bytes = s + .from_base58() + .map_err(|err| anyhow::anyhow!("Invalid base58 err {err:?}"))?; + if bytes.len() != 32 { + return Err(AccountIdError::InvalidLength(bytes.len())); + } + let mut value = [0u8; 32]; + value.copy_from_slice(&bytes); + Ok(AccountId { value }) + } +} + +#[cfg(feature = "host")] +impl Display for AccountId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.value.to_base58()) + } +} + #[cfg(test)] mod tests { - use crate::program::DEFAULT_PROGRAM_ID; - use super::*; + use crate::program::DEFAULT_PROGRAM_ID; #[test] fn test_zero_balance_account_data_creation() { @@ -84,4 +148,32 @@ mod tests { assert!(new_acc_with_metadata.is_authorized); assert_eq!(new_acc_with_metadata.account_id, fingerprint); } + + #[test] + fn parse_valid_account_id() { + let base58_str = "11111111111111111111111111111111"; + let account_id: AccountId = base58_str.parse().unwrap(); + assert_eq!(account_id.value, [0u8; 32]); + } + + #[test] + fn parse_invalid_base58() { + let base58_str = "00".repeat(32); // invalid base58 chars + let result = base58_str.parse::().unwrap_err(); + assert!(matches!(result, AccountIdError::InvalidBase58(_))); + } + + #[test] + fn parse_wrong_length_short() { + let base58_str = "11".repeat(31); // 62 chars = 31 bytes + let result = base58_str.parse::().unwrap_err(); + assert!(matches!(result, AccountIdError::InvalidLength(_))); + } + + #[test] + fn parse_wrong_length_long() { + let base58_str = "11".repeat(33); // 66 chars = 33 bytes + let result = base58_str.parse::().unwrap_err(); + assert!(matches!(result, AccountIdError::InvalidLength(_))); + } } diff --git a/nssa/core/src/address.rs b/nssa/core/src/address.rs deleted file mode 100644 index 6355351..0000000 --- a/nssa/core/src/address.rs +++ /dev/null @@ -1,98 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[cfg(feature = "host")] -use std::{fmt::Display, str::FromStr}; - -#[cfg(feature = "host")] -use base58::{FromBase58, ToBase58}; - -#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)] -#[cfg_attr( - any(feature = "host", test), - derive(Debug, Copy, PartialOrd, Ord, Default) -)] -pub struct Address { - value: [u8; 32], -} - -impl Address { - pub fn new(value: [u8; 32]) -> Self { - Self { value } - } - - pub fn value(&self) -> &[u8; 32] { - &self.value - } -} - -impl AsRef<[u8]> for Address { - fn as_ref(&self) -> &[u8] { - &self.value - } -} - -#[cfg(feature = "host")] -#[derive(Debug, thiserror::Error)] -pub enum AddressError { - #[error("invalid base58")] - InvalidBase58(#[from] anyhow::Error), - #[error("invalid length: expected 32 bytes, got {0}")] - InvalidLength(usize), -} - -#[cfg(feature = "host")] -impl FromStr for Address { - type Err = AddressError; - fn from_str(s: &str) -> Result { - let bytes = s - .from_base58() - .map_err(|err| anyhow::anyhow!("Invalid base58 err {err:?}"))?; - if bytes.len() != 32 { - return Err(AddressError::InvalidLength(bytes.len())); - } - let mut value = [0u8; 32]; - value.copy_from_slice(&bytes); - Ok(Address { value }) - } -} - -#[cfg(feature = "host")] -impl Display for Address { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.value.to_base58()) - } -} - -#[cfg(test)] -mod tests { - - use super::{Address, AddressError}; - - #[test] - fn parse_valid_address() { - let base58_str = "11111111111111111111111111111111"; - let addr: Address = base58_str.parse().unwrap(); - assert_eq!(addr.value, [0u8; 32]); - } - - #[test] - fn parse_invalid_base58() { - let base58_str = "00".repeat(32); // invalid base58 chars - let result = base58_str.parse::
().unwrap_err(); - assert!(matches!(result, AddressError::InvalidBase58(_))); - } - - #[test] - fn parse_wrong_length_short() { - let base58_str = "11".repeat(31); // 62 chars = 31 bytes - let result = base58_str.parse::
().unwrap_err(); - assert!(matches!(result, AddressError::InvalidLength(_))); - } - - #[test] - fn parse_wrong_length_long() { - let base58_str = "11".repeat(33); // 66 chars = 33 bytes - let result = base58_str.parse::
().unwrap_err(); - assert!(matches!(result, AddressError::InvalidLength(_))); - } -} diff --git a/nssa/core/src/circuit_io.rs b/nssa/core/src/circuit_io.rs index 6370dc6..e1afe10 100644 --- a/nssa/core/src/circuit_io.rs +++ b/nssa/core/src/circuit_io.rs @@ -38,12 +38,13 @@ impl PrivacyPreservingCircuitOutput { #[cfg(feature = "host")] #[cfg(test)] mod tests { + use risc0_zkvm::serde::from_slice; + use super::*; use crate::{ Commitment, Nullifier, NullifierPublicKey, account::{Account, AccountId, AccountWithMetadata}, }; - use risc0_zkvm::serde::from_slice; #[test] fn test_privacy_preserving_circuit_output_to_bytes_is_compatible_with_from_slice() { diff --git a/nssa/core/src/commitment.rs b/nssa/core/src/commitment.rs index c1f1cf7..5234417 100644 --- a/nssa/core/src/commitment.rs +++ b/nssa/core/src/commitment.rs @@ -1,9 +1,10 @@ +use borsh::{BorshDeserialize, BorshSerialize}; use risc0_zkvm::sha::{Impl, Sha256}; use serde::{Deserialize, Serialize}; use crate::{NullifierPublicKey, account::Account}; -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, BorshSerialize, BorshDeserialize)] #[cfg_attr(any(feature = "host", test), derive(Debug, Clone, PartialEq, Eq, Hash))] pub struct Commitment(pub(super) [u8; 32]); diff --git a/nssa/core/src/encoding.rs b/nssa/core/src/encoding.rs index 59844d3..3a8a128 100644 --- a/nssa/core/src/encoding.rs +++ b/nssa/core/src/encoding.rs @@ -1,25 +1,20 @@ // TODO: Consider switching to deriving Borsh #[cfg(feature = "host")] use std::io::Cursor; - #[cfg(feature = "host")] use std::io::Read; -use crate::account::Account; - -use crate::account::AccountId; -#[cfg(feature = "host")] -use crate::encryption::shared_key_derivation::Secp256k1Point; - -use crate::encryption::Ciphertext; - -#[cfg(feature = "host")] -use crate::error::NssaCoreError; - -use crate::Commitment; #[cfg(feature = "host")] use crate::Nullifier; -use crate::NullifierPublicKey; +#[cfg(feature = "host")] +use crate::encryption::shared_key_derivation::Secp256k1Point; +#[cfg(feature = "host")] +use crate::error::NssaCoreError; +use crate::{ + Commitment, NullifierPublicKey, + account::{Account, AccountId}, + encryption::Ciphertext, +}; impl Account { pub fn to_bytes(&self) -> Vec { @@ -55,7 +50,7 @@ impl Account { cursor.read_exact(&mut u128_bytes)?; let nonce = u128::from_le_bytes(u128_bytes); - //data + // data cursor.read_exact(&mut u32_bytes)?; let data_length = u32::from_le_bytes(u32_bytes); let mut data = vec![0; data_length as usize]; diff --git a/nssa/core/src/encryption/mod.rs b/nssa/core/src/encryption/mod.rs index 280451b..8f0c6be 100644 --- a/nssa/core/src/encryption/mod.rs +++ b/nssa/core/src/encryption/mod.rs @@ -1,3 +1,4 @@ +use borsh::{BorshDeserialize, BorshSerialize}; use chacha20::{ ChaCha20, cipher::{KeyIvInit, StreamCipher}, @@ -20,7 +21,7 @@ pub struct SharedSecretKey(pub [u8; 32]); pub struct EncryptionScheme; -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, BorshSerialize, BorshDeserialize)] #[cfg_attr(any(feature = "host", test), derive(Debug, Clone, PartialEq, Eq))] pub struct Ciphertext(pub(crate) Vec); diff --git a/nssa/core/src/encryption/shared_key_derivation.rs b/nssa/core/src/encryption/shared_key_derivation.rs index d40b63e..b1a572e 100644 --- a/nssa/core/src/encryption/shared_key_derivation.rs +++ b/nssa/core/src/encryption/shared_key_derivation.rs @@ -1,5 +1,4 @@ -use serde::{Deserialize, Serialize}; - +use borsh::{BorshDeserialize, BorshSerialize}; use k256::{ AffinePoint, EncodedPoint, FieldBytes, ProjectivePoint, elliptic_curve::{ @@ -7,10 +6,11 @@ use k256::{ sec1::{FromEncodedPoint, ToEncodedPoint}, }, }; +use serde::{Deserialize, Serialize}; use crate::{SharedSecretKey, encryption::Scalar}; -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct Secp256k1Point(pub Vec); impl Secp256k1Point { diff --git a/nssa/core/src/lib.rs b/nssa/core/src/lib.rs index d5c4aa3..8d4fce5 100644 --- a/nssa/core/src/lib.rs +++ b/nssa/core/src/lib.rs @@ -6,8 +6,6 @@ pub mod encryption; mod nullifier; pub mod program; -pub mod address; - pub use circuit_io::{PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput}; pub use commitment::{ Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, DUMMY_COMMITMENT_HASH, MembershipProof, diff --git a/nssa/core/src/nullifier.rs b/nssa/core/src/nullifier.rs index a1bc38c..ec30700 100644 --- a/nssa/core/src/nullifier.rs +++ b/nssa/core/src/nullifier.rs @@ -1,3 +1,4 @@ +use borsh::{BorshDeserialize, BorshSerialize}; use risc0_zkvm::sha::{Impl, Sha256}; use serde::{Deserialize, Serialize}; @@ -40,7 +41,7 @@ impl From<&NullifierSecretKey> for NullifierPublicKey { pub type NullifierSecretKey = [u8; 32]; -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, BorshSerialize, BorshDeserialize)] #[cfg_attr(any(feature = "host", test), derive(Debug, Clone, PartialEq, Eq, Hash))] pub struct Nullifier(pub(super) [u8; 32]); diff --git a/nssa/core/src/program.rs b/nssa/core/src/program.rs index 3ecee30..054f993 100644 --- a/nssa/core/src/program.rs +++ b/nssa/core/src/program.rs @@ -1,8 +1,8 @@ -use crate::account::{Account, AccountWithMetadata}; -use risc0_zkvm::serde::Deserializer; -use risc0_zkvm::{DeserializeOwned, guest::env}; +use risc0_zkvm::{DeserializeOwned, guest::env, serde::Deserializer}; use serde::{Deserialize, Serialize}; +use crate::account::{Account, AccountWithMetadata}; + pub type ProgramId = [u32; 8]; pub type InstructionData = Vec; pub const DEFAULT_PROGRAM_ID: ProgramId = [0; 8]; @@ -17,7 +17,7 @@ pub struct ProgramInput { pub struct ChainedCall { pub program_id: ProgramId, pub instruction_data: InstructionData, - pub account_indices: Vec, + pub pre_states: Vec, } #[derive(Serialize, Deserialize, Clone)] @@ -25,7 +25,7 @@ pub struct ChainedCall { pub struct ProgramOutput { pub pre_states: Vec, pub post_states: Vec, - pub chained_call: Option, + pub chained_calls: Vec, } pub fn read_nssa_inputs() -> ProgramInput { @@ -42,7 +42,7 @@ pub fn write_nssa_outputs(pre_states: Vec, post_states: Vec let output = ProgramOutput { pre_states, post_states, - chained_call: None, + chained_calls: Vec::new(), }; env::commit(&output); } @@ -50,12 +50,12 @@ pub fn write_nssa_outputs(pre_states: Vec, post_states: Vec pub fn write_nssa_outputs_with_chained_call( pre_states: Vec, post_states: Vec, - chained_call: Option, + chained_calls: Vec, ) { let output = ProgramOutput { pre_states, post_states, - chained_call, + chained_calls, }; env::commit(&output); } @@ -103,7 +103,8 @@ pub fn validate_execution( return false; } - // 6. If a post state has default program owner, the pre state must have been a default account + // 6. If a post state has default program owner, the pre state must have been a default + // account if post.program_owner == DEFAULT_PROGRAM_ID && pre.account != Account::default() { return false; } diff --git a/nssa/program_methods/guest/Cargo.lock b/nssa/program_methods/guest/Cargo.lock index 47585ba..563e8b9 100644 --- a/nssa/program_methods/guest/Cargo.lock +++ b/nssa/program_methods/guest/Cargo.lock @@ -1574,6 +1574,7 @@ checksum = "a5b0c77c1b780822bc749a33e39aeb2c07584ab93332303babeabb645298a76e" name = "nssa-core" version = "0.1.0" dependencies = [ + "borsh", "chacha20", "risc0-zkvm", "serde", diff --git a/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs b/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs index d8ed15d..6696245 100644 --- a/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs +++ b/nssa/program_methods/guest/src/bin/privacy_preserving_circuit.rs @@ -27,11 +27,11 @@ fn main() { let ProgramOutput { pre_states, post_states, - chained_call, + chained_calls, } = program_output; // TODO: implement chained calls for privacy preserving transactions - if chained_call.is_some() { + if !chained_calls.is_empty() { panic!("Privacy preserving transactions do not support yet chained calls.") } diff --git a/nssa/src/encoding/privacy_preserving_transaction.rs b/nssa/src/encoding/privacy_preserving_transaction.rs index 5788e6f..fcb6c94 100644 --- a/nssa/src/encoding/privacy_preserving_transaction.rs +++ b/nssa/src/encoding/privacy_preserving_transaction.rs @@ -1,258 +1,24 @@ -use std::io::{Cursor, Read}; - -use nssa_core::{ - Commitment, Nullifier, - account::Account, - encryption::{Ciphertext, EphemeralPublicKey}, -}; - use crate::{ - Address, PrivacyPreservingTransaction, PublicKey, Signature, - error::NssaError, - privacy_preserving_transaction::{ - circuit::Proof, - message::{EncryptedAccountData, Message}, - witness_set::WitnessSet, - }, + PrivacyPreservingTransaction, error::NssaError, + privacy_preserving_transaction::message::Message, }; -const MESSAGE_ENCODING_PREFIX_LEN: usize = 32; -const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] = - b"/NSSA/v0.2/TxMessage/Private/\x00\x00\x00"; - -impl EncryptedAccountData { - pub fn to_bytes(&self) -> Vec { - let mut bytes = self.ciphertext.to_bytes(); - bytes.extend_from_slice(&self.epk.to_bytes()); - bytes.push(self.view_tag); - bytes - } - - pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { - let ciphertext = Ciphertext::from_cursor(cursor)?; - let epk = EphemeralPublicKey::from_cursor(cursor)?; - - let mut tag_bytes = [0; 1]; - cursor.read_exact(&mut tag_bytes)?; - let view_tag = tag_bytes[0]; - - Ok(Self { - ciphertext, - epk, - view_tag, - }) - } -} - impl Message { - pub(crate) fn to_bytes(&self) -> Vec { - let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec(); - - // Public addresses - let public_addresses_len: u32 = self.public_addresses.len() as u32; - bytes.extend_from_slice(&public_addresses_len.to_le_bytes()); - for address in &self.public_addresses { - bytes.extend_from_slice(address.value()); - } - // Nonces - let nonces_len = self.nonces.len() as u32; - bytes.extend(&nonces_len.to_le_bytes()); - for nonce in &self.nonces { - bytes.extend(&nonce.to_le_bytes()); - } - // Public post states - let public_post_states_len: u32 = self.public_post_states.len() as u32; - bytes.extend_from_slice(&public_post_states_len.to_le_bytes()); - for account in &self.public_post_states { - bytes.extend_from_slice(&account.to_bytes()); - } - - // Encrypted post states - let encrypted_accounts_post_states_len: u32 = - self.encrypted_private_post_states.len() as u32; - bytes.extend_from_slice(&encrypted_accounts_post_states_len.to_le_bytes()); - for encrypted_account in &self.encrypted_private_post_states { - bytes.extend_from_slice(&encrypted_account.to_bytes()); - } - - // New commitments - let new_commitments_len: u32 = self.new_commitments.len() as u32; - bytes.extend_from_slice(&new_commitments_len.to_le_bytes()); - for commitment in &self.new_commitments { - bytes.extend_from_slice(&commitment.to_byte_array()); - } - - // New nullifiers - let new_nullifiers_len: u32 = self.new_nullifiers.len() as u32; - bytes.extend_from_slice(&new_nullifiers_len.to_le_bytes()); - for (nullifier, commitment_set_digest) in &self.new_nullifiers { - bytes.extend_from_slice(&nullifier.to_byte_array()); - bytes.extend_from_slice(commitment_set_digest); - } - - bytes + pub fn to_bytes(&self) -> Vec { + borsh::to_vec(&self).expect("Autoderived borsh serialization failure") } - #[allow(unused)] - pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { - let prefix = { - let mut this = [0u8; MESSAGE_ENCODING_PREFIX_LEN]; - cursor.read_exact(&mut this)?; - this - }; - if &prefix != MESSAGE_ENCODING_PREFIX { - return Err(NssaError::TransactionDeserializationError( - "Invalid privacy preserving message prefix".to_string(), - )); - } - - let mut len_bytes = [0u8; 4]; - - // Public addresses - cursor.read_exact(&mut len_bytes)?; - let public_addresses_len = u32::from_le_bytes(len_bytes) as usize; - let mut public_addresses = Vec::with_capacity(public_addresses_len); - for _ in 0..public_addresses_len { - let mut value = [0u8; 32]; - cursor.read_exact(&mut value)?; - public_addresses.push(Address::new(value)) - } - - // Nonces - cursor.read_exact(&mut len_bytes)?; - let nonces_len = u32::from_le_bytes(len_bytes) as usize; - let mut nonces = Vec::with_capacity(nonces_len); - for _ in 0..nonces_len { - let mut buf = [0u8; 16]; - cursor.read_exact(&mut buf)?; - nonces.push(u128::from_le_bytes(buf)) - } - - // Public post states - cursor.read_exact(&mut len_bytes)?; - let public_post_states_len = u32::from_le_bytes(len_bytes) as usize; - let mut public_post_states = Vec::with_capacity(public_post_states_len); - for _ in 0..public_post_states_len { - public_post_states.push(Account::from_cursor(cursor)?); - } - - // Encrypted private post states - cursor.read_exact(&mut len_bytes)?; - let encrypted_len = u32::from_le_bytes(len_bytes) as usize; - let mut encrypted_private_post_states = Vec::with_capacity(encrypted_len); - for _ in 0..encrypted_len { - encrypted_private_post_states.push(EncryptedAccountData::from_cursor(cursor)?); - } - - // New commitments - cursor.read_exact(&mut len_bytes)?; - let new_commitments_len = u32::from_le_bytes(len_bytes) as usize; - let mut new_commitments = Vec::with_capacity(new_commitments_len); - for _ in 0..new_commitments_len { - new_commitments.push(Commitment::from_cursor(cursor)?); - } - - // New nullifiers - cursor.read_exact(&mut len_bytes)?; - let new_nullifiers_len = u32::from_le_bytes(len_bytes) as usize; - let mut new_nullifiers = Vec::with_capacity(new_nullifiers_len); - for _ in 0..new_nullifiers_len { - let nullifier = Nullifier::from_cursor(cursor)?; - let mut commitment_set_digest = [0; 32]; - cursor.read_exact(&mut commitment_set_digest)?; - new_nullifiers.push((nullifier, commitment_set_digest)); - } - - Ok(Self { - public_addresses, - nonces, - public_post_states, - encrypted_private_post_states, - new_commitments, - new_nullifiers, - }) - } -} - -impl WitnessSet { - pub(crate) fn to_bytes(&self) -> Vec { - let mut bytes = Vec::new(); - let size = self.signatures_and_public_keys().len() as u32; - bytes.extend_from_slice(&size.to_le_bytes()); - for (signature, public_key) in self.signatures_and_public_keys() { - bytes.extend_from_slice(signature.to_bytes()); - bytes.extend_from_slice(public_key.to_bytes()); - } - bytes.extend_from_slice(&self.proof.to_bytes()); - bytes - } - - pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { - let num_signatures: u32 = { - let mut buf = [0u8; 4]; - cursor.read_exact(&mut buf)?; - u32::from_le_bytes(buf) - }; - let mut signatures_and_public_keys = Vec::with_capacity(num_signatures as usize); - for _i in 0..num_signatures { - let signature = Signature::from_cursor(cursor)?; - let public_key = PublicKey::from_cursor(cursor)?; - signatures_and_public_keys.push((signature, public_key)) - } - let proof = Proof::from_cursor(cursor)?; - Ok(Self { - signatures_and_public_keys, - proof, - }) + pub fn from_bytes(bytes: &[u8]) -> Result { + Ok(borsh::from_slice(bytes)?) } } impl PrivacyPreservingTransaction { pub fn to_bytes(&self) -> Vec { - let mut bytes = self.message().to_bytes(); - bytes.extend_from_slice(&self.witness_set().to_bytes()); - bytes + borsh::to_vec(&self).expect("Autoderived borsh serialization failure") } pub fn from_bytes(bytes: &[u8]) -> Result { - let mut cursor = Cursor::new(bytes); - Self::from_cursor(&mut cursor) - } - - pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { - let message = Message::from_cursor(cursor)?; - let witness_set = WitnessSet::from_cursor(cursor)?; - Ok(PrivacyPreservingTransaction::new(message, witness_set)) + Ok(borsh::from_slice(bytes)?) } } - -impl Proof { - pub fn to_bytes(&self) -> Vec { - let mut bytes = Vec::new(); - let proof_len = self.0.len() as u32; - bytes.extend_from_slice(&proof_len.to_le_bytes()); - bytes.extend_from_slice(&self.0); - bytes - } - - pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { - let proof_len = u32_from_cursor(cursor) as usize; - let mut proof = Vec::with_capacity(proof_len); - - for _ in 0..proof_len { - let mut one_byte_buf = [0u8]; - - cursor.read_exact(&mut one_byte_buf)?; - - proof.push(one_byte_buf[0]); - } - Ok(Self(proof)) - } -} - -// TODO: Improve error handling. Remove unwraps. -pub fn u32_from_cursor(cursor: &mut Cursor<&[u8]>) -> u32 { - let mut word_buf = [0u8; 4]; - cursor.read_exact(&mut word_buf).unwrap(); - u32::from_le_bytes(word_buf) -} diff --git a/nssa/src/encoding/program_deployment_transaction.rs b/nssa/src/encoding/program_deployment_transaction.rs index 2dc91b4..ee66863 100644 --- a/nssa/src/encoding/program_deployment_transaction.rs +++ b/nssa/src/encoding/program_deployment_transaction.rs @@ -1,77 +1,17 @@ -// TODO: Consider switching to deriving Borsh - -use std::io::{Cursor, Read}; - -use crate::{ - ProgramDeploymentTransaction, error::NssaError, program_deployment_transaction::Message, -}; - -const MESSAGE_ENCODING_PREFIX_LEN: usize = 32; -const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] = - b"/NSSA/v0.2/TxMessage/Program/\x00\x00\x00"; - -impl Message { - /// Serializes a `Message` into bytes in the following layout: - /// PREFIX || bytecode_len (4 bytes LE) || - /// Integers are encoded in little-endian byte order, and fields appear in the above order. - pub(crate) fn to_bytes(&self) -> Vec { - let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec(); - let bytecode_len = self.bytecode.len() as u32; - bytes.extend(&bytecode_len.to_le_bytes()); - bytes.extend(&self.bytecode); - bytes - } - - pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { - let prefix = { - let mut this = [0u8; MESSAGE_ENCODING_PREFIX_LEN]; - cursor.read_exact(&mut this)?; - this - }; - if &prefix != MESSAGE_ENCODING_PREFIX { - return Err(NssaError::TransactionDeserializationError( - "Invalid public message prefix".to_string(), - )); - } - let bytecode_len = u32_from_cursor(cursor)?; - let mut bytecode = vec![0; bytecode_len as usize]; - let num_bytes = cursor.read(&mut bytecode)?; - if num_bytes != bytecode_len as usize { - println!("num bytes: {}", num_bytes); - return Err(NssaError::TransactionDeserializationError( - "Invalid number of bytes".to_string(), - )); - } - Ok(Self { bytecode }) - } -} +use crate::{ProgramDeploymentTransaction, error::NssaError}; impl ProgramDeploymentTransaction { pub fn to_bytes(&self) -> Vec { - self.message.to_bytes() + borsh::to_vec(&self).expect("Autoderived borsh serialization failure") } pub fn from_bytes(bytes: &[u8]) -> Result { - let mut cursor = Cursor::new(bytes); - Self::from_cursor(&mut cursor) + Ok(borsh::from_slice(bytes)?) } - - pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { - let message = Message::from_cursor(cursor)?; - Ok(Self::new(message)) - } -} - -fn u32_from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { - let mut word_buf = [0u8; 4]; - cursor.read_exact(&mut word_buf)?; - Ok(u32::from_le_bytes(word_buf)) } #[cfg(test)] mod tests { - use std::io::Cursor; - use crate::{ProgramDeploymentTransaction, program_deployment_transaction::Message}; #[test] @@ -79,8 +19,7 @@ mod tests { let message = Message::new(vec![0xca, 0xfe, 0xca, 0xfe, 0x01, 0x02, 0x03]); let tx = ProgramDeploymentTransaction::new(message); let bytes = tx.to_bytes(); - let mut cursor = Cursor::new(bytes.as_ref()); - let tx_from_cursor = ProgramDeploymentTransaction::from_cursor(&mut cursor).unwrap(); - assert_eq!(tx, tx_from_cursor); + let tx_from_bytes = ProgramDeploymentTransaction::from_bytes(&bytes).unwrap(); + assert_eq!(tx, tx_from_bytes); } } diff --git a/nssa/src/encoding/public_transaction.rs b/nssa/src/encoding/public_transaction.rs index 03c34ee..ea0988c 100644 --- a/nssa/src/encoding/public_transaction.rs +++ b/nssa/src/encoding/public_transaction.rs @@ -1,153 +1,17 @@ -// TODO: Consider switching to deriving Borsh - -use std::io::{Cursor, Read}; - -use nssa_core::program::ProgramId; - -use crate::{ - Address, PublicKey, PublicTransaction, Signature, - error::NssaError, - public_transaction::{Message, WitnessSet}, -}; - -const MESSAGE_ENCODING_PREFIX_LEN: usize = 32; -const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] = - b"/NSSA/v0.2/TxMessage/Public/\x00\x00\x00\x00"; +use crate::{PublicTransaction, error::NssaError, public_transaction::Message}; impl Message { - /// Serializes a `Message` into bytes in the following layout: - /// PREFIX || (4 bytes LE) * 8 || addresses_len (4 bytes LE) || addresses (32 bytes * N) || nonces_len (4 bytes LE) || nonces (16 bytes LE * M) || instruction_data_len || instruction_data (4 bytes LE * K) - /// Integers and words are encoded in little-endian byte order, and fields appear in the above order. pub(crate) fn to_bytes(&self) -> Vec { - let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec(); - // program_id: [u32; 8] - for word in &self.program_id { - bytes.extend_from_slice(&word.to_le_bytes()); - } - // addresses: Vec<[u8;32]> - // serialize length as u32 little endian, then all addresses concatenated - let addresses_len = self.addresses.len() as u32; - bytes.extend(&addresses_len.to_le_bytes()); - for addr in &self.addresses { - bytes.extend_from_slice(addr.value()); - } - // nonces: Vec - // serialize length as u32 little endian, then all nonces concatenated in LE - let nonces_len = self.nonces.len() as u32; - bytes.extend(&nonces_len.to_le_bytes()); - for nonce in &self.nonces { - bytes.extend(&nonce.to_le_bytes()); - } - // instruction_data: Vec - // serialize length as u32 little endian, then all addresses concatenated - let instr_len = self.instruction_data.len() as u32; - bytes.extend(&instr_len.to_le_bytes()); - for word in &self.instruction_data { - bytes.extend(&word.to_le_bytes()); - } - - bytes - } - - pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { - let prefix = { - let mut this = [0u8; MESSAGE_ENCODING_PREFIX_LEN]; - cursor.read_exact(&mut this)?; - this - }; - if &prefix != MESSAGE_ENCODING_PREFIX { - return Err(NssaError::TransactionDeserializationError( - "Invalid public message prefix".to_string(), - )); - } - - let program_id: ProgramId = { - let mut this = [0u32; 8]; - for item in &mut this { - *item = u32_from_cursor(cursor)?; - } - this - }; - let addresses_len = u32_from_cursor(cursor)?; - let mut addresses = Vec::with_capacity(addresses_len as usize); - for _ in 0..addresses_len { - let mut value = [0u8; 32]; - cursor.read_exact(&mut value)?; - addresses.push(Address::new(value)) - } - let nonces_len = u32_from_cursor(cursor)?; - let mut nonces = Vec::with_capacity(nonces_len as usize); - for _ in 0..nonces_len { - let mut buf = [0u8; 16]; - cursor.read_exact(&mut buf)?; - nonces.push(u128::from_le_bytes(buf)) - } - let instruction_data_len = u32_from_cursor(cursor)?; - let mut instruction_data = Vec::with_capacity(instruction_data_len as usize); - for _ in 0..instruction_data_len { - let word = u32_from_cursor(cursor)?; - instruction_data.push(word) - } - Ok(Self { - program_id, - addresses, - nonces, - instruction_data, - }) - } -} - -impl WitnessSet { - pub(crate) fn to_bytes(&self) -> Vec { - let mut bytes = Vec::new(); - let size = self.signatures_and_public_keys().len() as u32; - bytes.extend_from_slice(&size.to_le_bytes()); - for (signature, public_key) in self.signatures_and_public_keys() { - bytes.extend_from_slice(signature.to_bytes()); - bytes.extend_from_slice(public_key.to_bytes()); - } - bytes - } - - pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { - let num_signatures: u32 = { - let mut buf = [0u8; 4]; - cursor.read_exact(&mut buf)?; - u32::from_le_bytes(buf) - }; - let mut signatures_and_public_keys = Vec::with_capacity(num_signatures as usize); - for _i in 0..num_signatures { - let signature = Signature::from_cursor(cursor)?; - let public_key = PublicKey::from_cursor(cursor)?; - signatures_and_public_keys.push((signature, public_key)) - } - Ok(Self { - signatures_and_public_keys, - }) + borsh::to_vec(&self).expect("Autoderived borsh serialization failure") } } impl PublicTransaction { pub fn to_bytes(&self) -> Vec { - let mut bytes = self.message().to_bytes(); - bytes.extend_from_slice(&self.witness_set().to_bytes()); - bytes + borsh::to_vec(&self).expect("Autoderived borsh serialization failure") } pub fn from_bytes(bytes: &[u8]) -> Result { - let mut cursor = Cursor::new(bytes); - Self::from_cursor(&mut cursor) - } - - pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { - let message = Message::from_cursor(cursor)?; - let witness_set = WitnessSet::from_cursor(cursor)?; - Ok(PublicTransaction::new(message, witness_set)) + Ok(borsh::from_slice(bytes)?) } } - -fn u32_from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { - let mut word_buf = [0u8; 4]; - cursor.read_exact(&mut word_buf)?; - Ok(u32::from_le_bytes(word_buf)) -} diff --git a/nssa/src/error.rs b/nssa/src/error.rs index 8ed9657..45d5310 100644 --- a/nssa/src/error.rs +++ b/nssa/src/error.rs @@ -54,4 +54,7 @@ pub enum NssaError { #[error("Program already exists")] ProgramAlreadyExists, + + #[error("Chain of calls is too long")] + MaxChainedCallsDepthExceeded, } diff --git a/nssa/src/lib.rs b/nssa/src/lib.rs index 2fe13b9..b698ae3 100644 --- a/nssa/src/lib.rs +++ b/nssa/src/lib.rs @@ -18,14 +18,11 @@ mod signature; mod state; pub use nssa_core::account::{Account, AccountId}; -pub use nssa_core::address::Address; pub use privacy_preserving_transaction::{ PrivacyPreservingTransaction, circuit::execute_and_prove, }; pub use program_deployment_transaction::ProgramDeploymentTransaction; pub use program_methods::PRIVACY_PRESERVING_CIRCUIT_ID; pub use public_transaction::PublicTransaction; -pub use signature::PrivateKey; -pub use signature::PublicKey; -pub use signature::Signature; +pub use signature::{PrivateKey, PublicKey, Signature}; pub use state::V02State; diff --git a/nssa/src/merkle_tree/mod.rs b/nssa/src/merkle_tree/mod.rs index 7b30d78..c4501cf 100644 --- a/nssa/src/merkle_tree/mod.rs +++ b/nssa/src/merkle_tree/mod.rs @@ -43,6 +43,7 @@ impl MerkleTree { (1 << (capacity_depth - tree_depth)) - 1 } } + /// Number of levels required to hold all nodes fn depth(&self) -> usize { self.length.next_power_of_two().trailing_zeros() as usize diff --git a/nssa/src/privacy_preserving_transaction/circuit.rs b/nssa/src/privacy_preserving_transaction/circuit.rs index 9ce0610..eeba692 100644 --- a/nssa/src/privacy_preserving_transaction/circuit.rs +++ b/nssa/src/privacy_preserving_transaction/circuit.rs @@ -1,3 +1,4 @@ +use borsh::{BorshDeserialize, BorshSerialize}; use nssa_core::{ MembershipProof, NullifierPublicKey, NullifierSecretKey, PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput, SharedSecretKey, @@ -6,12 +7,14 @@ use nssa_core::{ }; use risc0_zkvm::{ExecutorEnv, InnerReceipt, Receipt, default_prover}; -use crate::{error::NssaError, program::Program}; - -use crate::program_methods::{PRIVACY_PRESERVING_CIRCUIT_ELF, PRIVACY_PRESERVING_CIRCUIT_ID}; +use crate::{ + error::NssaError, + program::Program, + program_methods::{PRIVACY_PRESERVING_CIRCUIT_ELF, PRIVACY_PRESERVING_CIRCUIT_ID}, +}; /// Proof of the privacy preserving execution circuit -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct Proof(pub(crate) Vec); /// Generates a proof of the execution of a NSSA program inside the privacy preserving execution @@ -95,6 +98,7 @@ mod tests { account::{Account, AccountId, AccountWithMetadata}, }; + use super::*; use crate::{ privacy_preserving_transaction::circuit::execute_and_prove, program::Program, @@ -104,8 +108,6 @@ mod tests { }, }; - use super::*; - #[test] fn prove_privacy_preserving_execution_circuit_public_and_private_pre_accounts() { let recipient_keys = test_private_account_keys_1(); diff --git a/nssa/src/privacy_preserving_transaction/message.rs b/nssa/src/privacy_preserving_transaction/message.rs index 5911838..6d19532 100644 --- a/nssa/src/privacy_preserving_transaction/message.rs +++ b/nssa/src/privacy_preserving_transaction/message.rs @@ -1,3 +1,4 @@ +use borsh::{BorshDeserialize, BorshSerialize}; use nssa_core::{ Commitment, CommitmentSetDigest, Nullifier, NullifierPublicKey, PrivacyPreservingCircuitOutput, account::{Account, Nonce}, @@ -5,11 +6,11 @@ use nssa_core::{ }; use sha2::{Digest, Sha256}; -use crate::{Address, error::NssaError}; +use crate::{AccountId, error::NssaError}; pub type ViewTag = u8; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct EncryptedAccountData { pub ciphertext: Ciphertext, pub epk: EphemeralPublicKey, @@ -42,9 +43,9 @@ impl EncryptedAccountData { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct Message { - pub(crate) public_addresses: Vec
, + pub(crate) public_account_ids: Vec, pub(crate) nonces: Vec, pub(crate) public_post_states: Vec, pub encrypted_private_post_states: Vec, @@ -54,7 +55,7 @@ pub struct Message { impl Message { pub fn try_from_circuit_output( - public_addresses: Vec
, + public_account_ids: Vec, nonces: Vec, public_keys: Vec<( NullifierPublicKey, @@ -78,7 +79,7 @@ impl Message { }) .collect(); Ok(Self { - public_addresses, + public_account_ids, nonces, public_post_states: output.public_post_states, encrypted_private_post_states, @@ -90,8 +91,6 @@ impl Message { #[cfg(test)] pub mod tests { - use std::io::Cursor; - use nssa_core::{ Commitment, EncryptionScheme, Nullifier, NullifierPublicKey, SharedSecretKey, account::Account, @@ -100,7 +99,7 @@ pub mod tests { use sha2::{Digest, Sha256}; use crate::{ - Address, + AccountId, privacy_preserving_transaction::message::{EncryptedAccountData, Message}, }; @@ -114,7 +113,7 @@ pub mod tests { let npk1 = NullifierPublicKey::from(&nsk1); let npk2 = NullifierPublicKey::from(&nsk2); - let public_addresses = vec![Address::new([1; 32])]; + let public_account_ids = vec![AccountId::new([1; 32])]; let nonces = vec![1, 2, 3]; @@ -131,7 +130,7 @@ pub mod tests { )]; Message { - public_addresses: public_addresses.clone(), + public_account_ids: public_account_ids.clone(), nonces: nonces.clone(), public_post_states: public_post_states.clone(), encrypted_private_post_states: encrypted_private_post_states.clone(), @@ -140,17 +139,6 @@ pub mod tests { } } - #[test] - fn test_message_serialization_roundtrip() { - let message = message_for_tests(); - - let bytes = message.to_bytes(); - let mut cursor = Cursor::new(bytes.as_ref()); - let message_from_cursor = Message::from_cursor(&mut cursor).unwrap(); - - assert_eq!(message, message_from_cursor); - } - #[test] fn test_encrypted_account_data_constructor() { let npk = NullifierPublicKey::from(&[1; 32]); diff --git a/nssa/src/privacy_preserving_transaction/transaction.rs b/nssa/src/privacy_preserving_transaction/transaction.rs index 3e89ba7..2cb0889 100644 --- a/nssa/src/privacy_preserving_transaction/transaction.rs +++ b/nssa/src/privacy_preserving_transaction/transaction.rs @@ -1,19 +1,19 @@ use std::collections::{HashMap, HashSet}; +use borsh::{BorshDeserialize, BorshSerialize}; use nssa_core::{ Commitment, CommitmentSetDigest, Nullifier, PrivacyPreservingCircuitOutput, account::{Account, AccountWithMetadata}, }; -use crate::error::NssaError; -use crate::privacy_preserving_transaction::circuit::Proof; -use crate::privacy_preserving_transaction::message::EncryptedAccountData; -use crate::{Address, V02State}; +use super::{message::Message, witness_set::WitnessSet}; +use crate::{ + AccountId, V02State, + error::NssaError, + privacy_preserving_transaction::{circuit::Proof, message::EncryptedAccountData}, +}; -use super::message::Message; -use super::witness_set::WitnessSet; - -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct PrivacyPreservingTransaction { pub message: Message, witness_set: WitnessSet, @@ -30,7 +30,7 @@ impl PrivacyPreservingTransaction { pub(crate) fn validate_and_produce_public_state_diff( &self, state: &V02State, - ) -> Result, NssaError> { + ) -> Result, NssaError> { let message = &self.message; let witness_set = &self.witness_set; @@ -41,10 +41,10 @@ impl PrivacyPreservingTransaction { )); } - // 2. Check there are no duplicate addresses in the public_addresses list. - if n_unique(&message.public_addresses) != message.public_addresses.len() { + // 2. Check there are no duplicate account_ids in the public_account_ids list. + if n_unique(&message.public_account_ids) != message.public_account_ids.len() { return Err(NssaError::InvalidInput( - "Duplicate addresses found in message".into(), + "Duplicate account_ids found in message".into(), )); } @@ -77,10 +77,10 @@ impl PrivacyPreservingTransaction { )); } - let signer_addresses = self.signer_addresses(); + let signer_account_ids = self.signer_account_ids(); // Check nonces corresponds to the current nonces on the public state. - for (address, nonce) in signer_addresses.iter().zip(&message.nonces) { - let current_nonce = state.get_account_by_address(address).nonce; + for (account_id, nonce) in signer_account_ids.iter().zip(&message.nonces) { + let current_nonce = state.get_account_by_id(account_id).nonce; if current_nonce != *nonce { return Err(NssaError::InvalidInput("Nonce mismatch".into())); } @@ -88,13 +88,13 @@ impl PrivacyPreservingTransaction { // Build pre_states for proof verification let public_pre_states: Vec<_> = message - .public_addresses + .public_account_ids .iter() - .map(|address| { + .map(|account_id| { AccountWithMetadata::new( - state.get_account_by_address(address), - signer_addresses.contains(address), - *address, + state.get_account_by_id(account_id), + signer_account_ids.contains(account_id), + *account_id, ) }) .collect(); @@ -116,7 +116,7 @@ impl PrivacyPreservingTransaction { state.check_nullifiers_are_valid(&message.new_nullifiers)?; Ok(message - .public_addresses + .public_account_ids .iter() .cloned() .zip(message.public_post_states.clone()) @@ -131,11 +131,11 @@ impl PrivacyPreservingTransaction { &self.witness_set } - pub(crate) fn signer_addresses(&self) -> Vec
{ + pub(crate) fn signer_account_ids(&self) -> Vec { self.witness_set .signatures_and_public_keys() .iter() - .map(|(_, public_key)| Address::from(public_key)) + .map(|(_, public_key)| AccountId::from(public_key)) .collect() } } @@ -174,17 +174,17 @@ fn n_unique(data: &[T]) -> usize { #[cfg(test)] mod tests { use crate::{ - Address, PrivacyPreservingTransaction, PrivateKey, PublicKey, + AccountId, PrivacyPreservingTransaction, PrivateKey, PublicKey, privacy_preserving_transaction::{ circuit::Proof, message::tests::message_for_tests, witness_set::WitnessSet, }, }; - fn keys_for_tests() -> (PrivateKey, PrivateKey, Address, Address) { + fn keys_for_tests() -> (PrivateKey, PrivateKey, AccountId, AccountId) { let key1 = PrivateKey::try_new([1; 32]).unwrap(); let key2 = PrivateKey::try_new([2; 32]).unwrap(); - let addr1 = Address::from(&PublicKey::new_from_private_key(&key1)); - let addr2 = Address::from(&PublicKey::new_from_private_key(&key2)); + let addr1 = AccountId::from(&PublicKey::new_from_private_key(&key1)); + let addr2 = AccountId::from(&PublicKey::new_from_private_key(&key2)); (key1, key2, addr1, addr2) } diff --git a/nssa/src/privacy_preserving_transaction/witness_set.rs b/nssa/src/privacy_preserving_transaction/witness_set.rs index 9fc587e..b38b0fb 100644 --- a/nssa/src/privacy_preserving_transaction/witness_set.rs +++ b/nssa/src/privacy_preserving_transaction/witness_set.rs @@ -1,9 +1,11 @@ +use borsh::{BorshDeserialize, BorshSerialize}; + use crate::{ PrivateKey, PublicKey, Signature, privacy_preserving_transaction::{circuit::Proof, message::Message}, }; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct WitnessSet { pub(crate) signatures_and_public_keys: Vec<(Signature, PublicKey)>, pub(crate) proof: Proof, diff --git a/nssa/src/program.rs b/nssa/src/program.rs index 11eb413..d3f28b5 100644 --- a/nssa/src/program.rs +++ b/nssa/src/program.rs @@ -1,13 +1,14 @@ -use crate::program_methods::{AUTHENTICATED_TRANSFER_ELF, PINATA_ELF, TOKEN_ELF}; use nssa_core::{ account::AccountWithMetadata, program::{InstructionData, ProgramId, ProgramOutput}, }; - use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor, serde::to_vec}; use serde::Serialize; -use crate::error::NssaError; +use crate::{ + error::NssaError, + program_methods::{AUTHENTICATED_TRANSFER_ELF, PINATA_ELF, TOKEN_ELF}, +}; /// Maximum number of cycles for a public execution. /// TODO: Make this variable when fees are implemented @@ -107,13 +108,15 @@ impl Program { #[cfg(test)] mod tests { - use crate::program_methods::{ - AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, PINATA_ELF, PINATA_ID, TOKEN_ELF, - TOKEN_ID, - }; use nssa_core::account::{Account, AccountId, AccountWithMetadata}; - use crate::program::Program; + use crate::{ + program::Program, + program_methods::{ + AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID, PINATA_ELF, PINATA_ID, + TOKEN_ELF, TOKEN_ID, + }, + }; impl Program { /// A program that changes the nonce of an account diff --git a/nssa/src/program_deployment_transaction/message.rs b/nssa/src/program_deployment_transaction/message.rs index 6a5c670..65e9ec2 100644 --- a/nssa/src/program_deployment_transaction/message.rs +++ b/nssa/src/program_deployment_transaction/message.rs @@ -1,4 +1,6 @@ -#[derive(Debug, Clone, PartialEq, Eq)] +use borsh::{BorshDeserialize, BorshSerialize}; + +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct Message { pub(crate) bytecode: Vec, } diff --git a/nssa/src/program_deployment_transaction/transaction.rs b/nssa/src/program_deployment_transaction/transaction.rs index 4ec2e10..c5f31a1 100644 --- a/nssa/src/program_deployment_transaction/transaction.rs +++ b/nssa/src/program_deployment_transaction/transaction.rs @@ -1,8 +1,10 @@ +use borsh::{BorshDeserialize, BorshSerialize}; + use crate::{ V02State, error::NssaError, program::Program, program_deployment_transaction::message::Message, }; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct ProgramDeploymentTransaction { pub(crate) message: Message, } diff --git a/nssa/src/public_transaction/message.rs b/nssa/src/public_transaction/message.rs index 68cb5fb..63ed03f 100644 --- a/nssa/src/public_transaction/message.rs +++ b/nssa/src/public_transaction/message.rs @@ -1,15 +1,16 @@ +use borsh::{BorshDeserialize, BorshSerialize}; use nssa_core::{ account::Nonce, program::{InstructionData, ProgramId}, }; use serde::Serialize; -use crate::{Address, error::NssaError, program::Program}; +use crate::{AccountId, error::NssaError, program::Program}; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct Message { pub(crate) program_id: ProgramId, - pub(crate) addresses: Vec
, + pub(crate) account_ids: Vec, pub(crate) nonces: Vec, pub(crate) instruction_data: InstructionData, } @@ -17,14 +18,14 @@ pub struct Message { impl Message { pub fn try_new( program_id: ProgramId, - addresses: Vec
, + account_ids: Vec, nonces: Vec, instruction: T, ) -> Result { let instruction_data = Program::serialize_instruction(instruction)?; Ok(Self { program_id, - addresses, + account_ids, nonces, instruction_data, }) diff --git a/nssa/src/public_transaction/transaction.rs b/nssa/src/public_transaction/transaction.rs index d118d0c..28f33fb 100644 --- a/nssa/src/public_transaction/transaction.rs +++ b/nssa/src/public_transaction/transaction.rs @@ -1,9 +1,9 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::{HashMap, HashSet, VecDeque}; +use borsh::{BorshDeserialize, BorshSerialize}; use nssa_core::{ - account::{Account, AccountWithMetadata}, - address::Address, - program::{DEFAULT_PROGRAM_ID, validate_execution}, + account::{Account, AccountId, AccountWithMetadata}, + program::{ChainedCall, DEFAULT_PROGRAM_ID, validate_execution}, }; use sha2::{Digest, digest::FixedOutput}; @@ -11,14 +11,14 @@ use crate::{ V02State, error::NssaError, public_transaction::{Message, WitnessSet}, + state::MAX_NUMBER_CHAINED_CALLS, }; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct PublicTransaction { message: Message, witness_set: WitnessSet, } -const MAX_NUMBER_CHAINED_CALLS: usize = 10; impl PublicTransaction { pub fn new(message: Message, witness_set: WitnessSet) -> Self { @@ -36,11 +36,11 @@ impl PublicTransaction { &self.witness_set } - pub(crate) fn signer_addresses(&self) -> Vec
{ + pub(crate) fn signer_account_ids(&self) -> Vec { self.witness_set .signatures_and_public_keys() .iter() - .map(|(_, public_key)| Address::from(public_key)) + .map(|(_, public_key)| AccountId::from(public_key)) .collect() } @@ -54,14 +54,14 @@ impl PublicTransaction { pub(crate) fn validate_and_produce_public_state_diff( &self, state: &V02State, - ) -> Result, NssaError> { + ) -> Result, NssaError> { let message = self.message(); let witness_set = self.witness_set(); - // All addresses must be different - if message.addresses.iter().collect::>().len() != message.addresses.len() { + // All account_ids must be different + if message.account_ids.iter().collect::>().len() != message.account_ids.len() { return Err(NssaError::InvalidInput( - "Duplicate addresses found in message".into(), + "Duplicate account_ids found in message".into(), )); } @@ -79,46 +79,68 @@ impl PublicTransaction { )); } - let signer_addresses = self.signer_addresses(); + let signer_account_ids = self.signer_account_ids(); // Check nonces corresponds to the current nonces on the public state. - for (address, nonce) in signer_addresses.iter().zip(&message.nonces) { - let current_nonce = state.get_account_by_address(address).nonce; + for (account_id, nonce) in signer_account_ids.iter().zip(&message.nonces) { + let current_nonce = state.get_account_by_id(account_id).nonce; if current_nonce != *nonce { return Err(NssaError::InvalidInput("Nonce mismatch".into())); } } // Build pre_states for execution - let mut input_pre_states: Vec<_> = message - .addresses + let input_pre_states: Vec<_> = message + .account_ids .iter() - .map(|address| { + .map(|account_id| { AccountWithMetadata::new( - state.get_account_by_address(address), - signer_addresses.contains(address), - *address, + state.get_account_by_id(account_id), + signer_account_ids.contains(account_id), + *account_id, ) }) .collect(); - let mut state_diff: HashMap = HashMap::new(); + let mut state_diff: HashMap = HashMap::new(); - let mut program_id = message.program_id; - let mut instruction_data = message.instruction_data.clone(); + let initial_call = ChainedCall { + program_id: message.program_id, + instruction_data: message.instruction_data.clone(), + pre_states: input_pre_states, + }; + + let mut chained_calls = VecDeque::from_iter([initial_call]); + let mut chain_calls_counter = 0; + + while let Some(chained_call) = chained_calls.pop_front() { + if chain_calls_counter > MAX_NUMBER_CHAINED_CALLS { + return Err(NssaError::MaxChainedCallsDepthExceeded); + } - for _i in 0..MAX_NUMBER_CHAINED_CALLS { // Check the `program_id` corresponds to a deployed program - let Some(program) = state.programs().get(&program_id) else { + let Some(program) = state.programs().get(&chained_call.program_id) else { return Err(NssaError::InvalidInput("Unknown program".into())); }; - let mut program_output = program.execute(&input_pre_states, &instruction_data)?; + let mut program_output = + program.execute(&chained_call.pre_states, &chained_call.instruction_data)?; - // This check is equivalent to checking that the program output pre_states coinicide - // with the values in the public state or with any modifications to those values - // during the chain of calls. - if input_pre_states != program_output.pre_states { - return Err(NssaError::InvalidProgramBehavior); + for pre in &program_output.pre_states { + let account_id = pre.account_id; + // Check that the program output pre_states coinicide with the values in the public + // state or with any modifications to those values during the chain of calls. + let expected_pre = state_diff + .get(&account_id) + .cloned() + .unwrap_or_else(|| state.get_account_by_id(&account_id)); + if pre.account != expected_pre { + return Err(NssaError::InvalidProgramBehavior); + } + + // Check that authorization flags are consistent with the provided ones + if pre.is_authorized && !signer_account_ids.contains(&account_id) { + return Err(NssaError::InvalidProgramBehavior); + } } // Verify execution corresponds to a well-behaved program. @@ -126,7 +148,7 @@ impl PublicTransaction { if !validate_execution( &program_output.pre_states, &program_output.post_states, - program_id, + chained_call.program_id, ) { return Err(NssaError::InvalidProgramBehavior); } @@ -134,7 +156,7 @@ impl PublicTransaction { // The invoked program claims the accounts with default program id. for post in program_output.post_states.iter_mut() { if post.program_owner == DEFAULT_PROGRAM_ID { - post.program_owner = program_id; + post.program_owner = chained_call.program_id; } } @@ -147,37 +169,11 @@ impl PublicTransaction { state_diff.insert(pre.account_id, post.clone()); } - if let Some(next_chained_call) = program_output.chained_call { - program_id = next_chained_call.program_id; - instruction_data = next_chained_call.instruction_data; + for new_call in program_output.chained_calls.into_iter().rev() { + chained_calls.push_front(new_call); + } - // Build post states with metadata for next call - let mut post_states_with_metadata = Vec::new(); - for (pre, post) in program_output - .pre_states - .iter() - .zip(program_output.post_states) - { - let mut post_with_metadata = pre.clone(); - post_with_metadata.account = post.clone(); - post_states_with_metadata.push(post_with_metadata); - } - - input_pre_states = next_chained_call - .account_indices - .iter() - .map(|&i| { - post_states_with_metadata - .get(i) - .ok_or_else(|| { - NssaError::InvalidInput("Invalid account indices".into()) - }) - .cloned() - }) - .collect::, NssaError>>()?; - } else { - break; - }; + chain_calls_counter += 1; } Ok(state_diff) @@ -189,17 +185,17 @@ pub mod tests { use sha2::{Digest, digest::FixedOutput}; use crate::{ - Address, PrivateKey, PublicKey, PublicTransaction, Signature, V02State, + AccountId, PrivateKey, PublicKey, PublicTransaction, Signature, V02State, error::NssaError, program::Program, public_transaction::{Message, WitnessSet}, }; - fn keys_for_tests() -> (PrivateKey, PrivateKey, Address, Address) { + fn keys_for_tests() -> (PrivateKey, PrivateKey, AccountId, AccountId) { let key1 = PrivateKey::try_new([1; 32]).unwrap(); let key2 = PrivateKey::try_new([2; 32]).unwrap(); - let addr1 = Address::from(&PublicKey::new_from_private_key(&key1)); - let addr2 = Address::from(&PublicKey::new_from_private_key(&key2)); + let addr1 = AccountId::from(&PublicKey::new_from_private_key(&key1)); + let addr2 = AccountId::from(&PublicKey::new_from_private_key(&key2)); (key1, key2, addr1, addr2) } @@ -248,20 +244,20 @@ pub mod tests { } #[test] - fn test_signer_addresses() { + fn test_signer_account_ids() { let tx = transaction_for_tests(); - let expected_signer_addresses = vec![ - Address::new([ + let expected_signer_account_ids = vec![ + AccountId::new([ 208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9, 115, 84, 126, 106, 16, 111, 114, 241, 147, 194, 220, 131, 139, 68, ]), - Address::new([ + AccountId::new([ 231, 174, 119, 197, 239, 26, 5, 153, 147, 68, 175, 73, 159, 199, 138, 23, 5, 57, 141, 98, 237, 6, 207, 46, 20, 121, 246, 222, 248, 154, 57, 188, ]), ]; - let signer_addresses = tx.signer_addresses(); - assert_eq!(signer_addresses, expected_signer_addresses); + let signer_account_ids = tx.signer_account_ids(); + assert_eq!(signer_account_ids, expected_signer_account_ids); } #[test] @@ -286,7 +282,7 @@ pub mod tests { } #[test] - fn test_address_list_cant_have_duplicates() { + fn test_account_id_list_cant_have_duplicates() { let (key1, _, addr1, _) = keys_for_tests(); let state = state_for_tests(); let nonces = vec![0, 0]; diff --git a/nssa/src/public_transaction/witness_set.rs b/nssa/src/public_transaction/witness_set.rs index e5095ba..09a35a4 100644 --- a/nssa/src/public_transaction/witness_set.rs +++ b/nssa/src/public_transaction/witness_set.rs @@ -1,6 +1,8 @@ +use borsh::{BorshDeserialize, BorshSerialize}; + use crate::{PrivateKey, PublicKey, Signature, public_transaction::Message}; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct WitnessSet { pub(crate) signatures_and_public_keys: Vec<(Signature, PublicKey)>, } @@ -39,9 +41,8 @@ impl WitnessSet { #[cfg(test)] mod tests { - use crate::Address; - use super::*; + use crate::AccountId; #[test] fn test_for_message_constructor() { @@ -49,8 +50,8 @@ mod tests { let key2 = PrivateKey::try_new([2; 32]).unwrap(); let pubkey1 = PublicKey::new_from_private_key(&key1); let pubkey2 = PublicKey::new_from_private_key(&key2); - let addr1 = Address::from(&pubkey1); - let addr2 = Address::from(&pubkey2); + let addr1 = AccountId::from(&pubkey1); + let addr2 = AccountId::from(&pubkey2); let nonces = vec![1, 2]; let instruction = vec![1, 2, 3, 4]; let message = Message::try_new([0; 8], vec![addr1, addr2], nonces, instruction).unwrap(); diff --git a/nssa/src/signature/encoding.rs b/nssa/src/signature/encoding.rs deleted file mode 100644 index 999e4a1..0000000 --- a/nssa/src/signature/encoding.rs +++ /dev/null @@ -1,27 +0,0 @@ -use std::io::{Cursor, Read}; - -use crate::{PublicKey, Signature, error::NssaError}; - -impl PublicKey { - pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { - let mut value = [0u8; 32]; - cursor.read_exact(&mut value)?; - Self::try_new(value) - } - - pub(crate) fn to_bytes(&self) -> &[u8] { - self.value() - } -} - -impl Signature { - pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result { - let mut value = [0u8; 64]; - cursor.read_exact(&mut value)?; - Ok(Self { value }) - } - - pub(crate) fn to_bytes(&self) -> &[u8] { - &self.value - } -} diff --git a/nssa/src/signature/mod.rs b/nssa/src/signature/mod.rs index 2f18360..780ad63 100644 --- a/nssa/src/signature/mod.rs +++ b/nssa/src/signature/mod.rs @@ -1,13 +1,12 @@ -mod encoding; mod private_key; mod public_key; +use borsh::{BorshDeserialize, BorshSerialize}; pub use private_key::PrivateKey; pub use public_key::PublicKey; - use rand::{RngCore, rngs::OsRng}; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] pub struct Signature { value: [u8; 64], } diff --git a/nssa/src/signature/public_key.rs b/nssa/src/signature/public_key.rs index 095025d..57cda71 100644 --- a/nssa/src/signature/public_key.rs +++ b/nssa/src/signature/public_key.rs @@ -1,13 +1,27 @@ -use nssa_core::address::Address; +use borsh::{BorshDeserialize, BorshSerialize}; +use nssa_core::account::AccountId; use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; use crate::{PrivateKey, error::NssaError}; -use sha2::{Digest, Sha256}; - -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, Serialize, Deserialize)] pub struct PublicKey([u8; 32]); +impl BorshDeserialize for PublicKey { + fn deserialize_reader(reader: &mut R) -> std::io::Result { + let mut buf = [0u8; 32]; + reader.read_exact(&mut buf)?; + + Self::try_new(buf).map_err(|_| { + std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Invalid public key: not a valid point", + ) + }) + } +} + impl PublicKey { pub fn new_from_private_key(key: &PrivateKey) -> Self { let value = { @@ -20,7 +34,7 @@ impl PublicKey { Self(value) } - pub(super) fn try_new(value: [u8; 32]) -> Result { + pub fn try_new(value: [u8; 32]) -> Result { // Check point is valid let _ = secp256k1::XOnlyPublicKey::from_byte_array(value) .map_err(|_| NssaError::InvalidPublicKey)?; @@ -32,7 +46,7 @@ impl PublicKey { } } -impl From<&PublicKey> for Address { +impl From<&PublicKey> for AccountId { fn from(key: &PublicKey) -> Self { const PUBLIC_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/NSSA/v0.2/AccountId/Public/\x00\x00\x00\x00"; @@ -94,4 +108,14 @@ mod test { ); } } + + #[test] + fn test_correct_ser_deser_roundtrip() { + let pub_key = PublicKey::try_new([42; 32]).unwrap(); + + let pub_key_borsh_ser = borsh::to_vec(&pub_key).unwrap(); + let pub_key_new: PublicKey = borsh::from_slice(&pub_key_borsh_ser).unwrap(); + + assert_eq!(pub_key, pub_key_new); + } } diff --git a/nssa/src/state.rs b/nssa/src/state.rs index 4120824..cef7791 100644 --- a/nssa/src/state.rs +++ b/nssa/src/state.rs @@ -1,14 +1,19 @@ +use std::collections::{HashMap, HashSet}; + +use nssa_core::{ + Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, MembershipProof, Nullifier, + account::{Account, AccountId}, + program::ProgramId, +}; + use crate::{ error::NssaError, merkle_tree::MerkleTree, privacy_preserving_transaction::PrivacyPreservingTransaction, program::Program, program_deployment_transaction::ProgramDeploymentTransaction, public_transaction::PublicTransaction, }; -use nssa_core::{ - Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, MembershipProof, Nullifier, - account::Account, address::Address, program::ProgramId, -}; -use std::collections::{HashMap, HashSet}; + +pub const MAX_NUMBER_CHAINED_CALLS: usize = 10; pub(crate) struct CommitmentSet { merkle_tree: MerkleTree, @@ -58,27 +63,27 @@ impl CommitmentSet { type NullifierSet = HashSet; pub struct V02State { - public_state: HashMap, + public_state: HashMap, private_state: (CommitmentSet, NullifierSet), programs: HashMap, } impl V02State { pub fn new_with_genesis_accounts( - initial_data: &[(Address, u128)], + initial_data: &[(AccountId, u128)], initial_commitments: &[nssa_core::Commitment], ) -> Self { let authenticated_transfer_program = Program::authenticated_transfer_program(); let public_state = initial_data .iter() .copied() - .map(|(address, balance)| { + .map(|(account_id, balance)| { let account = Account { balance, program_owner: authenticated_transfer_program.id(), ..Account::default() }; - (address, account) + (account_id, account) }) .collect(); @@ -108,14 +113,14 @@ impl V02State { ) -> Result<(), NssaError> { let state_diff = tx.validate_and_produce_public_state_diff(self)?; - for (address, post) in state_diff.into_iter() { - let current_account = self.get_account_by_address_mut(address); + for (account_id, post) in state_diff.into_iter() { + let current_account = self.get_account_by_id_mut(account_id); *current_account = post; } - for address in tx.signer_addresses() { - let current_account = self.get_account_by_address_mut(address); + for account_id in tx.signer_account_ids() { + let current_account = self.get_account_by_id_mut(account_id); current_account.nonce += 1; } @@ -144,8 +149,8 @@ impl V02State { self.private_state.1.extend(new_nullifiers); // 4. Update public accounts - for (address, post) in public_state_diff.into_iter() { - let current_account = self.get_account_by_address_mut(address); + for (account_id, post) in public_state_diff.into_iter() { + let current_account = self.get_account_by_id_mut(account_id); *current_account = post; } @@ -161,13 +166,13 @@ impl V02State { Ok(()) } - fn get_account_by_address_mut(&mut self, address: Address) -> &mut Account { - self.public_state.entry(address).or_default() + fn get_account_by_id_mut(&mut self, account_id: AccountId) -> &mut Account { + self.public_state.entry(account_id).or_default() } - pub fn get_account_by_address(&self, address: &Address) -> Account { + pub fn get_account_by_id(&self, account_id: &AccountId) -> Account { self.public_state - .get(address) + .get(account_id) .cloned() .unwrap_or(Account::default()) } @@ -220,11 +225,11 @@ impl V02State { // TODO: Testnet only. Refactor to prevent compilation on mainnet. impl V02State { - pub fn add_pinata_program(&mut self, address: Address) { + pub fn add_pinata_program(&mut self, account_id: AccountId) { self.insert_program(Program::pinata()); self.public_state.insert( - address, + account_id, Account { program_owner: Program::pinata().id(), balance: 1500, @@ -241,8 +246,15 @@ pub mod tests { use std::collections::HashMap; + use nssa_core::{ + Commitment, Nullifier, NullifierPublicKey, NullifierSecretKey, SharedSecretKey, + account::{Account, AccountId, AccountWithMetadata, Nonce}, + encryption::{EphemeralPublicKey, IncomingViewingPublicKey, Scalar}, + program::ProgramId, + }; + use crate::{ - Address, PublicKey, PublicTransaction, V02State, + PublicKey, PublicTransaction, V02State, error::NssaError, execute_and_prove, privacy_preserving_transaction::{ @@ -251,27 +263,21 @@ pub mod tests { program::Program, public_transaction, signature::PrivateKey, - }; - - use nssa_core::{ - Commitment, Nullifier, NullifierPublicKey, NullifierSecretKey, SharedSecretKey, - account::{Account, AccountId, AccountWithMetadata, Nonce}, - encryption::{EphemeralPublicKey, IncomingViewingPublicKey, Scalar}, - program::ProgramId, + state::MAX_NUMBER_CHAINED_CALLS, }; fn transfer_transaction( - from: Address, + from: AccountId, from_key: PrivateKey, nonce: u128, - to: Address, + to: AccountId, balance: u128, ) -> PublicTransaction { - let addresses = vec![from, to]; + let account_ids = vec![from, to]; let nonces = vec![nonce]; let program_id = Program::authenticated_transfer_program().id(); let message = - public_transaction::Message::try_new(program_id, addresses, nonces, balance).unwrap(); + public_transaction::Message::try_new(program_id, account_ids, nonces, balance).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[&from_key]); PublicTransaction::new(message, witness_set) } @@ -280,8 +286,8 @@ pub mod tests { fn test_new_with_genesis() { let key1 = PrivateKey::try_new([1; 32]).unwrap(); let key2 = PrivateKey::try_new([2; 32]).unwrap(); - let addr1 = Address::from(&PublicKey::new_from_private_key(&key1)); - let addr2 = Address::from(&PublicKey::new_from_private_key(&key2)); + let addr1 = AccountId::from(&PublicKey::new_from_private_key(&key1)); + let addr2 = AccountId::from(&PublicKey::new_from_private_key(&key2)); let initial_data = [(addr1, 100u128), (addr2, 151u128)]; let authenticated_transfers_program = Program::authenticated_transfer_program(); let expected_public_state = { @@ -333,25 +339,25 @@ pub mod tests { } #[test] - fn test_get_account_by_address_non_default_account() { + fn test_get_account_by_account_id_non_default_account() { let key = PrivateKey::try_new([1; 32]).unwrap(); - let addr = Address::from(&PublicKey::new_from_private_key(&key)); - let initial_data = [(addr, 100u128)]; + let account_id = AccountId::from(&PublicKey::new_from_private_key(&key)); + let initial_data = [(account_id, 100u128)]; let state = V02State::new_with_genesis_accounts(&initial_data, &[]); - let expected_account = state.public_state.get(&addr).unwrap(); + let expected_account = state.public_state.get(&account_id).unwrap(); - let account = state.get_account_by_address(&addr); + let account = state.get_account_by_id(&account_id); assert_eq!(&account, expected_account); } #[test] - fn test_get_account_by_address_default_account() { - let addr2 = Address::new([0; 32]); + fn test_get_account_by_account_id_default_account() { + let addr2 = AccountId::new([0; 32]); let state = V02State::new_with_genesis_accounts(&[], &[]); let expected_account = Account::default(); - let account = state.get_account_by_address(&addr2); + let account = state.get_account_by_id(&addr2); assert_eq!(account, expected_account); } @@ -368,96 +374,96 @@ pub mod tests { #[test] fn transition_from_authenticated_transfer_program_invocation_default_account_destination() { let key = PrivateKey::try_new([1; 32]).unwrap(); - let address = Address::from(&PublicKey::new_from_private_key(&key)); - let initial_data = [(address, 100)]; + let account_id = AccountId::from(&PublicKey::new_from_private_key(&key)); + let initial_data = [(account_id, 100)]; let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]); - let from = address; - let to = Address::new([2; 32]); - assert_eq!(state.get_account_by_address(&to), Account::default()); + let from = account_id; + let to = AccountId::new([2; 32]); + assert_eq!(state.get_account_by_id(&to), Account::default()); let balance_to_move = 5; let tx = transfer_transaction(from, key, 0, to, balance_to_move); state.transition_from_public_transaction(&tx).unwrap(); - assert_eq!(state.get_account_by_address(&from).balance, 95); - assert_eq!(state.get_account_by_address(&to).balance, 5); - assert_eq!(state.get_account_by_address(&from).nonce, 1); - assert_eq!(state.get_account_by_address(&to).nonce, 0); + assert_eq!(state.get_account_by_id(&from).balance, 95); + assert_eq!(state.get_account_by_id(&to).balance, 5); + assert_eq!(state.get_account_by_id(&from).nonce, 1); + assert_eq!(state.get_account_by_id(&to).nonce, 0); } #[test] fn transition_from_authenticated_transfer_program_invocation_insuficient_balance() { let key = PrivateKey::try_new([1; 32]).unwrap(); - let address = Address::from(&PublicKey::new_from_private_key(&key)); - let initial_data = [(address, 100)]; + let account_id = AccountId::from(&PublicKey::new_from_private_key(&key)); + let initial_data = [(account_id, 100)]; let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]); - let from = address; + let from = account_id; let from_key = key; - let to = Address::new([2; 32]); + let to = AccountId::new([2; 32]); let balance_to_move = 101; - assert!(state.get_account_by_address(&from).balance < balance_to_move); + assert!(state.get_account_by_id(&from).balance < balance_to_move); let tx = transfer_transaction(from, from_key, 0, to, balance_to_move); let result = state.transition_from_public_transaction(&tx); assert!(matches!(result, Err(NssaError::ProgramExecutionFailed(_)))); - assert_eq!(state.get_account_by_address(&from).balance, 100); - assert_eq!(state.get_account_by_address(&to).balance, 0); - assert_eq!(state.get_account_by_address(&from).nonce, 0); - assert_eq!(state.get_account_by_address(&to).nonce, 0); + assert_eq!(state.get_account_by_id(&from).balance, 100); + assert_eq!(state.get_account_by_id(&to).balance, 0); + assert_eq!(state.get_account_by_id(&from).nonce, 0); + assert_eq!(state.get_account_by_id(&to).nonce, 0); } #[test] fn transition_from_authenticated_transfer_program_invocation_non_default_account_destination() { let key1 = PrivateKey::try_new([1; 32]).unwrap(); let key2 = PrivateKey::try_new([2; 32]).unwrap(); - let address1 = Address::from(&PublicKey::new_from_private_key(&key1)); - let address2 = Address::from(&PublicKey::new_from_private_key(&key2)); - let initial_data = [(address1, 100), (address2, 200)]; + let account_id1 = AccountId::from(&PublicKey::new_from_private_key(&key1)); + let account_id2 = AccountId::from(&PublicKey::new_from_private_key(&key2)); + let initial_data = [(account_id1, 100), (account_id2, 200)]; let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]); - let from = address2; + let from = account_id2; let from_key = key2; - let to = address1; - assert_ne!(state.get_account_by_address(&to), Account::default()); + let to = account_id1; + assert_ne!(state.get_account_by_id(&to), Account::default()); let balance_to_move = 8; let tx = transfer_transaction(from, from_key, 0, to, balance_to_move); state.transition_from_public_transaction(&tx).unwrap(); - assert_eq!(state.get_account_by_address(&from).balance, 192); - assert_eq!(state.get_account_by_address(&to).balance, 108); - assert_eq!(state.get_account_by_address(&from).nonce, 1); - assert_eq!(state.get_account_by_address(&to).nonce, 0); + assert_eq!(state.get_account_by_id(&from).balance, 192); + assert_eq!(state.get_account_by_id(&to).balance, 108); + assert_eq!(state.get_account_by_id(&from).nonce, 1); + assert_eq!(state.get_account_by_id(&to).nonce, 0); } #[test] fn transition_from_sequence_of_authenticated_transfer_program_invocations() { let key1 = PrivateKey::try_new([8; 32]).unwrap(); - let address1 = Address::from(&PublicKey::new_from_private_key(&key1)); + let account_id1 = AccountId::from(&PublicKey::new_from_private_key(&key1)); let key2 = PrivateKey::try_new([2; 32]).unwrap(); - let address2 = Address::from(&PublicKey::new_from_private_key(&key2)); - let initial_data = [(address1, 100)]; + let account_id2 = AccountId::from(&PublicKey::new_from_private_key(&key2)); + let initial_data = [(account_id1, 100)]; let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]); - let address3 = Address::new([3; 32]); + let account_id3 = AccountId::new([3; 32]); let balance_to_move = 5; - let tx = transfer_transaction(address1, key1, 0, address2, balance_to_move); + let tx = transfer_transaction(account_id1, key1, 0, account_id2, balance_to_move); state.transition_from_public_transaction(&tx).unwrap(); let balance_to_move = 3; - let tx = transfer_transaction(address2, key2, 0, address3, balance_to_move); + let tx = transfer_transaction(account_id2, key2, 0, account_id3, balance_to_move); state.transition_from_public_transaction(&tx).unwrap(); - assert_eq!(state.get_account_by_address(&address1).balance, 95); - assert_eq!(state.get_account_by_address(&address2).balance, 2); - assert_eq!(state.get_account_by_address(&address3).balance, 3); - assert_eq!(state.get_account_by_address(&address1).nonce, 1); - assert_eq!(state.get_account_by_address(&address2).nonce, 1); - assert_eq!(state.get_account_by_address(&address3).nonce, 0); + assert_eq!(state.get_account_by_id(&account_id1).balance, 95); + assert_eq!(state.get_account_by_id(&account_id2).balance, 2); + assert_eq!(state.get_account_by_id(&account_id3).balance, 3); + assert_eq!(state.get_account_by_id(&account_id1).nonce, 1); + assert_eq!(state.get_account_by_id(&account_id2).nonce, 1); + assert_eq!(state.get_account_by_id(&account_id3).nonce, 0); } impl V02State { - pub fn force_insert_account(&mut self, address: Address, account: Account) { - self.public_state.insert(address, account); + pub fn force_insert_account(&mut self, account_id: AccountId, account: Account) { + self.public_state.insert(account_id, account); } /// Include test programs in the builtin programs map @@ -488,15 +494,15 @@ pub mod tests { ..Account::default() }; self.force_insert_account( - Address::new([255; 32]), + AccountId::new([255; 32]), account_with_default_values_except_balance, ); self.force_insert_account( - Address::new([254; 32]), + AccountId::new([254; 32]), account_with_default_values_except_nonce, ); self.force_insert_account( - Address::new([253; 32]), + AccountId::new([253; 32]), account_with_default_values_except_data, ); self @@ -508,7 +514,7 @@ pub mod tests { balance: 100, ..Default::default() }; - self.force_insert_account(Address::new([252; 32]), account); + self.force_insert_account(AccountId::new([252; 32]), account); self } @@ -521,13 +527,13 @@ pub mod tests { #[test] fn test_program_should_fail_if_modifies_nonces() { - let initial_data = [(Address::new([1; 32]), 100)]; + let initial_data = [(AccountId::new([1; 32]), 100)]; let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); - let addresses = vec![Address::new([1; 32])]; + let account_ids = vec![AccountId::new([1; 32])]; let program_id = Program::nonce_changer_program().id(); let message = - public_transaction::Message::try_new(program_id, addresses, vec![], ()).unwrap(); + public_transaction::Message::try_new(program_id, account_ids, vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -538,13 +544,13 @@ pub mod tests { #[test] fn test_program_should_fail_if_output_accounts_exceed_inputs() { - let initial_data = [(Address::new([1; 32]), 100)]; + let initial_data = [(AccountId::new([1; 32]), 100)]; let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); - let addresses = vec![Address::new([1; 32])]; + let account_ids = vec![AccountId::new([1; 32])]; let program_id = Program::extra_output_program().id(); let message = - public_transaction::Message::try_new(program_id, addresses, vec![], ()).unwrap(); + public_transaction::Message::try_new(program_id, account_ids, vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -555,13 +561,13 @@ pub mod tests { #[test] fn test_program_should_fail_with_missing_output_accounts() { - let initial_data = [(Address::new([1; 32]), 100)]; + let initial_data = [(AccountId::new([1; 32]), 100)]; let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); - let addresses = vec![Address::new([1; 32]), Address::new([2; 32])]; + let account_ids = vec![AccountId::new([1; 32]), AccountId::new([2; 32])]; let program_id = Program::missing_output_program().id(); let message = - public_transaction::Message::try_new(program_id, addresses, vec![], ()).unwrap(); + public_transaction::Message::try_new(program_id, account_ids, vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -572,19 +578,20 @@ pub mod tests { #[test] fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_program_owner() { - let initial_data = [(Address::new([1; 32]), 0)]; + let initial_data = [(AccountId::new([1; 32]), 0)]; let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); - let address = Address::new([1; 32]); - let account = state.get_account_by_address(&address); - // Assert the target account only differs from the default account in the program owner field + let account_id = AccountId::new([1; 32]); + let account = state.get_account_by_id(&account_id); + // Assert the target account only differs from the default account in the program owner + // field assert_ne!(account.program_owner, Account::default().program_owner); assert_eq!(account.balance, Account::default().balance); assert_eq!(account.nonce, Account::default().nonce); assert_eq!(account.data, Account::default().data); let program_id = Program::program_owner_changer().id(); let message = - public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap(); + public_transaction::Message::try_new(program_id, vec![account_id], vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -599,8 +606,8 @@ pub mod tests { let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]) .with_test_programs() .with_non_default_accounts_but_default_program_owners(); - let address = Address::new([255; 32]); - let account = state.get_account_by_address(&address); + let account_id = AccountId::new([255; 32]); + let account = state.get_account_by_id(&account_id); // Assert the target account only differs from the default account in balance field assert_eq!(account.program_owner, Account::default().program_owner); assert_ne!(account.balance, Account::default().balance); @@ -608,7 +615,7 @@ pub mod tests { assert_eq!(account.data, Account::default().data); let program_id = Program::program_owner_changer().id(); let message = - public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap(); + public_transaction::Message::try_new(program_id, vec![account_id], vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -623,8 +630,8 @@ pub mod tests { let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]) .with_test_programs() .with_non_default_accounts_but_default_program_owners(); - let address = Address::new([254; 32]); - let account = state.get_account_by_address(&address); + let account_id = AccountId::new([254; 32]); + let account = state.get_account_by_id(&account_id); // Assert the target account only differs from the default account in nonce field assert_eq!(account.program_owner, Account::default().program_owner); assert_eq!(account.balance, Account::default().balance); @@ -632,7 +639,7 @@ pub mod tests { assert_eq!(account.data, Account::default().data); let program_id = Program::program_owner_changer().id(); let message = - public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap(); + public_transaction::Message::try_new(program_id, vec![account_id], vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -647,8 +654,8 @@ pub mod tests { let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]) .with_test_programs() .with_non_default_accounts_but_default_program_owners(); - let address = Address::new([253; 32]); - let account = state.get_account_by_address(&address); + let account_id = AccountId::new([253; 32]); + let account = state.get_account_by_id(&account_id); // Assert the target account only differs from the default account in data field assert_eq!(account.program_owner, Account::default().program_owner); assert_eq!(account.balance, Account::default().balance); @@ -656,7 +663,7 @@ pub mod tests { assert_ne!(account.data, Account::default().data); let program_id = Program::program_owner_changer().id(); let message = - public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap(); + public_transaction::Message::try_new(program_id, vec![account_id], vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -667,20 +674,20 @@ pub mod tests { #[test] fn test_program_should_fail_if_transfers_balance_from_non_owned_account() { - let initial_data = [(Address::new([1; 32]), 100)]; + let initial_data = [(AccountId::new([1; 32]), 100)]; let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); - let sender_address = Address::new([1; 32]); - let receiver_address = Address::new([2; 32]); + let sender_account_id = AccountId::new([1; 32]); + let receiver_account_id = AccountId::new([2; 32]); let balance_to_move: u128 = 1; let program_id = Program::simple_balance_transfer().id(); assert_ne!( - state.get_account_by_address(&sender_address).program_owner, + state.get_account_by_id(&sender_account_id).program_owner, program_id ); let message = public_transaction::Message::try_new( program_id, - vec![sender_address, receiver_address], + vec![sender_account_id, receiver_account_id], vec![], balance_to_move, ) @@ -699,16 +706,16 @@ pub mod tests { let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]) .with_test_programs() .with_non_default_accounts_but_default_program_owners(); - let address = Address::new([255; 32]); + let account_id = AccountId::new([255; 32]); let program_id = Program::data_changer().id(); - assert_ne!(state.get_account_by_address(&address), Account::default()); + assert_ne!(state.get_account_by_id(&account_id), Account::default()); assert_ne!( - state.get_account_by_address(&address).program_owner, + state.get_account_by_id(&account_id).program_owner, program_id ); let message = - public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap(); + public_transaction::Message::try_new(program_id, vec![account_id], vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -722,11 +729,11 @@ pub mod tests { let initial_data = []; let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); - let address = Address::new([1; 32]); + let account_id = AccountId::new([1; 32]); let program_id = Program::minter().id(); let message = - public_transaction::Message::try_new(program_id, vec![address], vec![], ()).unwrap(); + public_transaction::Message::try_new(program_id, vec![account_id], vec![], ()).unwrap(); let witness_set = public_transaction::WitnessSet::for_message(&message, &[]); let tx = PublicTransaction::new(message, witness_set); @@ -742,17 +749,17 @@ pub mod tests { .with_test_programs() .with_account_owned_by_burner_program(); let program_id = Program::burner().id(); - let address = Address::new([252; 32]); + let account_id = AccountId::new([252; 32]); assert_eq!( - state.get_account_by_address(&address).program_owner, + state.get_account_by_id(&account_id).program_owner, program_id ); let balance_to_burn: u128 = 1; - assert!(state.get_account_by_address(&address).balance > balance_to_burn); + assert!(state.get_account_by_id(&account_id).balance > balance_to_burn); let message = public_transaction::Message::try_new( program_id, - vec![address], + vec![account_id], vec![], balance_to_burn, ) @@ -769,8 +776,8 @@ pub mod tests { } impl TestPublicKeys { - pub fn address(&self) -> Address { - Address::from(&PublicKey::new_from_private_key(&self.signing_key)) + pub fn account_id(&self) -> AccountId { + AccountId::from(&PublicKey::new_from_private_key(&self.signing_key)) } } @@ -816,9 +823,9 @@ pub mod tests { state: &V02State, ) -> PrivacyPreservingTransaction { let sender = AccountWithMetadata::new( - state.get_account_by_address(&sender_keys.address()), + state.get_account_by_id(&sender_keys.account_id()), true, - sender_keys.address(), + sender_keys.account_id(), ); let sender_nonce = sender.account.nonce; @@ -841,7 +848,7 @@ pub mod tests { .unwrap(); let message = Message::try_from_circuit_output( - vec![sender_keys.address()], + vec![sender_keys.account_id()], vec![sender_nonce], vec![(recipient_keys.npk(), recipient_keys.ivk(), epk)], output, @@ -911,7 +918,7 @@ pub mod tests { fn deshielded_balance_transfer_for_tests( sender_keys: &TestPrivateKeys, sender_private_account: &Account, - recipient_address: &Address, + recipient_account_id: &AccountId, balance_to_move: u128, new_nonce: Nonce, state: &V02State, @@ -921,9 +928,9 @@ pub mod tests { let sender_pre = AccountWithMetadata::new(sender_private_account.clone(), true, &sender_keys.npk()); let recipient_pre = AccountWithMetadata::new( - state.get_account_by_address(recipient_address), + state.get_account_by_id(recipient_account_id), false, - *recipient_address, + *recipient_account_id, ); let esk = [3; 32]; @@ -945,7 +952,7 @@ pub mod tests { .unwrap(); let message = Message::try_from_circuit_output( - vec![*recipient_address], + vec![*recipient_account_id], vec![], vec![(sender_keys.npk(), sender_keys.ivk(), epk)], output, @@ -962,7 +969,8 @@ pub mod tests { let sender_keys = test_public_account_keys_1(); let recipient_keys = test_private_account_keys_1(); - let mut state = V02State::new_with_genesis_accounts(&[(sender_keys.address(), 200)], &[]); + let mut state = + V02State::new_with_genesis_accounts(&[(sender_keys.account_id(), 200)], &[]); let balance_to_move = 37; @@ -974,7 +982,7 @@ pub mod tests { ); let expected_sender_post = { - let mut this = state.get_account_by_address(&sender_keys.address()); + let mut this = state.get_account_by_id(&sender_keys.account_id()); this.balance -= balance_to_move; this.nonce += 1; this @@ -987,12 +995,12 @@ pub mod tests { .transition_from_privacy_preserving_transaction(&tx) .unwrap(); - let sender_post = state.get_account_by_address(&sender_keys.address()); + let sender_post = state.get_account_by_id(&sender_keys.account_id()); assert_eq!(sender_post, expected_sender_post); assert!(state.private_state.0.contains(&expected_new_commitment)); assert_eq!( - state.get_account_by_address(&sender_keys.address()).balance, + state.get_account_by_id(&sender_keys.account_id()).balance, 200 - balance_to_move ); } @@ -1075,7 +1083,7 @@ pub mod tests { let recipient_keys = test_public_account_keys_1(); let recipient_initial_balance = 400; let mut state = V02State::new_with_genesis_accounts( - &[(recipient_keys.address(), recipient_initial_balance)], + &[(recipient_keys.account_id(), recipient_initial_balance)], &[], ) .with_private_account(&sender_keys, &sender_private_account); @@ -1083,7 +1091,7 @@ pub mod tests { let balance_to_move = 37; let expected_recipient_post = { - let mut this = state.get_account_by_address(&recipient_keys.address()); + let mut this = state.get_account_by_id(&recipient_keys.account_id()); this.balance += balance_to_move; this }; @@ -1091,7 +1099,7 @@ pub mod tests { let tx = deshielded_balance_transfer_for_tests( &sender_keys, &sender_private_account, - &recipient_keys.address(), + &recipient_keys.account_id(), balance_to_move, 0xcafecafe, &state, @@ -1119,14 +1127,14 @@ pub mod tests { .transition_from_privacy_preserving_transaction(&tx) .unwrap(); - let recipient_post = state.get_account_by_address(&recipient_keys.address()); + let recipient_post = state.get_account_by_id(&recipient_keys.account_id()); assert_eq!(recipient_post, expected_recipient_post); assert!(state.private_state.0.contains(&sender_pre_commitment)); assert!(state.private_state.0.contains(&expected_new_commitment)); assert!(state.private_state.1.contains(&expected_new_nullifier)); assert_eq!( state - .get_account_by_address(&recipient_keys.address()) + .get_account_by_id(&recipient_keys.account_id()) .balance, recipient_initial_balance + balance_to_move ); @@ -2046,18 +2054,18 @@ pub mod tests { fn test_claiming_mechanism() { let program = Program::authenticated_transfer_program(); let key = PrivateKey::try_new([1; 32]).unwrap(); - let address = Address::from(&PublicKey::new_from_private_key(&key)); + let account_id = AccountId::from(&PublicKey::new_from_private_key(&key)); let initial_balance = 100; - let initial_data = [(address, initial_balance)]; + let initial_data = [(account_id, initial_balance)]; let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); - let from = address; + let from = account_id; let from_key = key; - let to = Address::new([2; 32]); + let to = AccountId::new([2; 32]); let amount: u128 = 37; // Check the recipient is an uninitialized account - assert_eq!(state.get_account_by_address(&to), Account::default()); + assert_eq!(state.get_account_by_id(&to), Account::default()); let expected_recipient_post = Account { program_owner: program.id(), @@ -2073,36 +2081,36 @@ pub mod tests { state.transition_from_public_transaction(&tx).unwrap(); - let recipient_post = state.get_account_by_address(&to); + let recipient_post = state.get_account_by_id(&to); assert_eq!(recipient_post, expected_recipient_post); } #[test] - fn test_chained_call() { + fn test_chained_call_succeeds() { let program = Program::chain_caller(); let key = PrivateKey::try_new([1; 32]).unwrap(); - let address = Address::from(&PublicKey::new_from_private_key(&key)); + let from = AccountId::from(&PublicKey::new_from_private_key(&key)); + let to = AccountId::new([2; 32]); let initial_balance = 100; - let initial_data = [(address, initial_balance)]; + let initial_data = [(from, initial_balance), (to, 0)]; let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); - let from = address; let from_key = key; - let to = Address::new([2; 32]); - let amount: u128 = 37; - let instruction: (u128, ProgramId) = - (amount, Program::authenticated_transfer_program().id()); + let amount: u128 = 0; + let instruction: (u128, ProgramId, u32) = + (amount, Program::authenticated_transfer_program().id(), 2); let expected_to_post = Account { - program_owner: Program::chain_caller().id(), - balance: amount, + program_owner: Program::authenticated_transfer_program().id(), + balance: amount * 2, // The `chain_caller` chains the program twice ..Account::default() }; let message = public_transaction::Message::try_new( program.id(), - vec![to, from], //The chain_caller program permutes the account order in the chain call + vec![to, from], // The chain_caller program permutes the account order in the chain + // call vec![0], instruction, ) @@ -2112,9 +2120,46 @@ pub mod tests { state.transition_from_public_transaction(&tx).unwrap(); - let from_post = state.get_account_by_address(&from); - let to_post = state.get_account_by_address(&to); - assert_eq!(from_post.balance, initial_balance - amount); + let from_post = state.get_account_by_id(&from); + let to_post = state.get_account_by_id(&to); + // The `chain_caller` program calls the program twice + assert_eq!(from_post.balance, initial_balance - 2 * amount); assert_eq!(to_post, expected_to_post); } + + #[test] + fn test_execution_fails_if_chained_calls_exceeds_depth() { + let program = Program::chain_caller(); + let key = PrivateKey::try_new([1; 32]).unwrap(); + let from = AccountId::from(&PublicKey::new_from_private_key(&key)); + let to = AccountId::new([2; 32]); + let initial_balance = 100; + let initial_data = [(from, initial_balance), (to, 0)]; + let mut state = + V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); + let from_key = key; + let amount: u128 = 0; + let instruction: (u128, ProgramId, u32) = ( + amount, + Program::authenticated_transfer_program().id(), + MAX_NUMBER_CHAINED_CALLS as u32 + 1, + ); + + let message = public_transaction::Message::try_new( + program.id(), + vec![to, from], // The chain_caller program permutes the account order in the chain + // call + vec![0], + instruction, + ) + .unwrap(); + let witness_set = public_transaction::WitnessSet::for_message(&message, &[&from_key]); + let tx = PublicTransaction::new(message, witness_set); + + let result = state.transition_from_public_transaction(&tx); + assert!(matches!( + result, + Err(NssaError::MaxChainedCallsDepthExceeded) + )); + } } diff --git a/nssa/test_program_methods/guest/Cargo.lock b/nssa/test_program_methods/guest/Cargo.lock index d7e5b67..85f566c 100644 --- a/nssa/test_program_methods/guest/Cargo.lock +++ b/nssa/test_program_methods/guest/Cargo.lock @@ -1579,6 +1579,7 @@ checksum = "a5b0c77c1b780822bc749a33e39aeb2c07584ab93332303babeabb645298a76e" name = "nssa-core" version = "0.1.0" dependencies = [ + "borsh", "chacha20", "risc0-zkvm", "serde", diff --git a/nssa/test_program_methods/guest/src/bin/chain_caller.rs b/nssa/test_program_methods/guest/src/bin/chain_caller.rs index dfd77b1..028f8a0 100644 --- a/nssa/test_program_methods/guest/src/bin/chain_caller.rs +++ b/nssa/test_program_methods/guest/src/bin/chain_caller.rs @@ -3,14 +3,14 @@ use nssa_core::program::{ }; use risc0_zkvm::serde::to_vec; -type Instruction = (u128, ProgramId); +type Instruction = (u128, ProgramId, u32); -/// A program that calls another program. +/// A program that calls another program `num_chain_calls` times. /// It permutes the order of the input accounts on the subsequent call fn main() { let ProgramInput { pre_states, - instruction: (balance, program_id), + instruction: (balance, program_id, num_chain_calls), } = read_nssa_inputs::(); let [sender_pre, receiver_pre] = match pre_states.try_into() { @@ -20,10 +20,19 @@ fn main() { let instruction_data = to_vec(&balance).unwrap(); - let chained_call = Some(ChainedCall { + let mut chained_call = vec![ + ChainedCall { + program_id, + instruction_data: instruction_data.clone(), + pre_states: vec![receiver_pre.clone(), sender_pre.clone()], // <- Account order permutation here + }; + num_chain_calls as usize - 1 + ]; + + chained_call.push(ChainedCall { program_id, instruction_data, - account_indices: vec![1, 0], // <- Account order permutation here + pre_states: vec![receiver_pre.clone(), sender_pre.clone()], // <- Account order permutation here }); write_nssa_outputs_with_chained_call( diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 5d56faf..3ec291c 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,3 @@ [toolchain] -channel = "nightly" +channel = "1.91.1" +profile = "default" diff --git a/rustfmt.toml b/rustfmt.toml index f216078..369ddfb 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1 +1,12 @@ edition = "2024" + +newline_style = "Unix" +use_field_init_shorthand = true +use_try_shorthand = true +group_imports = "StdExternalCrate" +imports_granularity = "Crate" +normalize_comments = true +reorder_impl_items = true +wrap_comments = true +comment_width = 100 +format_code_in_doc_comments = true diff --git a/sequencer_core/Cargo.toml b/sequencer_core/Cargo.toml index 6e9979c..32c263c 100644 --- a/sequencer_core/Cargo.toml +++ b/sequencer_core/Cargo.toml @@ -28,3 +28,7 @@ path = "../nssa" [features] default = [] testnet = [] + +[dev-dependencies] +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } +futures.workspace = true diff --git a/sequencer_core/src/block_store.rs b/sequencer_core/src/block_store.rs index 6fd9fb7..6753502 100644 --- a/sequencer_core/src/block_store.rs +++ b/sequencer_core/src/block_store.rs @@ -4,16 +4,16 @@ use anyhow::Result; use common::{HashType, block::Block, transaction::EncodedTransaction}; use storage::RocksDBIO; -pub struct SequecerBlockStore { +pub struct SequencerBlockStore { dbio: RocksDBIO, // TODO: Consider adding the hashmap to the database for faster recovery. - pub tx_hash_to_block_map: HashMap, - pub genesis_id: u64, - pub signing_key: nssa::PrivateKey, + tx_hash_to_block_map: HashMap, + genesis_id: u64, + signing_key: nssa::PrivateKey, } -impl SequecerBlockStore { - ///Starting database at the start of new chain. +impl SequencerBlockStore { + /// Starting database at the start of new chain. /// Creates files if necessary. /// /// ATTENTION: Will overwrite genesis block. @@ -40,9 +40,9 @@ impl SequecerBlockStore { }) } - ///Reopening existing database + /// Reopening existing database pub fn open_db_restart(location: &Path, signing_key: nssa::PrivateKey) -> Result { - SequecerBlockStore::open_db_with_genesis(location, None, signing_key) + SequencerBlockStore::open_db_with_genesis(location, None, signing_key) } pub fn get_block_at_id(&self, id: u64) -> Result { @@ -69,6 +69,18 @@ impl SequecerBlockStore { } None } + + pub fn insert(&mut self, tx: &EncodedTransaction, block_id: u64) { + self.tx_hash_to_block_map.insert(tx.hash(), block_id); + } + + pub fn genesis_id(&self) -> u64 { + self.genesis_id + } + + pub fn signing_key(&self) -> &nssa::PrivateKey { + &self.signing_key + } } pub(crate) fn block_to_transactions_map(block: &Block) -> HashMap { @@ -82,11 +94,11 @@ pub(crate) fn block_to_transactions_map(block: &Block) -> HashMap #[cfg(test)] mod tests { - use super::*; - use common::{block::HashableBlockData, test_utils::sequencer_sign_key_for_testing}; use tempfile::tempdir; + use super::*; + #[test] fn test_get_transaction_by_hash() { let temp_dir = tempdir().unwrap(); @@ -104,7 +116,7 @@ mod tests { let genesis_block = genesis_block_hashable_data.into_block(&signing_key); // Start an empty node store let mut node_store = - SequecerBlockStore::open_db_with_genesis(path, Some(genesis_block), signing_key) + SequencerBlockStore::open_db_with_genesis(path, Some(genesis_block), signing_key) .unwrap(); let tx = common::test_utils::produce_dummy_empty_transaction(); diff --git a/sequencer_core/src/config.rs b/sequencer_core/src/config.rs index a86bcb3..2f4ee3b 100644 --- a/sequencer_core/src/config.rs +++ b/sequencer_core/src/config.rs @@ -1,43 +1,45 @@ -use serde::{Deserialize, Serialize}; use std::path::PathBuf; +use serde::{Deserialize, Serialize}; + #[derive(Debug, Serialize, Deserialize, Clone)] -///Helperstruct for account serialization +/// Helperstruct for account serialization pub struct AccountInitialData { - ///Hex encoded `AccountAddress` - pub addr: String, + /// Hex encoded account id + pub account_id: String, pub balance: u128, } #[derive(Debug, Serialize, Deserialize, Clone)] -///Helperstruct to initialize commitments +/// Helperstruct to initialize commitments pub struct CommitmentsInitialData { pub npk: nssa_core::NullifierPublicKey, pub account: nssa_core::account::Account, } +// TODO: Provide default values #[derive(Clone, Serialize, Deserialize)] pub struct SequencerConfig { - ///Home dir of sequencer storage + /// Home dir of sequencer storage pub home: PathBuf, - ///Override rust log (env var logging level) + /// Override rust log (env var logging level) pub override_rust_log: Option, - ///Genesis id + /// Genesis id pub genesis_id: u64, - ///If `True`, then adds random sequence of bytes to genesis block + /// If `True`, then adds random sequence of bytes to genesis block pub is_genesis_random: bool, - ///Maximum number of transactions in block + /// Maximum number of transactions in block pub max_num_tx_in_block: usize, - ///Mempool maximum size + /// Mempool maximum size pub mempool_max_size: usize, - ///Interval in which blocks produced + /// Interval in which blocks produced pub block_create_timeout_millis: u64, - ///Port to listen + /// Port to listen pub port: u16, - ///List of initial accounts data + /// List of initial accounts data pub initial_accounts: Vec, - ///List of initial commitments + /// List of initial commitments pub initial_commitments: Vec, - ///Sequencer own signing key + /// Sequencer own signing key pub signing_key: [u8; 32], } diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 479a830..8e193ff 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -10,25 +10,24 @@ use common::{ }; use config::SequencerConfig; use log::warn; -use mempool::MemPool; +use mempool::{MemPool, MemPoolHandle}; use serde::{Deserialize, Serialize}; -use crate::block_store::SequecerBlockStore; +use crate::block_store::SequencerBlockStore; pub mod block_store; pub mod config; pub struct SequencerCore { - pub state: nssa::V02State, - pub block_store: SequecerBlockStore, - pub mempool: MemPool, - pub sequencer_config: SequencerConfig, - pub chain_height: u64, + state: nssa::V02State, + block_store: SequencerBlockStore, + mempool: MemPool, + sequencer_config: SequencerConfig, + chain_height: u64, } #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub enum TransactionMalformationError { - MempoolFullForRound, InvalidSignature, FailedToDecode { tx: HashType }, } @@ -42,7 +41,8 @@ impl Display for TransactionMalformationError { impl std::error::Error for TransactionMalformationError {} impl SequencerCore { - pub fn start_from_config(config: SequencerConfig) -> Self { + /// Start Sequencer from configuration and construct transaction sender + pub fn start_from_config(config: SequencerConfig) -> (Self, MemPoolHandle) { let hashable_data = HashableBlockData { block_id: config.genesis_id, transactions: vec![], @@ -53,9 +53,9 @@ impl SequencerCore { let signing_key = nssa::PrivateKey::try_new(config.signing_key).unwrap(); let genesis_block = hashable_data.into_block(&signing_key); - //Sequencer should panic if unable to open db, - //as fixing this issue may require actions non-native to program scope - let block_store = SequecerBlockStore::open_db_with_genesis( + // Sequencer should panic if unable to open db, + // as fixing this issue may require actions non-native to program scope + let block_store = SequencerBlockStore::open_db_with_genesis( &config.home.join("rocksdb"), Some(genesis_block), signing_key, @@ -75,10 +75,10 @@ impl SequencerCore { initial_commitments.push(comm); } - let init_accs: Vec<(nssa::Address, u128)> = config + let init_accs: Vec<(nssa::AccountId, u128)> = config .initial_accounts .iter() - .map(|acc_data| (acc_data.addr.parse().unwrap(), acc_data.balance)) + .map(|acc_data| (acc_data.account_id.parse().unwrap(), acc_data.balance)) .collect(); let mut state = nssa::V02State::new_with_genesis_accounts(&init_accs, &initial_commitments); @@ -86,21 +86,23 @@ impl SequencerCore { #[cfg(feature = "testnet")] state.add_pinata_program(PINATA_BASE58.parse().unwrap()); + let (mempool, mempool_handle) = MemPool::new(config.mempool_max_size); let mut this = Self { state, block_store, - mempool: MemPool::default(), + mempool, chain_height: config.genesis_id, sequencer_config: config, }; this.sync_state_with_stored_blocks(); - this + (this, mempool_handle) } - /// If there are stored blocks ahead of the current height, this method will load and process all transaction - /// in them in the order they are stored. The NSSA state will be updated accordingly. + /// If there are stored blocks ahead of the current height, this method will load and process + /// all transaction in them in the order they are stored. The NSSA state will be updated + /// accordingly. fn sync_state_with_stored_blocks(&mut self) { let mut next_block_id = self.sequencer_config.genesis_id + 1; while let Ok(block) = self.block_store.get_block_at_id(next_block_id) { @@ -110,108 +112,50 @@ impl SequencerCore { self.execute_check_transaction_on_state(transaction) .unwrap(); // Update the tx hash to block id map. - self.block_store - .tx_hash_to_block_map - .insert(encoded_transaction.hash(), next_block_id); + self.block_store.insert(&encoded_transaction, next_block_id); } self.chain_height = next_block_id; next_block_id += 1; } } - pub fn transaction_pre_check( - &mut self, - tx: NSSATransaction, - ) -> Result { - // Stateless checks here - match tx { - NSSATransaction::Public(tx) => { - if tx.witness_set().is_valid_for(tx.message()) { - Ok(NSSATransaction::Public(tx)) - } else { - Err(TransactionMalformationError::InvalidSignature) - } - } - NSSATransaction::PrivacyPreserving(tx) => { - if tx.witness_set().signatures_are_valid_for(tx.message()) { - Ok(NSSATransaction::PrivacyPreserving(tx)) - } else { - Err(TransactionMalformationError::InvalidSignature) - } - } - NSSATransaction::ProgramDeployment(tx) => Ok(NSSATransaction::ProgramDeployment(tx)), - } - } - - pub fn push_tx_into_mempool_pre_check( - &mut self, - transaction: EncodedTransaction, - ) -> Result<(), TransactionMalformationError> { - let transaction = NSSATransaction::try_from(&transaction).map_err(|_| { - TransactionMalformationError::FailedToDecode { - tx: transaction.hash(), - } - })?; - - let mempool_size = self.mempool.len(); - if mempool_size >= self.sequencer_config.mempool_max_size { - return Err(TransactionMalformationError::MempoolFullForRound); - } - - let authenticated_tx = self - .transaction_pre_check(transaction) - .inspect_err(|err| warn!("Error at pre_check {err:#?}"))?; - - self.mempool.push_item(authenticated_tx.into()); - - Ok(()) - } - fn execute_check_transaction_on_state( &mut self, tx: NSSATransaction, ) -> Result { match &tx { - NSSATransaction::Public(tx) => { - self.state - .transition_from_public_transaction(tx) - .inspect_err(|err| warn!("Error at transition {err:#?}"))?; - } - NSSATransaction::PrivacyPreserving(tx) => { - self.state - .transition_from_privacy_preserving_transaction(tx) - .inspect_err(|err| warn!("Error at transition {err:#?}"))?; - } - NSSATransaction::ProgramDeployment(tx) => { - self.state - .transition_from_program_deployment_transaction(tx) - .inspect_err(|err| warn!("Error at transition {err:#?}"))?; - } + NSSATransaction::Public(tx) => self.state.transition_from_public_transaction(tx), + NSSATransaction::PrivacyPreserving(tx) => self + .state + .transition_from_privacy_preserving_transaction(tx), + NSSATransaction::ProgramDeployment(tx) => self + .state + .transition_from_program_deployment_transaction(tx), } + .inspect_err(|err| warn!("Error at transition {err:#?}"))?; Ok(tx) } - ///Produces new block from transactions in mempool + /// Produces new block from transactions in mempool pub fn produce_new_block_with_mempool_transactions(&mut self) -> Result { let now = Instant::now(); let new_block_height = self.chain_height + 1; - let mut num_valid_transactions_in_block = 0; let mut valid_transactions = vec![]; - while let Some(tx) = self.mempool.pop_last() { + while let Some(tx) = self.mempool.pop() { let nssa_transaction = NSSATransaction::try_from(&tx) .map_err(|_| TransactionMalformationError::FailedToDecode { tx: tx.hash() })?; if let Ok(valid_tx) = self.execute_check_transaction_on_state(nssa_transaction) { valid_transactions.push(valid_tx.into()); - num_valid_transactions_in_block += 1; - - if num_valid_transactions_in_block >= self.sequencer_config.max_num_tx_in_block { + if valid_transactions.len() >= self.sequencer_config.max_num_tx_in_block { break; } + } else { + // Probably need to handle unsuccessful transaction execution? } } @@ -232,12 +176,22 @@ impl SequencerCore { timestamp: curr_time, }; - let block = hashable_data.into_block(&self.block_store.signing_key); + let block = hashable_data.into_block(self.block_store.signing_key()); self.block_store.put_block_at_id(block)?; self.chain_height = new_block_height; + // TODO: Consider switching to `tracing` crate to have more structured and consistent logs + // e.g. + // + // ``` + // info!( + // num_txs = num_txs_in_block, + // time = now.elapsed(), + // "Created block" + // ); + // ``` log::info!( "Created block with {} transactions in {} seconds", num_txs_in_block, @@ -246,17 +200,58 @@ impl SequencerCore { Ok(self.chain_height) } + + pub fn state(&self) -> &nssa::V02State { + &self.state + } + + pub fn block_store(&self) -> &SequencerBlockStore { + &self.block_store + } + + pub fn chain_height(&self) -> u64 { + self.chain_height + } + + pub fn sequencer_config(&self) -> &SequencerConfig { + &self.sequencer_config + } +} + +// TODO: Introduce type-safe wrapper around checked transaction, e.g. AuthenticatedTransaction +pub fn transaction_pre_check( + tx: NSSATransaction, +) -> Result { + // Stateless checks here + match tx { + NSSATransaction::Public(tx) => { + if tx.witness_set().is_valid_for(tx.message()) { + Ok(NSSATransaction::Public(tx)) + } else { + Err(TransactionMalformationError::InvalidSignature) + } + } + NSSATransaction::PrivacyPreserving(tx) => { + if tx.witness_set().signatures_are_valid_for(tx.message()) { + Ok(NSSATransaction::PrivacyPreserving(tx)) + } else { + Err(TransactionMalformationError::InvalidSignature) + } + } + NSSATransaction::ProgramDeployment(tx) => Ok(NSSATransaction::ProgramDeployment(tx)), + } } #[cfg(test)] mod tests { + use std::pin::pin; + use base58::{FromBase58, ToBase58}; use common::test_utils::sequencer_sign_key_for_testing; use nssa::PrivateKey; - use crate::config::AccountInitialData; - use super::*; + use crate::config::AccountInitialData; fn parse_unwrap_tx_body_into_nssa_tx(tx_body: EncodedTransaction) -> NSSATransaction { NSSATransaction::try_from(&tx_body) @@ -286,23 +281,23 @@ mod tests { } fn setup_sequencer_config() -> SequencerConfig { - let acc1_addr: Vec = vec![ + let acc1_account_id: Vec = vec![ 208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9, 115, 84, 126, 106, 16, 111, 114, 241, 147, 194, 220, 131, 139, 68, ]; - let acc2_addr: Vec = vec![ + let acc2_account_id: Vec = vec![ 231, 174, 119, 197, 239, 26, 5, 153, 147, 68, 175, 73, 159, 199, 138, 23, 5, 57, 141, 98, 237, 6, 207, 46, 20, 121, 246, 222, 248, 154, 57, 188, ]; let initial_acc1 = AccountInitialData { - addr: acc1_addr.to_base58(), + account_id: acc1_account_id.to_base58(), balance: 10000, }; let initial_acc2 = AccountInitialData { - addr: acc2_addr.to_base58(), + account_id: acc2_account_id.to_base58(), balance: 20000, }; @@ -319,33 +314,44 @@ mod tests { nssa::PrivateKey::try_new([2; 32]).unwrap() } - fn common_setup(sequencer: &mut SequencerCore) { + async fn common_setup() -> (SequencerCore, MemPoolHandle) { + let config = setup_sequencer_config(); + common_setup_with_config(config).await + } + + async fn common_setup_with_config( + config: SequencerConfig, + ) -> (SequencerCore, MemPoolHandle) { + let (mut sequencer, mempool_handle) = SequencerCore::start_from_config(config); + let tx = common::test_utils::produce_dummy_empty_transaction(); - sequencer.mempool.push_item(tx); + mempool_handle.push(tx).await.unwrap(); sequencer .produce_new_block_with_mempool_transactions() .unwrap(); + + (sequencer, mempool_handle) } #[test] fn test_start_from_config() { let config = setup_sequencer_config(); - let sequencer = SequencerCore::start_from_config(config.clone()); + let (sequencer, _mempool_handle) = SequencerCore::start_from_config(config.clone()); assert_eq!(sequencer.chain_height, config.genesis_id); assert_eq!(sequencer.sequencer_config.max_num_tx_in_block, 10); assert_eq!(sequencer.sequencer_config.port, 8080); - let acc1_addr = config.initial_accounts[0] - .addr + let acc1_account_id = config.initial_accounts[0] + .account_id .clone() .from_base58() .unwrap() .try_into() .unwrap(); - let acc2_addr = config.initial_accounts[1] - .addr + let acc2_account_id = config.initial_accounts[1] + .account_id .clone() .from_base58() .unwrap() @@ -354,11 +360,11 @@ mod tests { let balance_acc_1 = sequencer .state - .get_account_by_address(&nssa::Address::new(acc1_addr)) + .get_account_by_id(&nssa::AccountId::new(acc1_account_id)) .balance; let balance_acc_2 = sequencer .state - .get_account_by_address(&nssa::Address::new(acc2_addr)) + .get_account_by_id(&nssa::AccountId::new(acc2_account_id)) .balance; assert_eq!(10000, balance_acc_1); @@ -367,40 +373,40 @@ mod tests { #[test] fn test_start_different_intial_accounts_balances() { - let acc1_addr: Vec = vec![ + let acc1_account_id: Vec = vec![ 27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, 24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143, ]; - let acc2_addr: Vec = vec![ + let acc2_account_id: Vec = vec![ 77, 75, 108, 209, 54, 16, 50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217, 234, 216, 10, 201, 66, 51, 116, 196, 81, 167, 37, 77, 7, 102, ]; let initial_acc1 = AccountInitialData { - addr: acc1_addr.to_base58(), + account_id: acc1_account_id.to_base58(), balance: 10000, }; let initial_acc2 = AccountInitialData { - addr: acc2_addr.to_base58(), + account_id: acc2_account_id.to_base58(), balance: 20000, }; let initial_accounts = vec![initial_acc1, initial_acc2]; let config = setup_sequencer_config_variable_initial_accounts(initial_accounts); - let sequencer = SequencerCore::start_from_config(config.clone()); + let (sequencer, _mempool_handle) = SequencerCore::start_from_config(config.clone()); - let acc1_addr = config.initial_accounts[0] - .addr + let acc1_account_id = config.initial_accounts[0] + .account_id .clone() .from_base58() .unwrap() .try_into() .unwrap(); - let acc2_addr = config.initial_accounts[1] - .addr + let acc2_account_id = config.initial_accounts[1] + .account_id .clone() .from_base58() .unwrap() @@ -411,47 +417,39 @@ mod tests { 10000, sequencer .state - .get_account_by_address(&nssa::Address::new(acc1_addr)) + .get_account_by_id(&nssa::AccountId::new(acc1_account_id)) .balance ); assert_eq!( 20000, sequencer .state - .get_account_by_address(&nssa::Address::new(acc2_addr)) + .get_account_by_id(&nssa::AccountId::new(acc2_account_id)) .balance ); } #[test] fn test_transaction_pre_check_pass() { - let config = setup_sequencer_config(); - let mut sequencer = SequencerCore::start_from_config(config); - - common_setup(&mut sequencer); - let tx = common::test_utils::produce_dummy_empty_transaction(); - let result = sequencer.transaction_pre_check(parse_unwrap_tx_body_into_nssa_tx(tx)); + let result = transaction_pre_check(parse_unwrap_tx_body_into_nssa_tx(tx)); assert!(result.is_ok()); } - #[test] - fn test_transaction_pre_check_native_transfer_valid() { - let config = setup_sequencer_config(); - let mut sequencer = SequencerCore::start_from_config(config); - - common_setup(&mut sequencer); + #[tokio::test] + async fn test_transaction_pre_check_native_transfer_valid() { + let (sequencer, _mempool_handle) = common_setup().await; let acc1 = sequencer.sequencer_config.initial_accounts[0] - .addr + .account_id .clone() .from_base58() .unwrap() .try_into() .unwrap(); let acc2 = sequencer.sequencer_config.initial_accounts[1] - .addr + .account_id .clone() .from_base58() .unwrap() @@ -463,27 +461,24 @@ mod tests { let tx = common::test_utils::create_transaction_native_token_transfer( acc1, 0, acc2, 10, sign_key1, ); - let result = sequencer.transaction_pre_check(parse_unwrap_tx_body_into_nssa_tx(tx)); + let result = transaction_pre_check(parse_unwrap_tx_body_into_nssa_tx(tx)); assert!(result.is_ok()); } - #[test] - fn test_transaction_pre_check_native_transfer_other_signature() { - let config = setup_sequencer_config(); - let mut sequencer = SequencerCore::start_from_config(config); - - common_setup(&mut sequencer); + #[tokio::test] + async fn test_transaction_pre_check_native_transfer_other_signature() { + let (mut sequencer, _mempool_handle) = common_setup().await; let acc1 = sequencer.sequencer_config.initial_accounts[0] - .addr + .account_id .clone() .from_base58() .unwrap() .try_into() .unwrap(); let acc2 = sequencer.sequencer_config.initial_accounts[1] - .addr + .account_id .clone() .from_base58() .unwrap() @@ -497,9 +492,7 @@ mod tests { ); // Signature is valid, stateless check pass - let tx = sequencer - .transaction_pre_check(parse_unwrap_tx_body_into_nssa_tx(tx)) - .unwrap(); + let tx = transaction_pre_check(parse_unwrap_tx_body_into_nssa_tx(tx)).unwrap(); // Signature is not from sender. Execution fails let result = sequencer.execute_check_transaction_on_state(tx); @@ -510,22 +503,19 @@ mod tests { )); } - #[test] - fn test_transaction_pre_check_native_transfer_sent_too_much() { - let config = setup_sequencer_config(); - let mut sequencer = SequencerCore::start_from_config(config); - - common_setup(&mut sequencer); + #[tokio::test] + async fn test_transaction_pre_check_native_transfer_sent_too_much() { + let (mut sequencer, _mempool_handle) = common_setup().await; let acc1 = sequencer.sequencer_config.initial_accounts[0] - .addr + .account_id .clone() .from_base58() .unwrap() .try_into() .unwrap(); let acc2 = sequencer.sequencer_config.initial_accounts[1] - .addr + .account_id .clone() .from_base58() .unwrap() @@ -538,9 +528,9 @@ mod tests { acc1, 0, acc2, 10000000, sign_key1, ); - let result = sequencer.transaction_pre_check(parse_unwrap_tx_body_into_nssa_tx(tx)); + let result = transaction_pre_check(parse_unwrap_tx_body_into_nssa_tx(tx)); - //Passed pre-check + // Passed pre-check assert!(result.is_ok()); let result = sequencer.execute_check_transaction_on_state(result.unwrap()); @@ -552,22 +542,19 @@ mod tests { assert!(is_failed_at_balance_mismatch); } - #[test] - fn test_transaction_execute_native_transfer() { - let config = setup_sequencer_config(); - let mut sequencer = SequencerCore::start_from_config(config); - - common_setup(&mut sequencer); + #[tokio::test] + async fn test_transaction_execute_native_transfer() { + let (mut sequencer, _mempool_handle) = common_setup().await; let acc1 = sequencer.sequencer_config.initial_accounts[0] - .addr + .account_id .clone() .from_base58() .unwrap() .try_into() .unwrap(); let acc2 = sequencer.sequencer_config.initial_accounts[1] - .addr + .account_id .clone() .from_base58() .unwrap() @@ -586,84 +573,70 @@ mod tests { let bal_from = sequencer .state - .get_account_by_address(&nssa::Address::new(acc1)) + .get_account_by_id(&nssa::AccountId::new(acc1)) .balance; let bal_to = sequencer .state - .get_account_by_address(&nssa::Address::new(acc2)) + .get_account_by_id(&nssa::AccountId::new(acc2)) .balance; assert_eq!(bal_from, 9900); assert_eq!(bal_to, 20100); } - #[test] - fn test_push_tx_into_mempool_fails_mempool_full() { + #[tokio::test] + async fn test_push_tx_into_mempool_blocks_until_mempool_is_full() { let config = SequencerConfig { mempool_max_size: 1, ..setup_sequencer_config() }; - let mut sequencer = SequencerCore::start_from_config(config); - - common_setup(&mut sequencer); + let (mut sequencer, mempool_handle) = common_setup_with_config(config).await; let tx = common::test_utils::produce_dummy_empty_transaction(); // Fill the mempool - sequencer.mempool.push_item(tx.clone()); + mempool_handle.push(tx.clone()).await.unwrap(); - let result = sequencer.push_tx_into_mempool_pre_check(tx); + // Check that pushing another transaction will block + let mut push_fut = pin!(mempool_handle.push(tx.clone())); + let poll = futures::poll!(push_fut.as_mut()); + assert!(poll.is_pending()); - assert!(matches!( - result, - Err(TransactionMalformationError::MempoolFullForRound) - )); + // Empty the mempool by producing a block + sequencer + .produce_new_block_with_mempool_transactions() + .unwrap(); + + // Resolve the pending push + assert!(push_fut.await.is_ok()); } - #[test] - fn test_push_tx_into_mempool_pre_check() { - let config = setup_sequencer_config(); - let mut sequencer = SequencerCore::start_from_config(config); - - common_setup(&mut sequencer); - - let tx = common::test_utils::produce_dummy_empty_transaction(); - - let result = sequencer.push_tx_into_mempool_pre_check(tx); - assert!(result.is_ok()); - assert_eq!(sequencer.mempool.len(), 1); - } - - #[test] - fn test_produce_new_block_with_mempool_transactions() { - let config = setup_sequencer_config(); - let mut sequencer = SequencerCore::start_from_config(config); + #[tokio::test] + async fn test_produce_new_block_with_mempool_transactions() { + let (mut sequencer, mempool_handle) = common_setup().await; let genesis_height = sequencer.chain_height; let tx = common::test_utils::produce_dummy_empty_transaction(); - sequencer.mempool.push_item(tx); + mempool_handle.push(tx).await.unwrap(); let block_id = sequencer.produce_new_block_with_mempool_transactions(); assert!(block_id.is_ok()); assert_eq!(block_id.unwrap(), genesis_height + 1); } - #[test] - fn test_replay_transactions_are_rejected_in_the_same_block() { - let config = setup_sequencer_config(); - let mut sequencer = SequencerCore::start_from_config(config); - - common_setup(&mut sequencer); + #[tokio::test] + async fn test_replay_transactions_are_rejected_in_the_same_block() { + let (mut sequencer, mempool_handle) = common_setup().await; let acc1 = sequencer.sequencer_config.initial_accounts[0] - .addr + .account_id .clone() .from_base58() .unwrap() .try_into() .unwrap(); let acc2 = sequencer.sequencer_config.initial_accounts[1] - .addr + .account_id .clone() .from_base58() .unwrap() @@ -679,8 +652,8 @@ mod tests { let tx_original = tx.clone(); let tx_replay = tx.clone(); // Pushing two copies of the same tx to the mempool - sequencer.mempool.push_item(tx_original); - sequencer.mempool.push_item(tx_replay); + mempool_handle.push(tx_original).await.unwrap(); + mempool_handle.push(tx_replay).await.unwrap(); // Create block let current_height = sequencer @@ -695,22 +668,19 @@ mod tests { assert_eq!(block.body.transactions, vec![tx.clone()]); } - #[test] - fn test_replay_transactions_are_rejected_in_different_blocks() { - let config = setup_sequencer_config(); - let mut sequencer = SequencerCore::start_from_config(config); - - common_setup(&mut sequencer); + #[tokio::test] + async fn test_replay_transactions_are_rejected_in_different_blocks() { + let (mut sequencer, mempool_handle) = common_setup().await; let acc1 = sequencer.sequencer_config.initial_accounts[0] - .addr + .account_id .clone() .from_base58() .unwrap() .try_into() .unwrap(); let acc2 = sequencer.sequencer_config.initial_accounts[1] - .addr + .account_id .clone() .from_base58() .unwrap() @@ -724,7 +694,7 @@ mod tests { ); // The transaction should be included the first time - sequencer.mempool.push_item(tx.clone()); + mempool_handle.push(tx.clone()).await.unwrap(); let current_height = sequencer .produce_new_block_with_mempool_transactions() .unwrap(); @@ -735,7 +705,7 @@ mod tests { assert_eq!(block.body.transactions, vec![tx.clone()]); // Add same transaction should fail - sequencer.mempool.push_item(tx); + mempool_handle.push(tx.clone()).await.unwrap(); let current_height = sequencer .produce_new_block_with_mempool_transactions() .unwrap(); @@ -746,29 +716,31 @@ mod tests { assert!(block.body.transactions.is_empty()); } - #[test] - fn test_restart_from_storage() { + #[tokio::test] + async fn test_restart_from_storage() { let config = setup_sequencer_config(); - let acc1_addr: nssa::Address = config.initial_accounts[0].addr.parse().unwrap(); - let acc2_addr: nssa::Address = config.initial_accounts[1].addr.parse().unwrap(); + let acc1_account_id: nssa::AccountId = + config.initial_accounts[0].account_id.parse().unwrap(); + let acc2_account_id: nssa::AccountId = + config.initial_accounts[1].account_id.parse().unwrap(); let balance_to_move = 13; // In the following code block a transaction will be processed that moves `balance_to_move` // from `acc_1` to `acc_2`. The block created with that transaction will be kept stored in // the temporary directory for the block storage of this test. { - let mut sequencer = SequencerCore::start_from_config(config.clone()); + let (mut sequencer, mempool_handle) = SequencerCore::start_from_config(config.clone()); let signing_key = PrivateKey::try_new([1; 32]).unwrap(); let tx = common::test_utils::create_transaction_native_token_transfer( - *acc1_addr.value(), + *acc1_account_id.value(), 0, - *acc2_addr.value(), + *acc2_account_id.value(), balance_to_move, signing_key, ); - sequencer.mempool.push_item(tx.clone()); + mempool_handle.push(tx.clone()).await.unwrap(); let current_height = sequencer .produce_new_block_with_mempool_transactions() .unwrap(); @@ -781,9 +753,9 @@ mod tests { // Instantiating a new sequencer from the same config. This should load the existing block // with the above transaction and update the state to reflect that. - let sequencer = SequencerCore::start_from_config(config.clone()); - let balance_acc_1 = sequencer.state.get_account_by_address(&acc1_addr).balance; - let balance_acc_2 = sequencer.state.get_account_by_address(&acc2_addr).balance; + let (sequencer, _mempool_handle) = SequencerCore::start_from_config(config.clone()); + let balance_acc_1 = sequencer.state.get_account_by_id(&acc1_account_id).balance; + let balance_acc_2 = sequencer.state.get_account_by_id(&acc2_account_id).balance; // Balances should be consistent with the stored block assert_eq!( diff --git a/sequencer_core/src/sequencer_store/mod.rs b/sequencer_core/src/sequencer_store/mod.rs deleted file mode 100644 index dd99639..0000000 --- a/sequencer_core/src/sequencer_store/mod.rs +++ /dev/null @@ -1,74 +0,0 @@ -use std::path::Path; - -use block_store::SequecerBlockStore; -use common::block::HashableBlockData; -use nssa::{self, Address}; -use rand::{RngCore, rngs::OsRng}; - -use crate::config::AccountInitialData; - -pub mod block_store; - -pub struct SequecerChainStore { - pub state: nssa::V02State, - pub block_store: SequecerBlockStore, -} - -impl SequecerChainStore { - pub fn new_with_genesis( - home_dir: &Path, - genesis_id: u64, - is_genesis_random: bool, - initial_accounts: &[AccountInitialData], - initial_commitments: &[nssa_core::Commitment], - signing_key: nssa::PrivateKey, - ) -> Self { - let init_accs: Vec<(Address, u128)> = initial_accounts - .iter() - .map(|acc_data| (acc_data.addr.parse().unwrap(), acc_data.balance)) - .collect(); - - #[cfg(not(feature = "testnet"))] - let state = nssa::V02State::new_with_genesis_accounts(&init_accs, initial_commitments); - - #[cfg(feature = "testnet")] - let state = { - use common::PINATA_BASE58; - - let mut this = - nssa::V02State::new_with_genesis_accounts(&init_accs, initial_commitments); - this.add_pinata_program(PINATA_BASE58.parse().unwrap()); - this - }; - - let mut data = [0; 32]; - let mut prev_block_hash = [0; 32]; - - if is_genesis_random { - OsRng.fill_bytes(&mut data); - OsRng.fill_bytes(&mut prev_block_hash); - } - - let curr_time = chrono::Utc::now().timestamp_millis() as u64; - - let hashable_data = HashableBlockData { - block_id: genesis_id, - transactions: vec![], - prev_block_hash, - timestamp: curr_time, - }; - - let genesis_block = hashable_data.into_block(&signing_key); - - //Sequencer should panic if unable to open db, - //as fixing this issue may require actions non-native to program scope - let block_store = SequecerBlockStore::open_db_with_genesis( - &home_dir.join("rocksdb"), - Some(genesis_block), - signing_key, - ) - .unwrap(); - - Self { state, block_store } - } -} diff --git a/sequencer_rpc/Cargo.toml b/sequencer_rpc/Cargo.toml index 557ce6a..242e8b2 100644 --- a/sequencer_rpc/Cargo.toml +++ b/sequencer_rpc/Cargo.toml @@ -19,6 +19,8 @@ actix-web.workspace = true tokio.workspace = true borsh.workspace = true +# TODO: Move to workspace + [dependencies.sequencer_core] path = "../sequencer_core" @@ -27,3 +29,6 @@ path = "../common" [dependencies.nssa] path = "../nssa" + +[dependencies.mempool] +path = "../mempool" diff --git a/sequencer_rpc/src/lib.rs b/sequencer_rpc/src/lib.rs index 2973c42..89b3e8c 100644 --- a/sequencer_rpc/src/lib.rs +++ b/sequencer_rpc/src/lib.rs @@ -4,23 +4,23 @@ pub mod types; use std::sync::Arc; -use common::rpc_primitives::{ - RpcPollingConfig, - errors::{RpcError, RpcErrorKind}, +use common::{ + rpc_primitives::errors::{RpcError, RpcErrorKind}, + transaction::EncodedTransaction, }; +use mempool::MemPoolHandle; +pub use net_utils::*; use sequencer_core::SequencerCore; use serde::Serialize; use serde_json::Value; - -pub use net_utils::*; use tokio::sync::Mutex; use self::types::err_rpc::RpcErr; -//ToDo: Add necessary fields +// ToDo: Add necessary fields pub struct JsonHandler { - pub polling_config: RpcPollingConfig, - pub sequencer_state: Arc>, + sequencer_state: Arc>, + mempool_handle: MemPoolHandle, } fn respond(val: T) -> Result { diff --git a/sequencer_rpc/src/net_utils.rs b/sequencer_rpc/src/net_utils.rs index b373823..33eacae 100644 --- a/sequencer_rpc/src/net_utils.rs +++ b/sequencer_rpc/src/net_utils.rs @@ -1,14 +1,14 @@ -use std::io; -use std::sync::Arc; +use std::{io, sync::Arc}; use actix_cors::Cors; use actix_web::{App, Error as HttpError, HttpResponse, HttpServer, http, middleware, web}; -use futures::Future; -use futures::FutureExt; +use common::{ + rpc_primitives::{RpcConfig, message::Message}, + transaction::EncodedTransaction, +}; +use futures::{Future, FutureExt}; use log::info; - -use common::rpc_primitives::RpcConfig; -use common::rpc_primitives::message::Message; +use mempool::MemPoolHandle; use sequencer_core::SequencerCore; use tokio::sync::Mutex; @@ -46,17 +46,17 @@ fn get_cors(cors_allowed_origins: &[String]) -> Cors { pub fn new_http_server( config: RpcConfig, seuquencer_core: Arc>, + mempool_handle: MemPoolHandle, ) -> io::Result { let RpcConfig { addr, cors_allowed_origins, - polling_config, limits_config, } = config; info!(target:NETWORK, "Starting http server at {addr}"); let handler = web::Data::new(JsonHandler { - polling_config, sequencer_state: seuquencer_core.clone(), + mempool_handle, }); // HTTP server diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index 042d077..23d5edd 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -3,10 +3,6 @@ use std::collections::HashMap; use actix_web::Error as HttpError; use base58::FromBase58; use base64::{Engine, engine::general_purpose}; -use nssa::{self, program::Program}; -use sequencer_core::config::AccountInitialData; -use serde_json::Value; - use common::{ HashType, block::HashableBlockData, @@ -17,19 +13,20 @@ use common::{ requests::{ GetAccountBalanceRequest, GetAccountBalanceResponse, GetAccountRequest, GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse, - GetInitialTestnetAccountsRequest, GetProgramIdsRequest, GetProgramIdsResponse, - GetProofForCommitmentRequest, GetProofForCommitmentResponse, - GetTransactionByHashRequest, GetTransactionByHashResponse, + GetBlockDataRequest, GetBlockDataResponse, GetGenesisIdRequest, GetGenesisIdResponse, + GetInitialTestnetAccountsRequest, GetLastBlockRequest, GetLastBlockResponse, + GetProgramIdsRequest, GetProgramIdsResponse, GetProofForCommitmentRequest, + GetProofForCommitmentResponse, GetTransactionByHashRequest, + GetTransactionByHashResponse, HelloRequest, HelloResponse, SendTxRequest, + SendTxResponse, }, }, - transaction::EncodedTransaction, -}; - -use common::rpc_primitives::requests::{ - GetBlockDataRequest, GetBlockDataResponse, GetGenesisIdRequest, GetGenesisIdResponse, - GetLastBlockRequest, GetLastBlockResponse, HelloRequest, HelloResponse, SendTxRequest, - SendTxResponse, + transaction::{EncodedTransaction, NSSATransaction}, }; +use log::warn; +use nssa::{self, program::Program}; +use sequencer_core::{TransactionMalformationError, config::AccountInitialData}; +use serde_json::Value; use super::{JsonHandler, respond, types::err_rpc::RpcErr}; @@ -67,16 +64,16 @@ impl JsonHandler { } } + /// Example of request processing #[allow(clippy::unused_async)] - ///Example of request processing async fn process_temp_hello(&self, request: Request) -> Result { let _hello_request = HelloRequest::parse(Some(request.params))?; - let helperstruct = HelloResponse { + let response = HelloResponse { greeting: HELLO_FROM_SEQUENCER.to_string(), }; - respond(helperstruct) + respond(response) } async fn process_send_tx(&self, request: Request) -> Result { @@ -84,18 +81,25 @@ impl JsonHandler { let tx = borsh::from_slice::(&send_tx_req.transaction).unwrap(); let tx_hash = hex::encode(tx.hash()); - { - let mut state = self.sequencer_state.lock().await; + let transaction = NSSATransaction::try_from(&tx) + .map_err(|_| TransactionMalformationError::FailedToDecode { tx: tx.hash() })?; - state.push_tx_into_mempool_pre_check(tx)?; - } + let authenticated_tx = sequencer_core::transaction_pre_check(transaction) + .inspect_err(|err| warn!("Error at pre_check {err:#?}"))?; - let helperstruct = SendTxResponse { + // TODO: Do we need a timeout here? It will be usable if we have too many transactions to + // process + self.mempool_handle + .push(authenticated_tx.into()) + .await + .expect("Mempool is closed, this is a bug"); + + let response = SendTxResponse { status: TRANSACTION_SUBMITTED.to_string(), tx_hash, }; - respond(helperstruct) + respond(response) } async fn process_get_block_data(&self, request: Request) -> Result { @@ -104,14 +108,16 @@ impl JsonHandler { let block = { let state = self.sequencer_state.lock().await; - state.block_store.get_block_at_id(get_block_req.block_id)? + state + .block_store() + .get_block_at_id(get_block_req.block_id)? }; - let helperstruct = GetBlockDataResponse { + let response = GetBlockDataResponse { block: borsh::to_vec(&HashableBlockData::from(block)).unwrap(), }; - respond(helperstruct) + respond(response) } async fn process_get_genesis(&self, request: Request) -> Result { @@ -120,12 +126,12 @@ impl JsonHandler { let genesis_id = { let state = self.sequencer_state.lock().await; - state.block_store.genesis_id + state.block_store().genesis_id() }; - let helperstruct = GetGenesisIdResponse { genesis_id }; + let response = GetGenesisIdResponse { genesis_id }; - respond(helperstruct) + respond(response) } async fn process_get_last_block(&self, request: Request) -> Result { @@ -134,12 +140,12 @@ impl JsonHandler { let last_block = { let state = self.sequencer_state.lock().await; - state.chain_height + state.chain_height() }; - let helperstruct = GetLastBlockResponse { last_block }; + let response = GetLastBlockResponse { last_block }; - respond(helperstruct) + respond(response) } /// Returns the initial accounts for testnet @@ -151,83 +157,83 @@ impl JsonHandler { let initial_accounts: Vec = { let state = self.sequencer_state.lock().await; - state.sequencer_config.initial_accounts.clone() + state.sequencer_config().initial_accounts.clone() }; respond(initial_accounts) } - /// Returns the balance of the account at the given address. - /// The address must be a valid hex string of the correct length. + /// Returns the balance of the account at the given account_id. + /// The account_id must be a valid hex string of the correct length. async fn process_get_account_balance(&self, request: Request) -> Result { let get_account_req = GetAccountBalanceRequest::parse(Some(request.params))?; - let address_bytes = get_account_req - .address + let account_id_bytes = get_account_req + .account_id .from_base58() .map_err(|_| RpcError::invalid_params("invalid base58".to_string()))?; - let address = nssa::Address::new( - address_bytes + let account_id = nssa::AccountId::new( + account_id_bytes .try_into() .map_err(|_| RpcError::invalid_params("invalid length".to_string()))?, ); let balance = { let state = self.sequencer_state.lock().await; - let account = state.state.get_account_by_address(&address); + let account = state.state().get_account_by_id(&account_id); account.balance }; - let helperstruct = GetAccountBalanceResponse { balance }; + let response = GetAccountBalanceResponse { balance }; - respond(helperstruct) + respond(response) } - /// Returns the nonces of the accounts at the given addresses. - /// Each address must be a valid hex string of the correct length. + /// Returns the nonces of the accounts at the given account_ids. + /// Each account_id must be a valid hex string of the correct length. async fn process_get_accounts_nonces(&self, request: Request) -> Result { let get_account_nonces_req = GetAccountsNoncesRequest::parse(Some(request.params))?; - let mut addresses = vec![]; - for address_raw in get_account_nonces_req.addresses { - let address = address_raw - .parse::() + let mut account_ids = vec![]; + for account_id_raw in get_account_nonces_req.account_ids { + let account_id = account_id_raw + .parse::() .map_err(|e| RpcError::invalid_params(e.to_string()))?; - addresses.push(address); + account_ids.push(account_id); } let nonces = { let state = self.sequencer_state.lock().await; - addresses + account_ids .into_iter() - .map(|addr| state.state.get_account_by_address(&addr).nonce) + .map(|account_id| state.state().get_account_by_id(&account_id).nonce) .collect() }; - let helperstruct = GetAccountsNoncesResponse { nonces }; + let response = GetAccountsNoncesResponse { nonces }; - respond(helperstruct) + respond(response) } - /// Returns account struct for given address. - /// Address must be a valid hex string of the correct length. + /// Returns account struct for given account_id. + /// AccountId must be a valid hex string of the correct length. async fn process_get_account(&self, request: Request) -> Result { let get_account_nonces_req = GetAccountRequest::parse(Some(request.params))?; - let address = get_account_nonces_req - .address - .parse::() + let account_id = get_account_nonces_req + .account_id + .parse::() .map_err(|e| RpcError::invalid_params(e.to_string()))?; let account = { let state = self.sequencer_state.lock().await; - state.state.get_account_by_address(&address) + state.state().get_account_by_id(&account_id) }; - let helperstruct = GetAccountResponse { account }; + let response = GetAccountResponse { account }; - respond(helperstruct) + respond(response) } /// Returns the transaction corresponding to the given hash, if it exists in the blockchain. @@ -243,15 +249,15 @@ impl JsonHandler { let transaction = { let state = self.sequencer_state.lock().await; state - .block_store + .block_store() .get_transaction_by_hash(hash) .map(|tx| borsh::to_vec(&tx).unwrap()) }; let base64_encoded = transaction.map(|tx| general_purpose::STANDARD.encode(tx)); - let helperstruct = GetTransactionByHashResponse { + let response = GetTransactionByHashResponse { transaction: base64_encoded, }; - respond(helperstruct) + respond(response) } /// Returns the commitment proof, corresponding to commitment @@ -261,11 +267,11 @@ impl JsonHandler { let membership_proof = { let state = self.sequencer_state.lock().await; state - .state + .state() .get_proof_for_commitment(&get_proof_req.commitment) }; - let helperstruct = GetProofForCommitmentResponse { membership_proof }; - respond(helperstruct) + let response = GetProofForCommitmentResponse { membership_proof }; + respond(response) } async fn process_get_program_ids(&self, request: Request) -> Result { @@ -282,8 +288,8 @@ impl JsonHandler { "privacy_preserving_circuit".to_string(), nssa::PRIVACY_PRESERVING_CIRCUIT_ID, ); - let helperstruct = GetProgramIdsResponse { program_ids }; - respond(helperstruct) + let response = GetProgramIdsResponse { program_ids }; + respond(response) } pub async fn process_request_internal(&self, request: Request) -> Result { @@ -309,14 +315,9 @@ impl JsonHandler { mod tests { use std::sync::Arc; - use crate::{JsonHandler, rpc_handler}; use base58::ToBase58; use base64::{Engine, engine::general_purpose}; - use common::{ - rpc_primitives::RpcPollingConfig, test_utils::sequencer_sign_key_for_testing, - transaction::EncodedTransaction, - }; - + use common::{test_utils::sequencer_sign_key_for_testing, transaction::EncodedTransaction}; use sequencer_core::{ SequencerCore, config::{AccountInitialData, SequencerConfig}, @@ -325,26 +326,28 @@ mod tests { use tempfile::tempdir; use tokio::sync::Mutex; + use crate::{JsonHandler, rpc_handler}; + fn sequencer_config_for_tests() -> SequencerConfig { let tempdir = tempdir().unwrap(); let home = tempdir.path().to_path_buf(); - let acc1_addr: Vec = vec![ + let acc1_id: Vec = vec![ 208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9, 115, 84, 126, 106, 16, 111, 114, 241, 147, 194, 220, 131, 139, 68, ]; - let acc2_addr: Vec = vec![ + let acc2_id: Vec = vec![ 231, 174, 119, 197, 239, 26, 5, 153, 147, 68, 175, 73, 159, 199, 138, 23, 5, 57, 141, 98, 237, 6, 207, 46, 20, 121, 246, 222, 248, 154, 57, 188, ]; let initial_acc1 = AccountInitialData { - addr: acc1_addr.to_base58(), + account_id: acc1_id.to_base58(), balance: 10000, }; let initial_acc2 = AccountInitialData { - addr: acc2_addr.to_base58(), + account_id: acc2_id.to_base58(), balance: 20000, }; @@ -365,10 +368,10 @@ mod tests { } } - fn components_for_tests() -> (JsonHandler, Vec, EncodedTransaction) { + async fn components_for_tests() -> (JsonHandler, Vec, EncodedTransaction) { let config = sequencer_config_for_tests(); - let mut sequencer_core = SequencerCore::start_from_config(config); - let initial_accounts = sequencer_core.sequencer_config.initial_accounts.clone(); + let (mut sequencer_core, mempool_handle) = SequencerCore::start_from_config(config); + let initial_accounts = sequencer_core.sequencer_config().initial_accounts.clone(); let signing_key = nssa::PrivateKey::try_new([1; 32]).unwrap(); let balance_to_move = 10; @@ -383,9 +386,10 @@ mod tests { signing_key, ); - sequencer_core - .push_tx_into_mempool_pre_check(tx.clone()) - .unwrap(); + mempool_handle + .push(tx.clone()) + .await + .expect("Mempool is closed, this is a bug"); sequencer_core .produce_new_block_with_mempool_transactions() @@ -395,8 +399,8 @@ mod tests { ( JsonHandler { - polling_config: RpcPollingConfig::default(), sequencer_state: sequencer_core, + mempool_handle, }, initial_accounts, tx, @@ -426,11 +430,11 @@ mod tests { #[actix_web::test] async fn test_get_account_balance_for_non_existent_account() { - let (json_handler, _, _) = components_for_tests(); + let (json_handler, _, _) = components_for_tests().await; let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_account_balance", - "params": { "address": "11".repeat(16) }, + "params": { "account_id": "11".repeat(16) }, "id": 1 }); let expected_response = serde_json::json!({ @@ -448,11 +452,11 @@ mod tests { #[actix_web::test] async fn test_get_account_balance_for_invalid_base58() { - let (json_handler, _, _) = components_for_tests(); + let (json_handler, _, _) = components_for_tests().await; let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_account_balance", - "params": { "address": "not_a_valid_base58" }, + "params": { "account_id": "not_a_valid_base58" }, "id": 1 }); let expected_response = serde_json::json!({ @@ -471,11 +475,11 @@ mod tests { #[actix_web::test] async fn test_get_account_balance_for_invalid_length() { - let (json_handler, _, _) = components_for_tests(); + let (json_handler, _, _) = components_for_tests().await; let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_account_balance", - "params": { "address": "cafecafe" }, + "params": { "account_id": "cafecafe" }, "id": 1 }); let expected_response = serde_json::json!({ @@ -494,14 +498,14 @@ mod tests { #[actix_web::test] async fn test_get_account_balance_for_existing_account() { - let (json_handler, initial_accounts, _) = components_for_tests(); + let (json_handler, initial_accounts, _) = components_for_tests().await; - let acc1_addr = initial_accounts[0].addr.clone(); + let acc1_id = initial_accounts[0].account_id.clone(); let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_account_balance", - "params": { "address": acc1_addr }, + "params": { "account_id": acc1_id }, "id": 1 }); let expected_response = serde_json::json!({ @@ -519,11 +523,11 @@ mod tests { #[actix_web::test] async fn test_get_accounts_nonces_for_non_existent_account() { - let (json_handler, _, _) = components_for_tests(); + let (json_handler, _, _) = components_for_tests().await; let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_accounts_nonces", - "params": { "addresses": ["11".repeat(16)] }, + "params": { "account_ids": ["11".repeat(16)] }, "id": 1 }); let expected_response = serde_json::json!({ @@ -541,15 +545,15 @@ mod tests { #[actix_web::test] async fn test_get_accounts_nonces_for_existent_account() { - let (json_handler, initial_accounts, _) = components_for_tests(); + let (json_handler, initial_accounts, _) = components_for_tests().await; - let acc_1_addr = initial_accounts[0].addr.clone(); - let acc_2_addr = initial_accounts[1].addr.clone(); + let acc1_id = initial_accounts[0].account_id.clone(); + let acc2_id = initial_accounts[1].account_id.clone(); let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_accounts_nonces", - "params": { "addresses": [acc_1_addr, acc_2_addr] }, + "params": { "account_ids": [acc1_id, acc2_id] }, "id": 1 }); let expected_response = serde_json::json!({ @@ -567,11 +571,11 @@ mod tests { #[actix_web::test] async fn test_get_account_data_for_non_existent_account() { - let (json_handler, _, _) = components_for_tests(); + let (json_handler, _, _) = components_for_tests().await; let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_account", - "params": { "address": "11".repeat(16) }, + "params": { "account_id": "11".repeat(16) }, "id": 1 }); let expected_response = serde_json::json!({ @@ -594,7 +598,7 @@ mod tests { #[actix_web::test] async fn test_get_transaction_by_hash_for_non_existent_hash() { - let (json_handler, _, _) = components_for_tests(); + let (json_handler, _, _) = components_for_tests().await; let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_transaction_by_hash", @@ -616,7 +620,7 @@ mod tests { #[actix_web::test] async fn test_get_transaction_by_hash_for_invalid_hex() { - let (json_handler, _, _) = components_for_tests(); + let (json_handler, _, _) = components_for_tests().await; let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_transaction_by_hash", @@ -640,7 +644,7 @@ mod tests { #[actix_web::test] async fn test_get_transaction_by_hash_for_invalid_length() { - let (json_handler, _, _) = components_for_tests(); + let (json_handler, _, _) = components_for_tests().await; let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_transaction_by_hash", @@ -664,7 +668,7 @@ mod tests { #[actix_web::test] async fn test_get_transaction_by_hash_for_existing_transaction() { - let (json_handler, _, tx) = components_for_tests(); + let (json_handler, _, tx) = components_for_tests().await; let tx_hash_hex = hex::encode(tx.hash()); let expected_base64_encoded = general_purpose::STANDARD.encode(borsh::to_vec(&tx).unwrap()); diff --git a/sequencer_rpc/src/types/err_rpc.rs b/sequencer_rpc/src/types/err_rpc.rs index d217571..14807d5 100644 --- a/sequencer_rpc/src/types/err_rpc.rs +++ b/sequencer_rpc/src/types/err_rpc.rs @@ -1,6 +1,5 @@ -use log::debug; - use common::rpc_primitives::errors::{RpcError, RpcParseError}; +use log::debug; use sequencer_core::TransactionMalformationError; pub struct RpcErr(pub RpcError); diff --git a/sequencer_runner/configs/debug/sequencer_config.json b/sequencer_runner/configs/debug/sequencer_config.json index 08ba4dd..58348f6 100644 --- a/sequencer_runner/configs/debug/sequencer_config.json +++ b/sequencer_runner/configs/debug/sequencer_config.json @@ -9,11 +9,11 @@ "port": 3040, "initial_accounts": [ { - "addr": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", + "account_id": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", "balance": 10000 }, { - "addr": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", + "account_id": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", "balance": 20000 } ], diff --git a/sequencer_runner/src/config.rs b/sequencer_runner/src/config.rs index 175903d..58f539b 100644 --- a/sequencer_runner/src/config.rs +++ b/sequencer_runner/src/config.rs @@ -1,11 +1,8 @@ -use std::path::PathBuf; +use std::{fs::File, io::BufReader, path::PathBuf}; use anyhow::Result; use sequencer_core::config::SequencerConfig; -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); diff --git a/sequencer_runner/src/lib.rs b/sequencer_runner/src/lib.rs index 068d3d7..e9f4a84 100644 --- a/sequencer_runner/src/lib.rs +++ b/sequencer_runner/src/lib.rs @@ -26,13 +26,17 @@ pub async fn startup_sequencer( let block_timeout = app_config.block_create_timeout_millis; let port = app_config.port; - let sequencer_core = SequencerCore::start_from_config(app_config); + let (sequencer_core, mempool_handle) = SequencerCore::start_from_config(app_config); info!("Sequencer core set up"); let seq_core_wrapped = Arc::new(Mutex::new(sequencer_core)); - let http_server = new_http_server(RpcConfig::with_port(port), seq_core_wrapped.clone())?; + let http_server = new_http_server( + RpcConfig::with_port(port), + Arc::clone(&seq_core_wrapped), + mempool_handle, + )?; info!("HTTP server started"); let http_server_handle = http_server.handle(); tokio::spawn(http_server); @@ -76,7 +80,7 @@ pub async fn main_runner() -> Result<()> { } } - //ToDo: Add restart on failures + // ToDo: Add restart on failures let (_, main_loop_handle) = startup_sequencer(app_config).await?; main_loop_handle.await??; diff --git a/sequencer_runner/src/main.rs b/sequencer_runner/src/main.rs index 9de8835..3bf4ee2 100644 --- a/sequencer_runner/src/main.rs +++ b/sequencer_runner/src/main.rs @@ -1,9 +1,9 @@ use anyhow::Result; - use sequencer_runner::main_runner; pub const NUM_THREADS: usize = 4; +// TODO: Why it requires config as a directory and not as a file? fn main() -> Result<()> { actix::System::with_tokio_rt(|| { tokio::runtime::Builder::new_multi_thread() diff --git a/storage/src/lib.rs b/storage/src/lib.rs index cbce767..87b7870 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -8,33 +8,33 @@ use rocksdb::{ pub mod error; -///Maximal size of stored blocks in base +/// Maximal size of stored blocks in base /// -///Used to control db size +/// Used to control db size /// -///Currently effectively unbounded. +/// Currently effectively unbounded. pub const BUFF_SIZE_ROCKSDB: usize = usize::MAX; -///Size of stored blocks cache in memory +/// Size of stored blocks cache in memory /// -///Keeping small to not run out of memory +/// Keeping small to not run out of memory pub const CACHE_SIZE: usize = 1000; -///Key base for storing metainformation about id of first block in db +/// Key base for storing metainformation about id of first block in db pub const DB_META_FIRST_BLOCK_IN_DB_KEY: &str = "first_block_in_db"; -///Key base for storing metainformation about id of last current block in db +/// Key base for storing metainformation about id of last current block in db pub const DB_META_LAST_BLOCK_IN_DB_KEY: &str = "last_block_in_db"; -///Key base for storing metainformation which describe if first block has been set +/// Key base for storing metainformation which describe if first block has been set pub const DB_META_FIRST_BLOCK_SET_KEY: &str = "first_block_set"; -///Key base for storing snapshot which describe block id +/// Key base for storing snapshot which describe block id pub const DB_SNAPSHOT_BLOCK_ID_KEY: &str = "block_id"; -///Name of block column family +/// Name of block column family pub const CF_BLOCK_NAME: &str = "cf_block"; -///Name of meta column family +/// Name of meta column family pub const CF_META_NAME: &str = "cf_meta"; -///Name of snapshot column family +/// Name of snapshot column family pub const CF_SNAPSHOT_NAME: &str = "cf_snapshot"; pub type DbResult = Result; @@ -47,7 +47,7 @@ impl RocksDBIO { pub fn open_or_create(path: &Path, start_block: Option) -> DbResult { let mut cf_opts = Options::default(); cf_opts.set_max_write_buffer_number(16); - //ToDo: Add more column families for different data + // ToDo: Add more column families for different data let cfb = ColumnFamilyDescriptor::new(CF_BLOCK_NAME, cf_opts.clone()); let cfmeta = ColumnFamilyDescriptor::new(CF_META_NAME, cf_opts.clone()); let cfsnapshot = ColumnFamilyDescriptor::new(CF_SNAPSHOT_NAME, cf_opts.clone()); @@ -62,7 +62,7 @@ impl RocksDBIO { ); let dbio = Self { - //There is no point in handling this from runner code + // There is no point in handling this from runner code db: db.unwrap(), }; @@ -86,7 +86,7 @@ impl RocksDBIO { pub fn destroy(path: &Path) -> DbResult<()> { let mut cf_opts = Options::default(); cf_opts.set_max_write_buffer_number(16); - //ToDo: Add more column families for different data + // ToDo: Add more column families for different data let _cfb = ColumnFamilyDescriptor::new(CF_BLOCK_NAME, cf_opts.clone()); let _cfmeta = ColumnFamilyDescriptor::new(CF_META_NAME, cf_opts.clone()); let _cfsnapshot = ColumnFamilyDescriptor::new(CF_SNAPSHOT_NAME, cf_opts.clone()); diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index b04d67e..74eb5bc 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -19,6 +19,7 @@ borsh.workspace = true base58.workspace = true hex = "0.4.3" rand.workspace = true +itertools = "0.14.0" [dependencies.key_protocol] path = "../key_protocol" diff --git a/wallet/src/chain_storage/mod.rs b/wallet/src/chain_storage/mod.rs index 5215d99..14e931a 100644 --- a/wallet/src/chain_storage/mod.rs +++ b/wallet/src/chain_storage/mod.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{HashMap, hash_map::Entry}; use anyhow::Result; use key_protocol::{ @@ -36,7 +36,7 @@ impl WalletChainStore { _ => false, }) .cloned() - .unwrap(); + .expect("Malformed persistent account data, must have public root"); let private_root = persistent_accounts .iter() @@ -45,7 +45,7 @@ impl WalletChainStore { _ => false, }) .cloned() - .unwrap(); + .expect("Malformed persistent account data, must have private root"); let mut public_tree = KeyTreePublic::new_from_root(match public_root { PersistentAccountData::Public(data) => data.data, @@ -59,18 +59,18 @@ impl WalletChainStore { for pers_acc_data in persistent_accounts { match pers_acc_data { PersistentAccountData::Public(data) => { - public_tree.insert(data.address, data.chain_index, data.data); + public_tree.insert(data.account_id, data.chain_index, data.data); } PersistentAccountData::Private(data) => { - private_tree.insert(data.address, data.chain_index, data.data); + private_tree.insert(data.account_id, data.chain_index, data.data); } PersistentAccountData::Preconfigured(acc_data) => match acc_data { InitialAccountData::Public(data) => { - public_init_acc_map.insert(data.address.parse()?, data.pub_sign_key); + public_init_acc_map.insert(data.account_id.parse()?, data.pub_sign_key); } InitialAccountData::Private(data) => { private_init_acc_map - .insert(data.address.parse()?, (data.key_chain, data.account)); + .insert(data.account_id.parse()?, (data.key_chain, data.account)); } }, } @@ -94,7 +94,7 @@ impl WalletChainStore { for init_acc_data in config.initial_accounts.clone() { match init_acc_data { InitialAccountData::Public(data) => { - public_init_acc_map.insert(data.address.parse()?, data.pub_sign_key); + public_init_acc_map.insert(data.account_id.parse()?, data.pub_sign_key); } InitialAccountData::Private(data) => { let mut account = data.account; @@ -102,7 +102,8 @@ impl WalletChainStore { // the config. Therefore we overwrite it here on startup. Fix this when program // id can be fetched from the node and queried from the wallet. account.program_owner = Program::authenticated_transfer_program().id(); - private_init_acc_map.insert(data.address.parse()?, (data.key_chain, account)); + private_init_acc_map + .insert(data.account_id.parse()?, (data.key_chain, account)); } } } @@ -123,25 +124,22 @@ impl WalletChainStore { pub fn insert_private_account_data( &mut self, - addr: nssa::Address, + account_id: nssa::AccountId, account: nssa_core::account::Account, ) { - println!("inserting at address {}, this account {:?}", addr, account); + println!("inserting at address {account_id}, this account {account:?}"); - if self + let entry = self .user_data .default_user_private_accounts - .contains_key(&addr) - { - self.user_data - .default_user_private_accounts - .entry(addr) - .and_modify(|data| data.1 = account); - } else { + .entry(account_id) + .and_modify(|data| data.1 = account.clone()); + + if matches!(entry, Entry::Vacant(_)) { self.user_data .private_key_tree - .addr_map - .get(&addr) + .account_id_map + .get(&account_id) .map(|chain_index| { self.user_data .private_key_tree @@ -159,17 +157,16 @@ mod tests { keys_private::ChildKeysPrivate, keys_public::ChildKeysPublic, traits::KeyNode, }; + use super::*; use crate::config::{ InitialAccountData, PersistentAccountDataPrivate, PersistentAccountDataPublic, }; - use super::*; - fn create_initial_accounts() -> Vec { let initial_acc1 = serde_json::from_str( r#"{ "Public": { - "address": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", + "account_id": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", "pub_sign_key": [ 16, 162, @@ -212,7 +209,7 @@ mod tests { let initial_acc2 = serde_json::from_str( r#"{ "Public": { - "address": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", + "account_id": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", "pub_sign_key": [ 113, 121, @@ -270,27 +267,21 @@ mod tests { } fn create_sample_persistent_accounts() -> Vec { - let mut accs = vec![]; - let public_data = ChildKeysPublic::root([42; 64]); - - accs.push(PersistentAccountData::Public(PersistentAccountDataPublic { - address: public_data.address(), - chain_index: ChainIndex::root(), - data: public_data, - })); - let private_data = ChildKeysPrivate::root([47; 64]); - accs.push(PersistentAccountData::Private( - PersistentAccountDataPrivate { - address: private_data.address(), + vec![ + PersistentAccountData::Public(PersistentAccountDataPublic { + account_id: public_data.account_id(), + chain_index: ChainIndex::root(), + data: public_data, + }), + PersistentAccountData::Private(PersistentAccountDataPrivate { + account_id: private_data.account_id(), chain_index: ChainIndex::root(), data: private_data, - }, - )); - - accs + }), + ] } #[test] diff --git a/wallet/src/cli/account.rs b/wallet/src/cli/account.rs index b9a7699..6e831d1 100644 --- a/wallet/src/cli/account.rs +++ b/wallet/src/cli/account.rs @@ -1,14 +1,15 @@ use anyhow::Result; use base58::ToBase58; use clap::Subcommand; +use itertools::Itertools as _; use key_protocol::key_management::key_tree::chain_index::ChainIndex; -use nssa::{Account, Address, program::Program}; +use nssa::{Account, AccountId, program::Program}; use serde::Serialize; use crate::{ SubcommandReturnValue, WalletCore, cli::WalletSubcommand, - helperfunctions::{AddressPrivacyKind, HumanReadableAccount, parse_addr_with_privacy_prefix}, + helperfunctions::{AccountPrivacyKind, HumanReadableAccount, parse_addr_with_privacy_prefix}, parse_block_range, }; @@ -28,7 +29,7 @@ struct TokenDefinition { struct TokenHolding { #[allow(unused)] account_type: u8, - definition_id: Address, + definition_id: AccountId, balance: u128, } @@ -56,7 +57,7 @@ impl TokenHolding { None } else { let account_type = data[0]; - let definition_id = Address::new(data[1..33].try_into().unwrap()); + let definition_id = AccountId::new(data[1..33].try_into().unwrap()); let balance = u128::from_le_bytes(data[33..].try_into().unwrap()); Some(Self { definition_id, @@ -67,36 +68,41 @@ impl TokenHolding { } } -///Represents generic chain CLI subcommand +/// Represents generic chain CLI subcommand #[derive(Subcommand, Debug, Clone)] pub enum AccountSubcommand { - ///Get account data + /// Get account data Get { - ///Flag to get raw account data + /// Flag to get raw account data #[arg(short, long)] raw: bool, - ///Valid 32 byte base58 string with privacy prefix + /// Valid 32 byte base58 string with privacy prefix #[arg(short, long)] - addr: String, + account_id: String, }, - ///Produce new public or private account + /// Produce new public or private account #[command(subcommand)] New(NewSubcommand), - ///Sync private accounts + /// Sync private accounts SyncPrivate {}, + /// List all accounts owned by the wallet + #[command(visible_alias = "ls")] + List {}, } -///Represents generic register CLI subcommand +/// Represents generic register CLI subcommand #[derive(Subcommand, Debug, Clone)] pub enum NewSubcommand { - ///Register new public account + /// Register new public account Public { #[arg(long)] + /// Chain index of a parent node cci: ChainIndex, }, - ///Register new private account + /// Register new private account Private { #[arg(long)] + /// Chain index of a parent node cci: ChainIndex, }, } @@ -108,28 +114,28 @@ impl WalletSubcommand for NewSubcommand { ) -> Result { match self { NewSubcommand::Public { cci } => { - let addr = wallet_core.create_new_account_public(cci); + let account_id = wallet_core.create_new_account_public(cci); - println!("Generated new account with addr Public/{addr}"); + println!("Generated new account with account_id Public/{account_id}"); let path = wallet_core.store_persistent_data().await?; println!("Stored persistent accounts at {path:#?}"); - Ok(SubcommandReturnValue::RegisterAccount { addr }) + Ok(SubcommandReturnValue::RegisterAccount { account_id }) } NewSubcommand::Private { cci } => { - let addr = wallet_core.create_new_account_private(cci); + let account_id = wallet_core.create_new_account_private(cci); let (key, _) = wallet_core .storage .user_data - .get_private_account(&addr) + .get_private_account(&account_id) .unwrap(); println!( - "Generated new account with addr Private/{}", - addr.to_bytes().to_base58() + "Generated new account with account_id Private/{}", + account_id.to_bytes().to_base58() ); println!("With npk {}", hex::encode(key.nullifer_public_key.0)); println!( @@ -141,7 +147,7 @@ impl WalletSubcommand for NewSubcommand { println!("Stored persistent accounts at {path:#?}"); - Ok(SubcommandReturnValue::RegisterAccount { addr }) + Ok(SubcommandReturnValue::RegisterAccount { account_id }) } } } @@ -200,15 +206,17 @@ impl WalletSubcommand for AccountSubcommand { wallet_core: &mut WalletCore, ) -> Result { match self { - AccountSubcommand::Get { raw, addr } => { - let (addr, addr_kind) = parse_addr_with_privacy_prefix(&addr)?; + AccountSubcommand::Get { raw, account_id } => { + let (account_id, addr_kind) = parse_addr_with_privacy_prefix(&account_id)?; - let addr = addr.parse()?; + let account_id = account_id.parse()?; let account = match addr_kind { - AddressPrivacyKind::Public => wallet_core.get_account_public(addr).await?, - AddressPrivacyKind::Private => wallet_core - .get_account_private(&addr) + AccountPrivacyKind::Public => { + wallet_core.get_account_public(account_id).await? + } + AccountPrivacyKind::Private => wallet_core + .get_account_private(&account_id) .ok_or(anyhow::anyhow!("Private account not found in storage"))?, }; @@ -250,7 +258,9 @@ impl WalletSubcommand for AccountSubcommand { serde_json::to_string(&acc_view)? } else { - anyhow::bail!("Invalid data for account {addr:#?} with token program"); + anyhow::bail!( + "Invalid data for account {account_id:#?} with token program" + ); } } _ => { @@ -274,13 +284,19 @@ impl WalletSubcommand for AccountSubcommand { .await? .last_block; - if !wallet_core + if wallet_core .storage .user_data .private_key_tree - .addr_map + .account_id_map .is_empty() { + wallet_core.last_synced_block = curr_last_block; + + let path = wallet_core.store_persistent_data().await?; + + println!("Stored persistent data at {path:#?}"); + } else { parse_block_range( last_synced_block + 1, curr_last_block, @@ -288,16 +304,41 @@ impl WalletSubcommand for AccountSubcommand { wallet_core, ) .await?; - } else { - wallet_core.last_synced_block = curr_last_block; - - let path = wallet_core.store_persistent_data().await?; - - println!("Stored persistent data at {path:#?}"); } Ok(SubcommandReturnValue::SyncedToBlock(curr_last_block)) } + AccountSubcommand::List {} => { + let user_data = &wallet_core.storage.user_data; + let accounts = user_data + .default_pub_account_signing_keys + .keys() + .map(|id| format!("Preconfigured Public/{id}")) + .chain( + user_data + .default_user_private_accounts + .keys() + .map(|id| format!("Preconfigured Private/{id}")), + ) + .chain( + user_data + .public_key_tree + .account_id_map + .iter() + .map(|(id, chain_index)| format!("{chain_index} Public/{id}")), + ) + .chain( + user_data + .private_key_tree + .account_id_map + .iter() + .map(|(id, chain_index)| format!("{chain_index} Private/{id}")), + ) + .format(",\n"); + + println!("{accounts}"); + Ok(SubcommandReturnValue::Empty) + } } } } diff --git a/wallet/src/cli/chain.rs b/wallet/src/cli/chain.rs index a6e7999..a606066 100644 --- a/wallet/src/cli/chain.rs +++ b/wallet/src/cli/chain.rs @@ -3,19 +3,19 @@ use clap::Subcommand; use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand}; -///Represents generic chain CLI subcommand +/// Represents generic chain CLI subcommand #[derive(Subcommand, Debug, Clone)] pub enum ChainSubcommand { - ///Get current block id from sequencer + /// Get current block id from sequencer CurrentBlockId {}, - ///Get block at id from sequencer + /// Get block at id from sequencer Block { #[arg(short, long)] id: u64, }, - ///Get transaction at hash from sequencer + /// Get transaction at hash from sequencer Transaction { - ///hash - valid 32 byte hex string + /// hash - valid 32 byte hex string #[arg(short, long)] hash: String, }, diff --git a/wallet/src/cli/config.rs b/wallet/src/cli/config.rs index 12bc8b2..c41aa32 100644 --- a/wallet/src/cli/config.rs +++ b/wallet/src/cli/config.rs @@ -3,7 +3,7 @@ use clap::Subcommand; use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand}; -///Represents generic config CLI subcommand +/// Represents generic config CLI subcommand #[derive(Subcommand, Debug, Clone)] pub enum ConfigSubcommand { /// Command to explicitly setup config and storage @@ -14,6 +14,8 @@ pub enum ConfigSubcommand { Get { key: String }, /// Setter of config fields Set { key: String, value: String }, + /// Prints description of corresponding field + Description { key: String }, } impl WalletSubcommand for ConfigSubcommand { @@ -108,6 +110,40 @@ impl WalletSubcommand for ConfigSubcommand { println!("Stored changed config at {path:#?}"); } + ConfigSubcommand::Description { key } => match key.as_str() { + "override_rust_log" => { + println!("Value of variable RUST_LOG to override, affects logging"); + } + "sequencer_addr" => { + println!("HTTP V4 account_id of sequencer"); + } + "seq_poll_timeout_millis" => { + println!( + "Sequencer client retry variable: how much time to wait between retries in milliseconds(can be zero)" + ); + } + "seq_poll_max_blocks" => { + println!( + "Sequencer client polling variable: max number of blocks to poll in parallel" + ); + } + "seq_poll_max_retries" => { + println!( + "Sequencer client retry variable: MAX number of retries before failing(can be zero)" + ); + } + "seq_poll_retry_delay_millis" => { + println!( + "Sequencer client polling variable: how much time to wait in milliseconds between polling retries(can be zero)" + ); + } + "initial_accounts" => { + println!("List of initial accounts' keys(both public and private)"); + } + _ => { + println!("Unknown field"); + } + }, } Ok(SubcommandReturnValue::Empty) diff --git a/wallet/src/cli/native_token_transfer_program.rs b/wallet/src/cli/native_token_transfer_program.rs index e286bb9..f5fdb9a 100644 --- a/wallet/src/cli/native_token_transfer_program.rs +++ b/wallet/src/cli/native_token_transfer_program.rs @@ -1,42 +1,43 @@ use anyhow::Result; use clap::Subcommand; use common::transaction::NSSATransaction; -use nssa::Address; +use nssa::AccountId; use crate::{ SubcommandReturnValue, WalletCore, cli::WalletSubcommand, - helperfunctions::{AddressPrivacyKind, parse_addr_with_privacy_prefix}, + helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix}, }; -///Represents generic CLI subcommand for a wallet working with native token transfer program +/// Represents generic CLI subcommand for a wallet working with native token transfer program #[derive(Subcommand, Debug, Clone)] pub enum AuthTransferSubcommand { - ///Initialize account under authenticated transfer program + /// Initialize account under authenticated transfer program Init { - ///addr - valid 32 byte base58 string with privacy prefix + /// account_id - valid 32 byte base58 string with privacy prefix #[arg(long)] - addr: String, + account_id: String, }, - ///Send native tokens from one account to another with variable privacy + /// Send native tokens from one account to another with variable privacy /// - ///If receiver is private, then `to` and (`to_npk` , `to_ipk`) is a mutually exclusive patterns. + /// If receiver is private, then `to` and (`to_npk` , `to_ipk`) is a mutually exclusive + /// patterns. /// - ///First is used for owned accounts, second otherwise. + /// First is used for owned accounts, second otherwise. Send { - ///from - valid 32 byte base58 string with privacy prefix + /// from - valid 32 byte base58 string with privacy prefix #[arg(long)] from: String, - ///to - valid 32 byte base58 string with privacy prefix + /// to - valid 32 byte base58 string with privacy prefix #[arg(long)] to: Option, - ///to_npk - valid 32 byte hex string + /// to_npk - valid 32 byte hex string #[arg(long)] to_npk: Option, - ///to_ipk - valid 33 byte hex string + /// to_ipk - valid 33 byte hex string #[arg(long)] to_ipk: Option, - ///amount - amount of balance to move + /// amount - amount of balance to move #[arg(long)] amount: u128, }, @@ -48,15 +49,15 @@ impl WalletSubcommand for AuthTransferSubcommand { wallet_core: &mut WalletCore, ) -> Result { match self { - AuthTransferSubcommand::Init { addr } => { - let (addr, addr_privacy) = parse_addr_with_privacy_prefix(&addr)?; + AuthTransferSubcommand::Init { account_id } => { + let (account_id, addr_privacy) = parse_addr_with_privacy_prefix(&account_id)?; match addr_privacy { - AddressPrivacyKind::Public => { - let addr = addr.parse()?; + AccountPrivacyKind::Public => { + let account_id = account_id.parse()?; let res = wallet_core - .register_account_under_authenticated_transfers_programs(addr) + .register_account_under_authenticated_transfers_programs(account_id) .await?; println!("Results of tx send is {res:#?}"); @@ -70,11 +71,13 @@ impl WalletSubcommand for AuthTransferSubcommand { println!("Stored persistent accounts at {path:#?}"); } - AddressPrivacyKind::Private => { - let addr = addr.parse()?; + AccountPrivacyKind::Private => { + let account_id = account_id.parse()?; let (res, [secret]) = wallet_core - .register_account_under_authenticated_transfers_programs_private(addr) + .register_account_under_authenticated_transfers_programs_private( + account_id, + ) .await?; println!("Results of tx send is {res:#?}"); @@ -85,7 +88,7 @@ impl WalletSubcommand for AuthTransferSubcommand { .await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { - let acc_decode_data = vec![(secret, addr)]; + let acc_decode_data = vec![(secret, account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( tx, @@ -111,12 +114,12 @@ impl WalletSubcommand for AuthTransferSubcommand { let underlying_subcommand = match (to, to_npk, to_ipk) { (None, None, None) => { anyhow::bail!( - "Provide either account address of receiver or their public keys" + "Provide either account account_id of receiver or their public keys" ); } (Some(_), Some(_), Some(_)) => { anyhow::bail!( - "Provide only one variant: either account address of receiver or their public keys" + "Provide only one variant: either account account_id of receiver or their public keys" ); } (_, Some(_), None) | (_, None, Some(_)) => { @@ -127,10 +130,10 @@ impl WalletSubcommand for AuthTransferSubcommand { let (to, to_privacy) = parse_addr_with_privacy_prefix(&to)?; match (from_privacy, to_privacy) { - (AddressPrivacyKind::Public, AddressPrivacyKind::Public) => { + (AccountPrivacyKind::Public, AccountPrivacyKind::Public) => { NativeTokenTransferProgramSubcommand::Public { from, to, amount } } - (AddressPrivacyKind::Private, AddressPrivacyKind::Private) => { + (AccountPrivacyKind::Private, AccountPrivacyKind::Private) => { NativeTokenTransferProgramSubcommand::Private( NativeTokenTransferProgramSubcommandPrivate::PrivateOwned { from, @@ -139,14 +142,14 @@ impl WalletSubcommand for AuthTransferSubcommand { }, ) } - (AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { + (AccountPrivacyKind::Private, AccountPrivacyKind::Public) => { NativeTokenTransferProgramSubcommand::Deshielded { from, to, amount, } } - (AddressPrivacyKind::Public, AddressPrivacyKind::Private) => { + (AccountPrivacyKind::Public, AccountPrivacyKind::Private) => { NativeTokenTransferProgramSubcommand::Shielded( NativeTokenTransferProgramSubcommandShielded::ShieldedOwned { from, @@ -161,7 +164,7 @@ impl WalletSubcommand for AuthTransferSubcommand { let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?; match from_privacy { - AddressPrivacyKind::Private => { + AccountPrivacyKind::Private => { NativeTokenTransferProgramSubcommand::Private( NativeTokenTransferProgramSubcommandPrivate::PrivateForeign { from, @@ -171,7 +174,7 @@ impl WalletSubcommand for AuthTransferSubcommand { }, ) } - AddressPrivacyKind::Public => { + AccountPrivacyKind::Public => { NativeTokenTransferProgramSubcommand::Shielded( NativeTokenTransferProgramSubcommandShielded::ShieldedForeign { from, @@ -191,112 +194,114 @@ impl WalletSubcommand for AuthTransferSubcommand { } } -///Represents generic CLI subcommand for a wallet working with native token transfer program +/// Represents generic CLI subcommand for a wallet working with native token transfer program #[derive(Subcommand, Debug, Clone)] pub enum NativeTokenTransferProgramSubcommand { - ///Send native token transfer from `from` to `to` for `amount` + /// Send native token transfer from `from` to `to` for `amount` /// /// Public operation Public { - ///from - valid 32 byte hex string + /// from - valid 32 byte hex string #[arg(long)] from: String, - ///to - valid 32 byte hex string + /// to - valid 32 byte hex string #[arg(long)] to: String, - ///amount - amount of balance to move + /// amount - amount of balance to move #[arg(long)] amount: u128, }, - ///Private execution + /// Private execution #[command(subcommand)] Private(NativeTokenTransferProgramSubcommandPrivate), - ///Send native token transfer from `from` to `to` for `amount` + /// Send native token transfer from `from` to `to` for `amount` /// /// Deshielded operation Deshielded { - ///from - valid 32 byte hex string + /// from - valid 32 byte hex string #[arg(long)] from: String, - ///to - valid 32 byte hex string + /// to - valid 32 byte hex string #[arg(long)] to: String, - ///amount - amount of balance to move + /// amount - amount of balance to move #[arg(long)] amount: u128, }, - ///Shielded execution + /// Shielded execution #[command(subcommand)] Shielded(NativeTokenTransferProgramSubcommandShielded), } -///Represents generic shielded CLI subcommand for a wallet working with native token transfer program +/// Represents generic shielded CLI subcommand for a wallet working with native token transfer +/// program #[derive(Subcommand, Debug, Clone)] pub enum NativeTokenTransferProgramSubcommandShielded { - ///Send native token transfer from `from` to `to` for `amount` + /// Send native token transfer from `from` to `to` for `amount` /// /// Shielded operation ShieldedOwned { - ///from - valid 32 byte hex string + /// from - valid 32 byte hex string #[arg(long)] from: String, - ///to - valid 32 byte hex string + /// to - valid 32 byte hex string #[arg(long)] to: String, - ///amount - amount of balance to move + /// amount - amount of balance to move #[arg(long)] amount: u128, }, - ///Send native token transfer from `from` to `to` for `amount` + /// Send native token transfer from `from` to `to` for `amount` /// /// Shielded operation ShieldedForeign { - ///from - valid 32 byte hex string + /// from - valid 32 byte hex string #[arg(long)] from: String, - ///to_npk - valid 32 byte hex string + /// to_npk - valid 32 byte hex string #[arg(long)] to_npk: String, - ///to_ipk - valid 33 byte hex string + /// to_ipk - valid 33 byte hex string #[arg(long)] to_ipk: String, - ///amount - amount of balance to move + /// amount - amount of balance to move #[arg(long)] amount: u128, }, } -///Represents generic private CLI subcommand for a wallet working with native token transfer program +/// Represents generic private CLI subcommand for a wallet working with native token transfer +/// program #[derive(Subcommand, Debug, Clone)] pub enum NativeTokenTransferProgramSubcommandPrivate { - ///Send native token transfer from `from` to `to` for `amount` + /// Send native token transfer from `from` to `to` for `amount` /// /// Private operation PrivateOwned { - ///from - valid 32 byte hex string + /// from - valid 32 byte hex string #[arg(long)] from: String, - ///to - valid 32 byte hex string + /// to - valid 32 byte hex string #[arg(long)] to: String, - ///amount - amount of balance to move + /// amount - amount of balance to move #[arg(long)] amount: u128, }, - ///Send native token transfer from `from` to `to` for `amount` + /// Send native token transfer from `from` to `to` for `amount` /// /// Private operation PrivateForeign { - ///from - valid 32 byte hex string + /// from - valid 32 byte hex string #[arg(long)] from: String, - ///to_npk - valid 32 byte hex string + /// to_npk - valid 32 byte hex string #[arg(long)] to_npk: String, - ///to_ipk - valid 33 byte hex string + /// to_ipk - valid 33 byte hex string #[arg(long)] to_ipk: String, - ///amount - amount of balance to move + /// amount - amount of balance to move #[arg(long)] amount: u128, }, @@ -309,8 +314,8 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate { ) -> Result { match self { NativeTokenTransferProgramSubcommandPrivate::PrivateOwned { from, to, amount } => { - let from: Address = from.parse().unwrap(); - let to: Address = to.parse().unwrap(); + let from: AccountId = from.parse().unwrap(); + let to: AccountId = to.parse().unwrap(); let to_initialization = wallet_core.check_private_account_initialized(&to).await?; @@ -356,7 +361,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate { to_ipk, amount, } => { - let from: Address = from.parse().unwrap(); + let from: AccountId = from.parse().unwrap(); let to_npk_res = hex::decode(to_npk)?; let mut to_npk = [0; 32]; to_npk.copy_from_slice(&to_npk_res); @@ -405,8 +410,8 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded { ) -> Result { match self { NativeTokenTransferProgramSubcommandShielded::ShieldedOwned { from, to, amount } => { - let from: Address = from.parse().unwrap(); - let to: Address = to.parse().unwrap(); + let from: AccountId = from.parse().unwrap(); + let to: AccountId = to.parse().unwrap(); let to_initialization = wallet_core.check_private_account_initialized(&to).await?; @@ -450,7 +455,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded { to_ipk, amount, } => { - let from: Address = from.parse().unwrap(); + let from: AccountId = from.parse().unwrap(); let to_npk_res = hex::decode(to_npk)?; let mut to_npk = [0; 32]; @@ -494,8 +499,8 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand { shielded_subcommand.handle_subcommand(wallet_core).await } NativeTokenTransferProgramSubcommand::Deshielded { from, to, amount } => { - let from: Address = from.parse().unwrap(); - let to: Address = to.parse().unwrap(); + let from: AccountId = from.parse().unwrap(); + let to: AccountId = to.parse().unwrap(); let (res, [secret]) = wallet_core .send_deshielded_native_token_transfer(from, to, amount) @@ -524,8 +529,8 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand { Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) } NativeTokenTransferProgramSubcommand::Public { from, to, amount } => { - let from: Address = from.parse().unwrap(); - let to: Address = to.parse().unwrap(); + let from: AccountId = from.parse().unwrap(); + let to: AccountId = to.parse().unwrap(); let res = wallet_core .send_public_native_token_transfer(from, to, amount) diff --git a/wallet/src/cli/pinata_program.rs b/wallet/src/cli/pinata_program.rs index fafd5f1..cc71a51 100644 --- a/wallet/src/cli/pinata_program.rs +++ b/wallet/src/cli/pinata_program.rs @@ -6,18 +6,18 @@ use log::info; use crate::{ SubcommandReturnValue, WalletCore, cli::WalletSubcommand, - helperfunctions::{AddressPrivacyKind, parse_addr_with_privacy_prefix}, + helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix}, }; -///Represents generic CLI subcommand for a wallet working with pinata program +/// Represents generic CLI subcommand for a wallet working with pinata program #[derive(Subcommand, Debug, Clone)] pub enum PinataProgramAgnosticSubcommand { - ///Claim pinata + /// Claim pinata Claim { - ///to_addr - valid 32 byte base58 string with privacy prefix + /// to_account_id - valid 32 byte base58 string with privacy prefix #[arg(long)] - to_addr: String, - ///solution - solution to pinata challenge + to_account_id: String, + /// solution - solution to pinata challenge #[arg(long)] solution: u128, }, @@ -29,21 +29,25 @@ impl WalletSubcommand for PinataProgramAgnosticSubcommand { wallet_core: &mut WalletCore, ) -> Result { let underlying_subcommand = match self { - PinataProgramAgnosticSubcommand::Claim { to_addr, solution } => { - let (to_addr, to_addr_privacy) = parse_addr_with_privacy_prefix(&to_addr)?; + PinataProgramAgnosticSubcommand::Claim { + to_account_id, + solution, + } => { + let (to_account_id, to_addr_privacy) = + parse_addr_with_privacy_prefix(&to_account_id)?; match to_addr_privacy { - AddressPrivacyKind::Public => { + AccountPrivacyKind::Public => { PinataProgramSubcommand::Public(PinataProgramSubcommandPublic::Claim { - pinata_addr: PINATA_BASE58.to_string(), - winner_addr: to_addr, + pinata_account_id: PINATA_BASE58.to_string(), + winner_account_id: to_account_id, solution, }) } - AddressPrivacyKind::Private => PinataProgramSubcommand::Private( + AccountPrivacyKind::Private => PinataProgramSubcommand::Private( PinataProgramSubcommandPrivate::ClaimPrivateOwned { - pinata_addr: PINATA_BASE58.to_string(), - winner_addr: to_addr, + pinata_account_id: PINATA_BASE58.to_string(), + winner_account_id: to_account_id, solution, }, ), @@ -55,48 +59,48 @@ impl WalletSubcommand for PinataProgramAgnosticSubcommand { } } -///Represents generic CLI subcommand for a wallet working with pinata program +/// Represents generic CLI subcommand for a wallet working with pinata program #[derive(Subcommand, Debug, Clone)] pub enum PinataProgramSubcommand { - ///Public execution + /// Public execution #[command(subcommand)] Public(PinataProgramSubcommandPublic), - ///Private execution + /// Private execution #[command(subcommand)] Private(PinataProgramSubcommandPrivate), } -///Represents generic public CLI subcommand for a wallet working with pinata program +/// Represents generic public CLI subcommand for a wallet working with pinata program #[derive(Subcommand, Debug, Clone)] pub enum PinataProgramSubcommandPublic { // TODO: Testnet only. Refactor to prevent compilation on mainnet. // Claim piñata prize Claim { - ///pinata_addr - valid 32 byte hex string + /// pinata_account_id - valid 32 byte hex string #[arg(long)] - pinata_addr: String, - ///winner_addr - valid 32 byte hex string + pinata_account_id: String, + /// winner_account_id - valid 32 byte hex string #[arg(long)] - winner_addr: String, - ///solution - solution to pinata challenge + winner_account_id: String, + /// solution - solution to pinata challenge #[arg(long)] solution: u128, }, } -///Represents generic private CLI subcommand for a wallet working with pinata program +/// Represents generic private CLI subcommand for a wallet working with pinata program #[derive(Subcommand, Debug, Clone)] pub enum PinataProgramSubcommandPrivate { // TODO: Testnet only. Refactor to prevent compilation on mainnet. // Claim piñata prize ClaimPrivateOwned { - ///pinata_addr - valid 32 byte hex string + /// pinata_account_id - valid 32 byte hex string #[arg(long)] - pinata_addr: String, - ///winner_addr - valid 32 byte hex string + pinata_account_id: String, + /// winner_account_id - valid 32 byte hex string #[arg(long)] - winner_addr: String, - ///solution - solution to pinata challenge + winner_account_id: String, + /// solution - solution to pinata challenge #[arg(long)] solution: u128, }, @@ -109,14 +113,14 @@ impl WalletSubcommand for PinataProgramSubcommandPublic { ) -> Result { match self { PinataProgramSubcommandPublic::Claim { - pinata_addr, - winner_addr, + pinata_account_id, + winner_account_id, solution, } => { let res = wallet_core .claim_pinata( - pinata_addr.parse().unwrap(), - winner_addr.parse().unwrap(), + pinata_account_id.parse().unwrap(), + winner_account_id.parse().unwrap(), solution, ) .await?; @@ -135,22 +139,22 @@ impl WalletSubcommand for PinataProgramSubcommandPrivate { ) -> Result { match self { PinataProgramSubcommandPrivate::ClaimPrivateOwned { - pinata_addr, - winner_addr, + pinata_account_id, + winner_account_id, solution, } => { - let pinata_addr = pinata_addr.parse().unwrap(); - let winner_addr = winner_addr.parse().unwrap(); + let pinata_account_id = pinata_account_id.parse().unwrap(); + let winner_account_id = winner_account_id.parse().unwrap(); let winner_initialization = wallet_core - .check_private_account_initialized(&winner_addr) + .check_private_account_initialized(&winner_account_id) .await?; let (res, [secret_winner]) = if let Some(winner_proof) = winner_initialization { wallet_core .claim_pinata_private_owned_account_already_initialized( - pinata_addr, - winner_addr, + pinata_account_id, + winner_account_id, solution, winner_proof, ) @@ -158,8 +162,8 @@ impl WalletSubcommand for PinataProgramSubcommandPrivate { } else { wallet_core .claim_pinata_private_owned_account_not_initialized( - pinata_addr, - winner_addr, + pinata_account_id, + winner_account_id, solution, ) .await? @@ -173,7 +177,7 @@ impl WalletSubcommand for PinataProgramSubcommandPrivate { .await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { - let acc_decode_data = vec![(secret_winner, winner_addr)]; + let acc_decode_data = vec![(secret_winner, winner_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( tx, diff --git a/wallet/src/cli/token_program.rs b/wallet/src/cli/token_program.rs index 6ce7dbe..b412e2f 100644 --- a/wallet/src/cli/token_program.rs +++ b/wallet/src/cli/token_program.rs @@ -1,51 +1,52 @@ use anyhow::Result; use clap::Subcommand; use common::transaction::NSSATransaction; -use nssa::Address; +use nssa::AccountId; use crate::{ SubcommandReturnValue, WalletCore, cli::WalletSubcommand, - helperfunctions::{AddressPrivacyKind, parse_addr_with_privacy_prefix}, + helperfunctions::{AccountPrivacyKind, parse_addr_with_privacy_prefix}, }; -///Represents generic CLI subcommand for a wallet working with token program +/// Represents generic CLI subcommand for a wallet working with token program #[derive(Subcommand, Debug, Clone)] pub enum TokenProgramAgnosticSubcommand { - ///Produce a new token + /// Produce a new token /// - ///Currently the only supported privacy options is for public definition + /// Currently the only supported privacy options is for public definition New { - ///definition_addr - valid 32 byte base58 string with privacy prefix + /// definition_account_id - valid 32 byte base58 string with privacy prefix #[arg(long)] - definition_addr: String, - ///supply_addr - valid 32 byte base58 string with privacy prefix + definition_account_id: String, + /// supply_account_id - valid 32 byte base58 string with privacy prefix #[arg(long)] - supply_addr: String, + supply_account_id: String, #[arg(short, long)] name: String, #[arg(short, long)] total_supply: u128, }, - ///Send tokens from one account to another with variable privacy + /// Send tokens from one account to another with variable privacy /// - ///If receiver is private, then `to` and (`to_npk` , `to_ipk`) is a mutually exclusive patterns. + /// If receiver is private, then `to` and (`to_npk` , `to_ipk`) is a mutually exclusive + /// patterns. /// - ///First is used for owned accounts, second otherwise. + /// First is used for owned accounts, second otherwise. Send { - ///from - valid 32 byte base58 string with privacy prefix + /// from - valid 32 byte base58 string with privacy prefix #[arg(long)] from: String, - ///to - valid 32 byte base58 string with privacy prefix + /// to - valid 32 byte base58 string with privacy prefix #[arg(long)] to: Option, - ///to_npk - valid 32 byte hex string + /// to_npk - valid 32 byte hex string #[arg(long)] to_npk: Option, - ///to_ipk - valid 33 byte hex string + /// to_ipk - valid 33 byte hex string #[arg(long)] to_ipk: Option, - ///amount - amount of balance to move + /// amount - amount of balance to move #[arg(long)] amount: u128, }, @@ -58,43 +59,45 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { ) -> Result { match self { TokenProgramAgnosticSubcommand::New { - definition_addr, - supply_addr, + definition_account_id, + supply_account_id, name, total_supply, } => { - let (definition_addr, definition_addr_privacy) = - parse_addr_with_privacy_prefix(&definition_addr)?; - let (supply_addr, supply_addr_privacy) = - parse_addr_with_privacy_prefix(&supply_addr)?; + let (definition_account_id, definition_addr_privacy) = + parse_addr_with_privacy_prefix(&definition_account_id)?; + let (supply_account_id, supply_addr_privacy) = + parse_addr_with_privacy_prefix(&supply_account_id)?; let underlying_subcommand = match (definition_addr_privacy, supply_addr_privacy) { - (AddressPrivacyKind::Public, AddressPrivacyKind::Public) => { + (AccountPrivacyKind::Public, AccountPrivacyKind::Public) => { TokenProgramSubcommand::Public( TokenProgramSubcommandPublic::CreateNewToken { - definition_addr, - supply_addr, + definition_account_id, + supply_account_id, name, total_supply, }, ) } - (AddressPrivacyKind::Public, AddressPrivacyKind::Private) => { + (AccountPrivacyKind::Public, AccountPrivacyKind::Private) => { TokenProgramSubcommand::Private( TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned { - definition_addr, - supply_addr, + definition_account_id, + supply_account_id, name, total_supply, }, ) } - (AddressPrivacyKind::Private, AddressPrivacyKind::Private) => { - //ToDo: maybe implement this one. It is not immediately clear why definition should be private. + (AccountPrivacyKind::Private, AccountPrivacyKind::Private) => { + // ToDo: maybe implement this one. It is not immediately clear why + // definition should be private. anyhow::bail!("Unavailable privacy pairing") } - (AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { - //ToDo: Probably valid. If definition is not public, but supply is it is very suspicious. + (AccountPrivacyKind::Private, AccountPrivacyKind::Public) => { + // ToDo: Probably valid. If definition is not public, but supply is it is + // very suspicious. anyhow::bail!("Unavailable privacy pairing") } }; @@ -111,12 +114,12 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { let underlying_subcommand = match (to, to_npk, to_ipk) { (None, None, None) => { anyhow::bail!( - "Provide either account address of receiver or their public keys" + "Provide either account account_id of receiver or their public keys" ); } (Some(_), Some(_), Some(_)) => { anyhow::bail!( - "Provide only one variant: either account address of receiver or their public keys" + "Provide only one variant: either account account_id of receiver or their public keys" ); } (_, Some(_), None) | (_, None, Some(_)) => { @@ -127,38 +130,38 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { let (to, to_privacy) = parse_addr_with_privacy_prefix(&to)?; match (from_privacy, to_privacy) { - (AddressPrivacyKind::Public, AddressPrivacyKind::Public) => { + (AccountPrivacyKind::Public, AccountPrivacyKind::Public) => { TokenProgramSubcommand::Public( TokenProgramSubcommandPublic::TransferToken { - sender_addr: from, - recipient_addr: to, + sender_account_id: from, + recipient_account_id: to, balance_to_move: amount, }, ) } - (AddressPrivacyKind::Private, AddressPrivacyKind::Private) => { + (AccountPrivacyKind::Private, AccountPrivacyKind::Private) => { TokenProgramSubcommand::Private( TokenProgramSubcommandPrivate::TransferTokenPrivateOwned { - sender_addr: from, - recipient_addr: to, + sender_account_id: from, + recipient_account_id: to, balance_to_move: amount, }, ) } - (AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { + (AccountPrivacyKind::Private, AccountPrivacyKind::Public) => { TokenProgramSubcommand::Deshielded( TokenProgramSubcommandDeshielded::TransferTokenDeshielded { - sender_addr: from, - recipient_addr: to, + sender_account_id: from, + recipient_account_id: to, balance_to_move: amount, }, ) } - (AddressPrivacyKind::Public, AddressPrivacyKind::Private) => { + (AccountPrivacyKind::Public, AccountPrivacyKind::Private) => { TokenProgramSubcommand::Shielded( TokenProgramSubcommandShielded::TransferTokenShieldedOwned { - sender_addr: from, - recipient_addr: to, + sender_account_id: from, + recipient_account_id: to, balance_to_move: amount, }, ) @@ -169,17 +172,17 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?; match from_privacy { - AddressPrivacyKind::Private => TokenProgramSubcommand::Private( + AccountPrivacyKind::Private => TokenProgramSubcommand::Private( TokenProgramSubcommandPrivate::TransferTokenPrivateForeign { - sender_addr: from, + sender_account_id: from, recipient_npk: to_npk, recipient_ipk: to_ipk, balance_to_move: amount, }, ), - AddressPrivacyKind::Public => TokenProgramSubcommand::Shielded( + AccountPrivacyKind::Public => TokenProgramSubcommand::Shielded( TokenProgramSubcommandShielded::TransferTokenShieldedForeign { - sender_addr: from, + sender_account_id: from, recipient_npk: to_npk, recipient_ipk: to_ipk, balance_to_move: amount, @@ -195,79 +198,79 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand { } } -///Represents generic CLI subcommand for a wallet working with token_program +/// Represents generic CLI subcommand for a wallet working with token_program #[derive(Subcommand, Debug, Clone)] pub enum TokenProgramSubcommand { - ///Public execution + /// Public execution #[command(subcommand)] Public(TokenProgramSubcommandPublic), - ///Private execution + /// Private execution #[command(subcommand)] Private(TokenProgramSubcommandPrivate), - ///Deshielded execution + /// Deshielded execution #[command(subcommand)] Deshielded(TokenProgramSubcommandDeshielded), - ///Shielded execution + /// Shielded execution #[command(subcommand)] Shielded(TokenProgramSubcommandShielded), } -///Represents generic public CLI subcommand for a wallet working with token_program +/// Represents generic public CLI subcommand for a wallet working with token_program #[derive(Subcommand, Debug, Clone)] pub enum TokenProgramSubcommandPublic { - //Create a new token using the token program + // Create a new token using the token program CreateNewToken { #[arg(short, long)] - definition_addr: String, + definition_account_id: String, #[arg(short, long)] - supply_addr: String, + supply_account_id: String, #[arg(short, long)] name: String, #[arg(short, long)] total_supply: u128, }, - //Transfer tokens using the token program + // Transfer tokens using the token program TransferToken { #[arg(short, long)] - sender_addr: String, + sender_account_id: String, #[arg(short, long)] - recipient_addr: String, + recipient_account_id: String, #[arg(short, long)] balance_to_move: u128, }, } -///Represents generic private CLI subcommand for a wallet working with token_program +/// Represents generic private CLI subcommand for a wallet working with token_program #[derive(Subcommand, Debug, Clone)] pub enum TokenProgramSubcommandPrivate { - //Create a new token using the token program + // Create a new token using the token program CreateNewTokenPrivateOwned { #[arg(short, long)] - definition_addr: String, + definition_account_id: String, #[arg(short, long)] - supply_addr: String, + supply_account_id: String, #[arg(short, long)] name: String, #[arg(short, long)] total_supply: u128, }, - //Transfer tokens using the token program + // Transfer tokens using the token program TransferTokenPrivateOwned { #[arg(short, long)] - sender_addr: String, + sender_account_id: String, #[arg(short, long)] - recipient_addr: String, + recipient_account_id: String, #[arg(short, long)] balance_to_move: u128, }, - //Transfer tokens using the token program + // Transfer tokens using the token program TransferTokenPrivateForeign { #[arg(short, long)] - sender_addr: String, - ///recipient_npk - valid 32 byte hex string + sender_account_id: String, + /// recipient_npk - valid 32 byte hex string #[arg(long)] recipient_npk: String, - ///recipient_ipk - valid 33 byte hex string + /// recipient_ipk - valid 33 byte hex string #[arg(long)] recipient_ipk: String, #[arg(short, long)] @@ -275,40 +278,40 @@ pub enum TokenProgramSubcommandPrivate { }, } -///Represents deshielded public CLI subcommand for a wallet working with token_program +/// Represents deshielded public CLI subcommand for a wallet working with token_program #[derive(Subcommand, Debug, Clone)] pub enum TokenProgramSubcommandDeshielded { - //Transfer tokens using the token program + // Transfer tokens using the token program TransferTokenDeshielded { #[arg(short, long)] - sender_addr: String, + sender_account_id: String, #[arg(short, long)] - recipient_addr: String, + recipient_account_id: String, #[arg(short, long)] balance_to_move: u128, }, } -///Represents generic shielded CLI subcommand for a wallet working with token_program +/// Represents generic shielded CLI subcommand for a wallet working with token_program #[derive(Subcommand, Debug, Clone)] pub enum TokenProgramSubcommandShielded { - //Transfer tokens using the token program + // Transfer tokens using the token program TransferTokenShieldedOwned { #[arg(short, long)] - sender_addr: String, + sender_account_id: String, #[arg(short, long)] - recipient_addr: String, + recipient_account_id: String, #[arg(short, long)] balance_to_move: u128, }, - //Transfer tokens using the token program + // Transfer tokens using the token program TransferTokenShieldedForeign { #[arg(short, long)] - sender_addr: String, - ///recipient_npk - valid 32 byte hex string + sender_account_id: String, + /// recipient_npk - valid 32 byte hex string #[arg(long)] recipient_npk: String, - ///recipient_ipk - valid 33 byte hex string + /// recipient_ipk - valid 33 byte hex string #[arg(long)] recipient_ipk: String, #[arg(short, long)] @@ -323,8 +326,8 @@ impl WalletSubcommand for TokenProgramSubcommandPublic { ) -> Result { match self { TokenProgramSubcommandPublic::CreateNewToken { - definition_addr, - supply_addr, + definition_account_id, + supply_account_id, name, total_supply, } => { @@ -337,8 +340,8 @@ impl WalletSubcommand for TokenProgramSubcommandPublic { name_bytes[..name.len()].copy_from_slice(name); wallet_core .send_new_token_definition( - definition_addr.parse().unwrap(), - supply_addr.parse().unwrap(), + definition_account_id.parse().unwrap(), + supply_account_id.parse().unwrap(), name_bytes, total_supply, ) @@ -346,14 +349,14 @@ impl WalletSubcommand for TokenProgramSubcommandPublic { Ok(SubcommandReturnValue::Empty) } TokenProgramSubcommandPublic::TransferToken { - sender_addr, - recipient_addr, + sender_account_id, + recipient_account_id, balance_to_move, } => { wallet_core .send_transfer_token_transaction( - sender_addr.parse().unwrap(), - recipient_addr.parse().unwrap(), + sender_account_id.parse().unwrap(), + recipient_account_id.parse().unwrap(), balance_to_move, ) .await?; @@ -370,8 +373,8 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { ) -> Result { match self { TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned { - definition_addr, - supply_addr, + definition_account_id, + supply_account_id, name, total_supply, } => { @@ -383,13 +386,13 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { let mut name_bytes = [0; 6]; name_bytes[..name.len()].copy_from_slice(name); - let definition_addr: Address = definition_addr.parse().unwrap(); - let supply_addr: Address = supply_addr.parse().unwrap(); + let definition_account_id: AccountId = definition_account_id.parse().unwrap(); + let supply_account_id: AccountId = supply_account_id.parse().unwrap(); let (res, [secret_supply]) = wallet_core .send_new_token_definition_private_owned( - definition_addr, - supply_addr, + definition_account_id, + supply_account_id, name_bytes, total_supply, ) @@ -403,7 +406,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { .await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { - let acc_decode_data = vec![(secret_supply, supply_addr)]; + let acc_decode_data = vec![(secret_supply, supply_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( tx, @@ -418,23 +421,23 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) } TokenProgramSubcommandPrivate::TransferTokenPrivateOwned { - sender_addr, - recipient_addr, + sender_account_id, + recipient_account_id, balance_to_move, } => { - let sender_addr: Address = sender_addr.parse().unwrap(); - let recipient_addr: Address = recipient_addr.parse().unwrap(); + let sender_account_id: AccountId = sender_account_id.parse().unwrap(); + let recipient_account_id: AccountId = recipient_account_id.parse().unwrap(); let recipient_initialization = wallet_core - .check_private_account_initialized(&recipient_addr) + .check_private_account_initialized(&recipient_account_id) .await?; let (res, [secret_sender, secret_recipient]) = if let Some(recipient_proof) = recipient_initialization { wallet_core .send_transfer_token_transaction_private_owned_account_already_initialized( - sender_addr, - recipient_addr, + sender_account_id, + recipient_account_id, balance_to_move, recipient_proof, ) @@ -442,8 +445,8 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { } else { wallet_core .send_transfer_token_transaction_private_owned_account_not_initialized( - sender_addr, - recipient_addr, + sender_account_id, + recipient_account_id, balance_to_move, ) .await? @@ -458,8 +461,8 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { let acc_decode_data = vec![ - (secret_sender, sender_addr), - (secret_recipient, recipient_addr), + (secret_sender, sender_account_id), + (secret_recipient, recipient_account_id), ]; wallet_core.decode_insert_privacy_preserving_transaction_results( @@ -475,12 +478,12 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) } TokenProgramSubcommandPrivate::TransferTokenPrivateForeign { - sender_addr, + sender_account_id, recipient_npk, recipient_ipk, balance_to_move, } => { - let sender_addr: Address = sender_addr.parse().unwrap(); + let sender_account_id: AccountId = sender_account_id.parse().unwrap(); let recipient_npk_res = hex::decode(recipient_npk)?; let mut recipient_npk = [0; 32]; recipient_npk.copy_from_slice(&recipient_npk_res); @@ -495,7 +498,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { let (res, [secret_sender, _]) = wallet_core .send_transfer_token_transaction_private_foreign_account( - sender_addr, + sender_account_id, recipient_npk, recipient_ipk, balance_to_move, @@ -510,7 +513,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate { .await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { - let acc_decode_data = vec![(secret_sender, sender_addr)]; + let acc_decode_data = vec![(secret_sender, sender_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( tx, @@ -535,17 +538,17 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { ) -> Result { match self { TokenProgramSubcommandDeshielded::TransferTokenDeshielded { - sender_addr, - recipient_addr, + sender_account_id, + recipient_account_id, balance_to_move, } => { - let sender_addr: Address = sender_addr.parse().unwrap(); - let recipient_addr: Address = recipient_addr.parse().unwrap(); + let sender_account_id: AccountId = sender_account_id.parse().unwrap(); + let recipient_account_id: AccountId = recipient_account_id.parse().unwrap(); let (res, [secret_sender]) = wallet_core .send_transfer_token_transaction_deshielded( - sender_addr, - recipient_addr, + sender_account_id, + recipient_account_id, balance_to_move, ) .await?; @@ -558,7 +561,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded { .await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { - let acc_decode_data = vec![(secret_sender, sender_addr)]; + let acc_decode_data = vec![(secret_sender, sender_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( tx, @@ -583,12 +586,12 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { ) -> Result { match self { TokenProgramSubcommandShielded::TransferTokenShieldedForeign { - sender_addr, + sender_account_id, recipient_npk, recipient_ipk, balance_to_move, } => { - let sender_addr: Address = sender_addr.parse().unwrap(); + let sender_account_id: AccountId = sender_account_id.parse().unwrap(); let recipient_npk_res = hex::decode(recipient_npk)?; let mut recipient_npk = [0; 32]; recipient_npk.copy_from_slice(&recipient_npk_res); @@ -603,7 +606,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { let res = wallet_core .send_transfer_token_transaction_shielded_foreign_account( - sender_addr, + sender_account_id, recipient_npk, recipient_ipk, balance_to_move, @@ -628,23 +631,23 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) } TokenProgramSubcommandShielded::TransferTokenShieldedOwned { - sender_addr, - recipient_addr, + sender_account_id, + recipient_account_id, balance_to_move, } => { - let sender_addr: Address = sender_addr.parse().unwrap(); - let recipient_addr: Address = recipient_addr.parse().unwrap(); + let sender_account_id: AccountId = sender_account_id.parse().unwrap(); + let recipient_account_id: AccountId = recipient_account_id.parse().unwrap(); let recipient_initialization = wallet_core - .check_private_account_initialized(&recipient_addr) + .check_private_account_initialized(&recipient_account_id) .await?; let (res, [secret_recipient]) = if let Some(recipient_proof) = recipient_initialization { wallet_core .send_transfer_token_transaction_shielded_owned_account_already_initialized( - sender_addr, - recipient_addr, + sender_account_id, + recipient_account_id, balance_to_move, recipient_proof, ) @@ -652,8 +655,8 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { } else { wallet_core .send_transfer_token_transaction_shielded_owned_account_not_initialized( - sender_addr, - recipient_addr, + sender_account_id, + recipient_account_id, balance_to_move, ) .await? @@ -667,7 +670,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded { .await?; if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { - let acc_decode_data = vec![(secret_recipient, recipient_addr)]; + let acc_decode_data = vec![(secret_recipient, recipient_account_id)]; wallet_core.decode_insert_privacy_preserving_transaction_results( tx, diff --git a/wallet/src/config.rs b/wallet/src/config.rs index f5bd3ea..e11359e 100644 --- a/wallet/src/config.rs +++ b/wallet/src/config.rs @@ -8,33 +8,34 @@ use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct InitialAccountDataPublic { - pub address: String, + pub account_id: String, pub pub_sign_key: nssa::PrivateKey, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PersistentAccountDataPublic { - pub address: nssa::Address, + pub account_id: nssa::AccountId, pub chain_index: ChainIndex, pub data: ChildKeysPublic, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct InitialAccountDataPrivate { - pub address: String, + pub account_id: String, pub account: nssa_core::account::Account, pub key_chain: KeyChain, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct PersistentAccountDataPrivate { - pub address: nssa::Address, + pub account_id: nssa::AccountId, pub chain_index: ChainIndex, pub data: ChildKeysPrivate, } -//Big difference in enum variants sizes -//however it is improbable, that we will have that much accounts, that it will substantialy affect memory +// Big difference in enum variants sizes +// however it is improbable, that we will have that much accounts, that it will substantialy affect +// memory #[allow(clippy::large_enum_variant)] #[derive(Debug, Clone, Serialize, Deserialize)] pub enum InitialAccountData { @@ -42,8 +43,9 @@ pub enum InitialAccountData { Private(InitialAccountDataPrivate), } -//Big difference in enum variants sizes -//however it is improbable, that we will have that much accounts, that it will substantialy affect memory +// Big difference in enum variants sizes +// however it is improbable, that we will have that much accounts, that it will substantialy affect +// memory #[allow(clippy::large_enum_variant)] #[derive(Debug, Clone, Serialize, Deserialize)] pub enum PersistentAccountData { @@ -59,20 +61,20 @@ pub struct PersistentStorage { } impl InitialAccountData { - pub fn address(&self) -> nssa::Address { + pub fn account_id(&self) -> nssa::AccountId { match &self { - Self::Public(acc) => acc.address.parse().unwrap(), - Self::Private(acc) => acc.address.parse().unwrap(), + Self::Public(acc) => acc.account_id.parse().unwrap(), + Self::Private(acc) => acc.account_id.parse().unwrap(), } } } impl PersistentAccountData { - pub fn address(&self) -> nssa::Address { + pub fn account_id(&self) -> nssa::AccountId { match &self { - Self::Public(acc) => acc.address, - Self::Private(acc) => acc.address, - Self::Preconfigured(acc) => acc.address(), + Self::Public(acc) => acc.account_id, + Self::Private(acc) => acc.account_id, + Self::Preconfigured(acc) => acc.account_id(), } } } @@ -127,19 +129,19 @@ pub struct GasConfig { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WalletConfig { - ///Override rust log (env var logging level) + /// Override rust log (env var logging level) pub override_rust_log: Option, - ///Sequencer URL + /// Sequencer URL pub sequencer_addr: String, - ///Sequencer polling duration for new blocks in milliseconds + /// Sequencer polling duration for new blocks in milliseconds pub seq_poll_timeout_millis: u64, - ///Sequencer polling max number of blocks + /// Sequencer polling max number of blocks pub seq_poll_max_blocks: usize, - ///Sequencer polling max number error retries + /// Sequencer polling max number error retries pub seq_poll_max_retries: u64, - ///Sequencer polling error retry delay in milliseconds + /// Sequencer polling error retry delay in milliseconds pub seq_poll_retry_delay_millis: u64, - ///Initial accounts for wallet + /// Initial accounts for wallet pub initial_accounts: Vec, } @@ -157,7 +159,7 @@ impl Default for WalletConfig { [ { "Public": { - "address": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", + "account_id": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", "pub_sign_key": [ 16, 162, @@ -196,7 +198,7 @@ impl Default for WalletConfig { }, { "Public": { - "address": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", + "account_id": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", "pub_sign_key": [ 113, 121, @@ -235,7 +237,7 @@ impl Default for WalletConfig { }, { "Private": { - "address": "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw", + "account_id": "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw", "account": { "program_owner": [ 0, @@ -464,7 +466,7 @@ impl Default for WalletConfig { }, { "Private": { - "address": "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX", + "account_id": "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX", "account": { "program_owner": [ 0, diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index 0d08348..770d2bb 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -1,13 +1,13 @@ -use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; -use nssa_core::account::Nonce; -use rand::{RngCore, rngs::OsRng}; use std::{path::PathBuf, str::FromStr}; -use tokio::io::{AsyncReadExt, AsyncWriteExt}; use anyhow::Result; +use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; use key_protocol::key_protocol_core::NSSAUserData; use nssa::Account; +use nssa_core::account::Nonce; +use rand::{RngCore, rngs::OsRng}; use serde::Serialize; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; use crate::{ HOME_DIR_ENV_VAR, @@ -91,7 +91,7 @@ pub async fn fetch_config() -> Result { /// Fetch data stored at home /// -/// If file not present, it is considered as empty list of persistent accounts +/// File must be created through setup beforehand. pub async fn fetch_persistent_storage() -> Result { let home = get_home()?; let accs_path = home.join("storage.json"); @@ -120,11 +120,11 @@ pub fn produce_data_for_storage( ) -> PersistentStorage { let mut vec_for_storage = vec![]; - for (addr, key) in &user_data.public_key_tree.addr_map { + for (account_id, key) in &user_data.public_key_tree.account_id_map { if let Some(data) = user_data.public_key_tree.key_map.get(key) { vec_for_storage.push( PersistentAccountDataPublic { - address: *addr, + account_id: *account_id, chain_index: key.clone(), data: data.clone(), } @@ -133,11 +133,11 @@ pub fn produce_data_for_storage( } } - for (addr, key) in &user_data.private_key_tree.addr_map { + for (account_id, key) in &user_data.private_key_tree.account_id_map { if let Some(data) = user_data.private_key_tree.key_map.get(key) { vec_for_storage.push( PersistentAccountDataPrivate { - address: *addr, + account_id: *account_id, chain_index: key.clone(), data: data.clone(), } @@ -146,20 +146,20 @@ pub fn produce_data_for_storage( } } - for (addr, key) in &user_data.default_pub_account_signing_keys { + for (account_id, key) in &user_data.default_pub_account_signing_keys { vec_for_storage.push( InitialAccountData::Public(InitialAccountDataPublic { - address: addr.to_string(), + account_id: account_id.to_string(), pub_sign_key: key.clone(), }) .into(), ) } - for (addr, (key_chain, account)) in &user_data.default_user_private_accounts { + for (account_id, (key_chain, account)) in &user_data.default_user_private_accounts { vec_for_storage.push( InitialAccountData::Private(InitialAccountDataPrivate { - address: addr.to_string(), + account_id: account_id.to_string(), account: account.clone(), key_chain: key_chain.clone(), }) @@ -180,23 +180,23 @@ pub(crate) fn produce_random_nonces(size: usize) -> Vec { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum AddressPrivacyKind { +pub enum AccountPrivacyKind { Public, Private, } pub(crate) fn parse_addr_with_privacy_prefix( - addr_base58: &str, -) -> Result<(String, AddressPrivacyKind)> { - if addr_base58.starts_with("Public/") { + account_base58: &str, +) -> Result<(String, AccountPrivacyKind)> { + if account_base58.starts_with("Public/") { Ok(( - addr_base58.strip_prefix("Public/").unwrap().to_string(), - AddressPrivacyKind::Public, + account_base58.strip_prefix("Public/").unwrap().to_string(), + AccountPrivacyKind::Public, )) - } else if addr_base58.starts_with("Private/") { + } else if account_base58.starts_with("Private/") { Ok(( - addr_base58.strip_prefix("Private/").unwrap().to_string(), - AddressPrivacyKind::Private, + account_base58.strip_prefix("Private/").unwrap().to_string(), + AccountPrivacyKind::Private, )) } else { anyhow::bail!("Unsupported privacy kind, available variants is Public/ and Private/"); @@ -249,12 +249,12 @@ mod tests { let addr_base58 = "Public/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy"; let (_, addr_kind) = parse_addr_with_privacy_prefix(addr_base58).unwrap(); - assert_eq!(addr_kind, AddressPrivacyKind::Public); + assert_eq!(addr_kind, AccountPrivacyKind::Public); let addr_base58 = "Private/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy"; let (_, addr_kind) = parse_addr_with_privacy_prefix(addr_base58).unwrap(); - assert_eq!(addr_kind, AddressPrivacyKind::Private); + assert_eq!(addr_kind, AccountPrivacyKind::Private); let addr_base58 = "asdsada/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy"; assert!(parse_addr_with_privacy_prefix(addr_base58).is_err()); diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 8949e7b..6f41d37 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -1,23 +1,21 @@ use std::{path::PathBuf, sync::Arc}; +use anyhow::Result; use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; +use chain_storage::WalletChainStore; +use clap::{Parser, Subcommand}; use common::{ block::HashableBlockData, sequencer_client::SequencerClient, transaction::{EncodedTransaction, NSSATransaction}, }; - -use anyhow::Result; -use chain_storage::WalletChainStore; use config::WalletConfig; use key_protocol::key_management::key_tree::{chain_index::ChainIndex, traits::KeyNode}; use log::info; use nssa::{ - Account, Address, privacy_preserving_transaction::message::EncryptedAccountData, + Account, AccountId, privacy_preserving_transaction::message::EncryptedAccountData, program::Program, }; - -use clap::{Parser, Subcommand}; use nssa_core::{Commitment, MembershipProof}; use tokio::io::AsyncWriteExt; @@ -29,10 +27,7 @@ use crate::{ token_program::TokenProgramAgnosticSubcommand, }, config::PersistentStorage, - helperfunctions::fetch_persistent_storage, -}; -use crate::{ - helperfunctions::{fetch_config, get_home, produce_data_for_storage}, + helperfunctions::{fetch_config, fetch_persistent_storage, get_home, produce_data_for_storage}, poller::TxPoller, }; @@ -92,7 +87,7 @@ impl WalletCore { }) } - ///Store persistent data at home + /// Store persistent data at home pub async fn store_persistent_data(&self) -> Result { let home = get_home()?; let storage_path = home.join("storage.json"); @@ -108,7 +103,7 @@ impl WalletCore { Ok(storage_path) } - ///Store persistent data at home + /// Store persistent data at home pub async fn store_config_changes(&self) -> Result { let home = get_home()?; let config_path = home.join("wallet_config.json"); @@ -122,20 +117,20 @@ impl WalletCore { Ok(config_path) } - pub fn create_new_account_public(&mut self, chain_index: ChainIndex) -> Address { + pub fn create_new_account_public(&mut self, chain_index: ChainIndex) -> AccountId { self.storage .user_data .generate_new_public_transaction_private_key(chain_index) } - pub fn create_new_account_private(&mut self, chain_index: ChainIndex) -> Address { + pub fn create_new_account_private(&mut self, chain_index: ChainIndex) -> AccountId { self.storage .user_data .generate_new_privacy_preserving_transaction_key_chain(chain_index) } - ///Get account balance - pub async fn get_account_balance(&self, acc: Address) -> Result { + /// Get account balance + pub async fn get_account_balance(&self, acc: AccountId) -> Result { Ok(self .sequencer_client .get_account_balance(acc.to_string()) @@ -143,8 +138,8 @@ impl WalletCore { .balance) } - ///Get accounts nonces - pub async fn get_accounts_nonces(&self, accs: Vec
) -> Result> { + /// Get accounts nonces + pub async fn get_accounts_nonces(&self, accs: Vec) -> Result> { Ok(self .sequencer_client .get_accounts_nonces(accs.into_iter().map(|acc| acc.to_string()).collect()) @@ -152,25 +147,28 @@ impl WalletCore { .nonces) } - ///Get account - pub async fn get_account_public(&self, addr: Address) -> Result { - let response = self.sequencer_client.get_account(addr.to_string()).await?; + /// Get account + pub async fn get_account_public(&self, account_id: AccountId) -> Result { + let response = self + .sequencer_client + .get_account(account_id.to_string()) + .await?; Ok(response.account) } - pub fn get_account_private(&self, addr: &Address) -> Option { + pub fn get_account_private(&self, account_id: &AccountId) -> Option { self.storage .user_data - .get_private_account(addr) + .get_private_account(account_id) .map(|value| value.1.clone()) } - pub fn get_private_account_commitment(&self, addr: &Address) -> Option { - let (keys, account) = self.storage.user_data.get_private_account(addr)?; + pub fn get_private_account_commitment(&self, account_id: &AccountId) -> Option { + let (keys, account) = self.storage.user_data.get_private_account(account_id)?; Some(Commitment::new(&keys.nullifer_public_key, account)) } - ///Poll transactions + /// Poll transactions pub async fn poll_native_token_transfer(&self, hash: String) -> Result { let transaction_encoded = self.poller.poll_tx(hash).await?; let tx_base64_decode = BASE64.decode(transaction_encoded)?; @@ -181,9 +179,9 @@ impl WalletCore { pub async fn check_private_account_initialized( &self, - addr: &Address, + account_id: &AccountId, ) -> Result> { - if let Some(acc_comm) = self.get_private_account_commitment(addr) { + if let Some(acc_comm) = self.get_private_account_commitment(account_id) { self.sequencer_client .get_proof_for_commitment(acc_comm) .await @@ -196,9 +194,9 @@ impl WalletCore { pub fn decode_insert_privacy_preserving_transaction_results( &mut self, tx: nssa::privacy_preserving_transaction::PrivacyPreservingTransaction, - acc_decode_data: &[(nssa_core::SharedSecretKey, Address)], + acc_decode_data: &[(nssa_core::SharedSecretKey, AccountId)], ) -> Result<()> { - for (output_index, (secret, acc_address)) in acc_decode_data.iter().enumerate() { + for (output_index, (secret, acc_account_id)) in acc_decode_data.iter().enumerate() { let acc_ead = tx.message.encrypted_private_post_states[output_index].clone(); let acc_comm = tx.message.new_commitments[output_index].clone(); @@ -213,7 +211,7 @@ impl WalletCore { println!("Received new acc {res_acc:#?}"); self.storage - .insert_private_account_data(*acc_address, res_acc); + .insert_private_account_data(*acc_account_id, res_acc); } println!("Transaction data is {:?}", tx.message); @@ -222,23 +220,23 @@ impl WalletCore { } } -///Represents CLI command for a wallet +/// Represents CLI command for a wallet #[derive(Subcommand, Debug, Clone)] #[clap(about)] pub enum Command { - ///Authenticated transfer subcommand + /// Authenticated transfer subcommand #[command(subcommand)] AuthTransfer(AuthTransferSubcommand), - ///Generic chain info subcommand + /// Generic chain info subcommand #[command(subcommand)] ChainInfo(ChainSubcommand), - ///Account view and sync subcommand + /// Account view and sync subcommand #[command(subcommand)] Account(AccountSubcommand), - ///Pinata program interaction subcommand + /// Pinata program interaction subcommand #[command(subcommand)] Pinata(PinataProgramAgnosticSubcommand), - ///Token program interaction subcommand + /// Token program interaction subcommand #[command(subcommand)] Token(TokenProgramAgnosticSubcommand), /// Check the wallet can connect to the node and builtin local programs @@ -249,12 +247,14 @@ pub enum Command { Config(ConfigSubcommand), } -///Represents CLI command for a wallet with setup included +/// Represents overarching CLI command for a wallet with setup included #[derive(Debug, Subcommand, Clone)] #[clap(about)] pub enum OverCommand { + /// Represents CLI command for a wallet #[command(subcommand)] Command(Command), + /// Setup of a storage. Initializes rots for public and private trees from `password`. Setup { #[arg(short, long)] password: String, @@ -268,11 +268,11 @@ pub enum OverCommand { }, } -///To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config +/// To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config /// /// All account adresses must be valid 32 byte base58 strings. /// -/// All account addresses must be provided as {privacy_prefix}/{addr}, +/// All account account_ids must be provided as {privacy_prefix}/{account_id}, /// where valid options for `privacy_prefix` is `Public` and `Private` #[derive(Parser, Debug)] #[clap(version, about)] @@ -288,7 +288,7 @@ pub struct Args { #[derive(Debug, Clone)] pub enum SubcommandReturnValue { PrivacyPreservingTransfer { tx_hash: String }, - RegisterAccount { addr: nssa::Address }, + RegisterAccount { account_id: nssa::AccountId }, Account(nssa::Account), Empty, SyncedToBlock(u64), @@ -376,11 +376,8 @@ pub async fn parse_block_range( if let NSSATransaction::PrivacyPreserving(tx) = nssa_tx { let mut affected_accounts = vec![]; - for (acc_addr, (key_chain, _)) in wallet_core - .storage - .user_data - .default_user_private_accounts - .iter() + for (acc_account_id, (key_chain, _)) in + &wallet_core.storage.user_data.default_user_private_accounts { let view_tag = EncryptedAccountData::compute_view_tag( key_chain.nullifer_public_key.clone(), @@ -408,23 +405,23 @@ pub async fn parse_block_range( if let Some(res_acc) = res_acc { println!( - "Received new account for addr {acc_addr:#?} with account object {res_acc:#?}" + "Received new account for account_id {acc_account_id:#?} with account object {res_acc:#?}" ); - affected_accounts.push((*acc_addr, res_acc)); + affected_accounts.push((*acc_account_id, res_acc)); } } } } - for (_, keys_node) in wallet_core + for keys_node in wallet_core .storage .user_data .private_key_tree .key_map - .iter() + .values() { - let acc_addr = keys_node.address(); + let acc_account_id = keys_node.account_id(); let key_chain = &keys_node.value.0; let view_tag = EncryptedAccountData::compute_view_tag( @@ -453,19 +450,19 @@ pub async fn parse_block_range( if let Some(res_acc) = res_acc { println!( - "Received new account for addr {acc_addr:#?} with account object {res_acc:#?}" + "Received new account for account_id {acc_account_id:#?} with account object {res_acc:#?}" ); - affected_accounts.push((acc_addr, res_acc)); + affected_accounts.push((acc_account_id, res_acc)); } } } } - for (affected_addr, new_acc) in affected_accounts { + for (affected_account_id, new_acc) in affected_accounts { wallet_core .storage - .insert_private_account_data(affected_addr, new_acc); + .insert_private_account_data(affected_account_id, new_acc); } } } diff --git a/wallet/src/main.rs b/wallet/src/main.rs index 1a8b35a..6d8e501 100644 --- a/wallet/src/main.rs +++ b/wallet/src/main.rs @@ -8,6 +8,10 @@ use wallet::{ pub const NUM_THREADS: usize = 2; +// TODO #169: We have sample configs for sequencer, but not for wallet +// TODO #168: Why it requires config as a directory? Maybe better to deduce directory from config +// file path? TODO #172: Why it requires config as env var while sequencer_runner accepts as +// argument? TODO #171: Running pinata doesn't give output about transaction hash and etc. fn main() -> Result<()> { let runtime = Builder::new_multi_thread() .worker_threads(NUM_THREADS) diff --git a/wallet/src/pinata_interactions.rs b/wallet/src/pinata_interactions.rs index 6e3e5ce..e5150c5 100644 --- a/wallet/src/pinata_interactions.rs +++ b/wallet/src/pinata_interactions.rs @@ -1,6 +1,6 @@ use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse}; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; -use nssa::{Address, privacy_preserving_transaction::circuit}; +use nssa::{AccountId, privacy_preserving_transaction::circuit}; use nssa_core::{MembershipProof, SharedSecretKey, account::AccountWithMetadata}; use crate::{ @@ -10,14 +10,14 @@ use crate::{ impl WalletCore { pub async fn claim_pinata( &self, - pinata_addr: Address, - winner_addr: Address, + pinata_account_id: AccountId, + winner_account_id: AccountId, solution: u128, ) -> Result { - let addresses = vec![pinata_addr, winner_addr]; + let account_ids = vec![pinata_account_id, winner_account_id]; let program_id = nssa::program::Program::pinata().id(); let message = - nssa::public_transaction::Message::try_new(program_id, addresses, vec![], solution) + nssa::public_transaction::Message::try_new(program_id, account_ids, vec![], solution) .unwrap(); let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]); @@ -28,8 +28,8 @@ impl WalletCore { pub async fn claim_pinata_private_owned_account_already_initialized( &self, - pinata_addr: Address, - winner_addr: Address, + pinata_account_id: AccountId, + winner_account_id: AccountId, solution: u128, winner_proof: MembershipProof, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { @@ -40,14 +40,14 @@ impl WalletCore { auth_acc: winner_pre, proof: _, } = self - .private_acc_preparation(winner_addr, true, false) + .private_acc_preparation(winner_account_id, true, false) .await?; - let pinata_acc = self.get_account_public(pinata_addr).await.unwrap(); + let pinata_acc = self.get_account_public(pinata_account_id).await.unwrap(); let program = nssa::program::Program::pinata(); - let pinata_pre = AccountWithMetadata::new(pinata_acc.clone(), false, pinata_addr); + let pinata_pre = AccountWithMetadata::new(pinata_acc.clone(), false, pinata_account_id); let eph_holder_winner = EphemeralKeyHolder::new(&winner_npk); let shared_secret_winner = eph_holder_winner.calculate_shared_secret_sender(&winner_ipk); @@ -65,7 +65,7 @@ impl WalletCore { let message = nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( - vec![pinata_addr], + vec![pinata_account_id], vec![], vec![( winner_npk.clone(), @@ -95,8 +95,8 @@ impl WalletCore { pub async fn claim_pinata_private_owned_account_not_initialized( &self, - pinata_addr: Address, - winner_addr: Address, + pinata_account_id: AccountId, + winner_account_id: AccountId, solution: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { let AccountPreparedData { @@ -106,14 +106,14 @@ impl WalletCore { auth_acc: winner_pre, proof: _, } = self - .private_acc_preparation(winner_addr, false, false) + .private_acc_preparation(winner_account_id, false, false) .await?; - let pinata_acc = self.get_account_public(pinata_addr).await.unwrap(); + let pinata_acc = self.get_account_public(pinata_account_id).await.unwrap(); let program = nssa::program::Program::pinata(); - let pinata_pre = AccountWithMetadata::new(pinata_acc.clone(), false, pinata_addr); + let pinata_pre = AccountWithMetadata::new(pinata_acc.clone(), false, pinata_account_id); let eph_holder_winner = EphemeralKeyHolder::new(&winner_npk); let shared_secret_winner = eph_holder_winner.calculate_shared_secret_sender(&winner_ipk); @@ -131,7 +131,7 @@ impl WalletCore { let message = nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( - vec![pinata_addr], + vec![pinata_account_id], vec![], vec![( winner_npk.clone(), diff --git a/wallet/src/poller.rs b/wallet/src/poller.rs index 279197f..2b709e7 100644 --- a/wallet/src/poller.rs +++ b/wallet/src/poller.rs @@ -7,10 +7,11 @@ use log::{info, warn}; use crate::config::WalletConfig; #[derive(Clone)] -///Helperstruct to poll transactions +/// Helperstruct to poll transactions pub struct TxPoller { pub polling_max_blocks_to_query: usize, pub polling_max_error_attempts: u64, + // TODO: This should be Duration pub polling_error_delay_millis: u64, pub polling_delay_millis: u64, pub client: Arc, diff --git a/wallet/src/token_program_interactions.rs b/wallet/src/token_program_interactions.rs index 04f1abc..c441842 100644 --- a/wallet/src/token_program_interactions.rs +++ b/wallet/src/token_program_interactions.rs @@ -1,5 +1,5 @@ use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse}; -use nssa::{Account, Address, program::Program}; +use nssa::{Account, AccountId, program::Program}; use nssa_core::{ MembershipProof, NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey, program::InstructionData, @@ -15,7 +15,8 @@ impl WalletCore { Program, impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, ) { - // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. + // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || + // 0x00 || 0x00 || 0x00]. let mut instruction = [0; 23]; instruction[0] = 0x01; instruction[1..17].copy_from_slice(&amount.to_le_bytes()); @@ -47,20 +48,24 @@ impl WalletCore { pub async fn send_new_token_definition( &self, - definition_address: Address, - supply_address: Address, + definition_account_id: AccountId, + supply_account_id: AccountId, name: [u8; 6], total_supply: u128, ) -> Result { - let addresses = vec![definition_address, supply_address]; + let account_ids = vec![definition_account_id, supply_account_id]; let program_id = nssa::program::Program::token().id(); // Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)] let mut instruction = [0; 23]; instruction[1..17].copy_from_slice(&total_supply.to_le_bytes()); instruction[17..].copy_from_slice(&name); - let message = - nssa::public_transaction::Message::try_new(program_id, addresses, vec![], instruction) - .unwrap(); + let message = nssa::public_transaction::Message::try_new( + program_id, + account_ids, + vec![], + instruction, + ) + .unwrap(); let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]); @@ -71,8 +76,8 @@ impl WalletCore { pub async fn send_new_token_definition_private_owned( &self, - definition_addr: Address, - supply_addr: Address, + definition_account_id: AccountId, + supply_account_id: AccountId, name: [u8; 6], total_supply: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { @@ -82,8 +87,8 @@ impl WalletCore { // Kind of non-obvious naming // Basically this funtion is called because authentication mask is [0, 2] self.shielded_two_accs_receiver_uninit( - definition_addr, - supply_addr, + definition_account_id, + supply_account_id, instruction_data, tx_pre_check, program, @@ -93,27 +98,32 @@ impl WalletCore { pub async fn send_transfer_token_transaction( &self, - sender_address: Address, - recipient_address: Address, + sender_account_id: AccountId, + recipient_account_id: AccountId, amount: u128, ) -> Result { - let addresses = vec![sender_address, recipient_address]; + let account_ids = vec![sender_account_id, recipient_account_id]; let program_id = nssa::program::Program::token().id(); - // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || 0x00 || 0x00 || 0x00]. + // Instruction must be: [0x01 || amount (little-endian 16 bytes) || 0x00 || 0x00 || 0x00 || + // 0x00 || 0x00 || 0x00]. let mut instruction = [0; 23]; instruction[0] = 0x01; instruction[1..17].copy_from_slice(&amount.to_le_bytes()); - let Ok(nonces) = self.get_accounts_nonces(vec![sender_address]).await else { + let Ok(nonces) = self.get_accounts_nonces(vec![sender_account_id]).await else { return Err(ExecutionFailureKind::SequencerError); }; - let message = - nssa::public_transaction::Message::try_new(program_id, addresses, nonces, instruction) - .unwrap(); + let message = nssa::public_transaction::Message::try_new( + program_id, + account_ids, + nonces, + instruction, + ) + .unwrap(); let Some(signing_key) = self .storage .user_data - .get_pub_account_signing_key(&sender_address) + .get_pub_account_signing_key(&sender_account_id) else { return Err(ExecutionFailureKind::KeyNotFoundError); }; @@ -127,8 +137,8 @@ impl WalletCore { pub async fn send_transfer_token_transaction_private_owned_account_already_initialized( &self, - sender_address: Address, - recipient_address: Address, + sender_account_id: AccountId, + recipient_account_id: AccountId, amount: u128, recipient_proof: MembershipProof, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { @@ -136,8 +146,8 @@ impl WalletCore { WalletCore::token_program_preparation_transfer(amount); self.private_tx_two_accs_all_init( - sender_address, - recipient_address, + sender_account_id, + recipient_account_id, instruction_data, tx_pre_check, program, @@ -148,16 +158,16 @@ impl WalletCore { pub async fn send_transfer_token_transaction_private_owned_account_not_initialized( &self, - sender_address: Address, - recipient_address: Address, + sender_account_id: AccountId, + recipient_account_id: AccountId, amount: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { let (instruction_data, program, tx_pre_check) = WalletCore::token_program_preparation_transfer(amount); self.private_tx_two_accs_receiver_uninit( - sender_address, - recipient_address, + sender_account_id, + recipient_account_id, instruction_data, tx_pre_check, program, @@ -167,7 +177,7 @@ impl WalletCore { pub async fn send_transfer_token_transaction_private_foreign_account( &self, - sender_address: Address, + sender_account_id: AccountId, recipient_npk: NullifierPublicKey, recipient_ipk: IncomingViewingPublicKey, amount: u128, @@ -176,7 +186,7 @@ impl WalletCore { WalletCore::token_program_preparation_transfer(amount); self.private_tx_two_accs_receiver_outer( - sender_address, + sender_account_id, recipient_npk, recipient_ipk, instruction_data, @@ -188,16 +198,16 @@ impl WalletCore { pub async fn send_transfer_token_transaction_deshielded( &self, - sender_address: Address, - recipient_address: Address, + sender_account_id: AccountId, + recipient_account_id: AccountId, amount: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { let (instruction_data, program, tx_pre_check) = WalletCore::token_program_preparation_transfer(amount); self.deshielded_tx_two_accs( - sender_address, - recipient_address, + sender_account_id, + recipient_account_id, instruction_data, tx_pre_check, program, @@ -207,8 +217,8 @@ impl WalletCore { pub async fn send_transfer_token_transaction_shielded_owned_account_already_initialized( &self, - sender_address: Address, - recipient_address: Address, + sender_account_id: AccountId, + recipient_account_id: AccountId, amount: u128, recipient_proof: MembershipProof, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { @@ -216,8 +226,8 @@ impl WalletCore { WalletCore::token_program_preparation_transfer(amount); self.shielded_two_accs_all_init( - sender_address, - recipient_address, + sender_account_id, + recipient_account_id, instruction_data, tx_pre_check, program, @@ -228,16 +238,16 @@ impl WalletCore { pub async fn send_transfer_token_transaction_shielded_owned_account_not_initialized( &self, - sender_address: Address, - recipient_address: Address, + sender_account_id: AccountId, + recipient_account_id: AccountId, amount: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { let (instruction_data, program, tx_pre_check) = WalletCore::token_program_preparation_transfer(amount); self.shielded_two_accs_receiver_uninit( - sender_address, - recipient_address, + sender_account_id, + recipient_account_id, instruction_data, tx_pre_check, program, @@ -247,7 +257,7 @@ impl WalletCore { pub async fn send_transfer_token_transaction_shielded_foreign_account( &self, - sender_address: Address, + sender_account_id: AccountId, recipient_npk: NullifierPublicKey, recipient_ipk: IncomingViewingPublicKey, amount: u128, @@ -256,7 +266,7 @@ impl WalletCore { WalletCore::token_program_preparation_transfer(amount); self.shielded_two_accs_receiver_outer( - sender_address, + sender_account_id, recipient_npk, recipient_ipk, instruction_data, diff --git a/wallet/src/token_transfers/deshielded.rs b/wallet/src/token_transfers/deshielded.rs index 4c922f6..4c8cbe3 100644 --- a/wallet/src/token_transfers/deshielded.rs +++ b/wallet/src/token_transfers/deshielded.rs @@ -1,13 +1,13 @@ use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse}; -use nssa::Address; +use nssa::AccountId; use crate::WalletCore; impl WalletCore { pub async fn send_deshielded_native_token_transfer( &self, - from: Address, - to: Address, + from: AccountId, + to: AccountId, balance_to_move: u128, ) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 1]), ExecutionFailureKind> { let (instruction_data, program, tx_pre_check) = diff --git a/wallet/src/token_transfers/private.rs b/wallet/src/token_transfers/private.rs index 40d2731..35d3e3b 100644 --- a/wallet/src/token_transfers/private.rs +++ b/wallet/src/token_transfers/private.rs @@ -1,5 +1,5 @@ use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse}; -use nssa::Address; +use nssa::AccountId; use nssa_core::{ MembershipProof, NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey, }; @@ -9,7 +9,7 @@ use crate::WalletCore; impl WalletCore { pub async fn send_private_native_token_transfer_outer_account( &self, - from: Address, + from: AccountId, to_npk: NullifierPublicKey, to_ipk: IncomingViewingPublicKey, balance_to_move: u128, @@ -30,8 +30,8 @@ impl WalletCore { pub async fn send_private_native_token_transfer_owned_account_not_initialized( &self, - from: Address, - to: Address, + from: AccountId, + to: AccountId, balance_to_move: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { let (instruction_data, program, tx_pre_check) = @@ -43,8 +43,8 @@ impl WalletCore { pub async fn send_private_native_token_transfer_owned_account_already_initialized( &self, - from: Address, - to: Address, + from: AccountId, + to: AccountId, balance_to_move: u128, to_proof: MembershipProof, ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { diff --git a/wallet/src/token_transfers/public.rs b/wallet/src/token_transfers/public.rs index 353a7c7..a63d838 100644 --- a/wallet/src/token_transfers/public.rs +++ b/wallet/src/token_transfers/public.rs @@ -1,6 +1,6 @@ use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse}; use nssa::{ - Address, PublicTransaction, + AccountId, PublicTransaction, program::Program, public_transaction::{Message, WitnessSet}, }; @@ -10,8 +10,8 @@ use crate::WalletCore; impl WalletCore { pub async fn send_public_native_token_transfer( &self, - from: Address, - to: Address, + from: AccountId, + to: AccountId, balance_to_move: u128, ) -> Result { let Ok(balance) = self.get_account_balance(from).await else { @@ -23,9 +23,10 @@ impl WalletCore { return Err(ExecutionFailureKind::SequencerError); }; - let addresses = vec![from, to]; + let account_ids = vec![from, to]; let program_id = Program::authenticated_transfer_program().id(); - let message = Message::try_new(program_id, addresses, nonces, balance_to_move).unwrap(); + let message = + Message::try_new(program_id, account_ids, nonces, balance_to_move).unwrap(); let signing_key = self.storage.user_data.get_pub_account_signing_key(&from); @@ -45,16 +46,16 @@ impl WalletCore { pub async fn register_account_under_authenticated_transfers_programs( &self, - from: Address, + from: AccountId, ) -> Result { let Ok(nonces) = self.get_accounts_nonces(vec![from]).await else { return Err(ExecutionFailureKind::SequencerError); }; let instruction: u128 = 0; - let addresses = vec![from]; + let account_ids = vec![from]; let program_id = Program::authenticated_transfer_program().id(); - let message = Message::try_new(program_id, addresses, nonces, instruction).unwrap(); + let message = Message::try_new(program_id, account_ids, nonces, instruction).unwrap(); let signing_key = self.storage.user_data.get_pub_account_signing_key(&from); diff --git a/wallet/src/token_transfers/shielded.rs b/wallet/src/token_transfers/shielded.rs index e2e0618..8ba260c 100644 --- a/wallet/src/token_transfers/shielded.rs +++ b/wallet/src/token_transfers/shielded.rs @@ -1,5 +1,5 @@ use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse}; -use nssa::Address; +use nssa::AccountId; use nssa_core::{ MembershipProof, NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey, }; @@ -9,8 +9,8 @@ use crate::WalletCore; impl WalletCore { pub async fn send_shielded_native_token_transfer_already_initialized( &self, - from: Address, - to: Address, + from: AccountId, + to: AccountId, balance_to_move: u128, to_proof: MembershipProof, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { @@ -23,8 +23,8 @@ impl WalletCore { pub async fn send_shielded_native_token_transfer_not_initialized( &self, - from: Address, - to: Address, + from: AccountId, + to: AccountId, balance_to_move: u128, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { let (instruction_data, program, tx_pre_check) = @@ -36,7 +36,7 @@ impl WalletCore { pub async fn send_shielded_native_token_transfer_outer_account( &self, - from: Address, + from: AccountId, to_npk: NullifierPublicKey, to_ipk: IncomingViewingPublicKey, balance_to_move: u128, diff --git a/wallet/src/transaction_utils.rs b/wallet/src/transaction_utils.rs index 2dd69ca..a54f81c 100644 --- a/wallet/src/transaction_utils.rs +++ b/wallet/src/transaction_utils.rs @@ -1,7 +1,7 @@ use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse}; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use nssa::{ - Account, Address, PrivacyPreservingTransaction, + Account, AccountId, PrivacyPreservingTransaction, privacy_preserving_transaction::{circuit, message::Message, witness_set::WitnessSet}, program::Program, }; @@ -23,12 +23,15 @@ pub(crate) struct AccountPreparedData { impl WalletCore { pub(crate) async fn private_acc_preparation( &self, - addr: Address, + account_id: AccountId, is_authorized: bool, needs_proof: bool, ) -> Result { - let Some((from_keys, from_acc)) = - self.storage.user_data.get_private_account(&addr).cloned() + let Some((from_keys, from_acc)) = self + .storage + .user_data + .get_private_account(&account_id) + .cloned() else { return Err(ExecutionFailureKind::KeyNotFoundError); }; @@ -66,8 +69,8 @@ impl WalletCore { pub(crate) async fn private_tx_two_accs_all_init( &self, - from: Address, - to: Address, + from: AccountId, + to: AccountId, instruction_data: InstructionData, tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, program: Program, @@ -144,8 +147,8 @@ impl WalletCore { pub(crate) async fn private_tx_two_accs_receiver_uninit( &self, - from: Address, - to: Address, + from: AccountId, + to: AccountId, instruction_data: InstructionData, tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, program: Program, @@ -218,7 +221,7 @@ impl WalletCore { pub(crate) async fn private_tx_two_accs_receiver_outer( &self, - from: Address, + from: AccountId, to_npk: NullifierPublicKey, to_ipk: IncomingViewingPublicKey, instruction_data: InstructionData, @@ -289,8 +292,8 @@ impl WalletCore { pub(crate) async fn deshielded_tx_two_accs( &self, - from: Address, - to: Address, + from: AccountId, + to: AccountId, instruction_data: InstructionData, tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, program: Program, @@ -349,8 +352,8 @@ impl WalletCore { pub(crate) async fn shielded_two_accs_all_init( &self, - from: Address, - to: Address, + from: AccountId, + to: AccountId, instruction_data: InstructionData, tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, program: Program, @@ -416,8 +419,8 @@ impl WalletCore { pub(crate) async fn shielded_two_accs_receiver_uninit( &self, - from: Address, - to: Address, + from: AccountId, + to: AccountId, instruction_data: InstructionData, tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, program: Program, @@ -482,7 +485,7 @@ impl WalletCore { pub(crate) async fn shielded_two_accs_receiver_outer( &self, - from: Address, + from: AccountId, to_npk: NullifierPublicKey, to_ipk: IncomingViewingPublicKey, instruction_data: InstructionData, @@ -540,7 +543,7 @@ impl WalletCore { pub async fn register_account_under_authenticated_transfers_programs_private( &self, - from: Address, + from: AccountId, ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { let AccountPreparedData { nsk: _,