Merge branch 'main' into Pravdyvy/deterministic-key-derivation

This commit is contained in:
Pravdyvy 2025-11-27 13:46:35 +02:00
commit 6c409b6fb1
86 changed files with 1910 additions and 2032 deletions

View File

@ -1,7 +1,7 @@
on: on:
push: push:
branches: branches:
- master - main
paths-ignore: paths-ignore:
- "**.md" - "**.md"
- "!.github/workflows/*.yml" - "!.github/workflows/*.yml"
@ -21,15 +21,14 @@ jobs:
name: ubuntu-latest-pipeline name: ubuntu-latest-pipeline
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- name: Install stable toolchain
uses: actions-rs/toolchain@v1 - name: Install active toolchain
with: run: rustup install
profile: minimal
toolchain: nightly - name: Install nightly toolchain for rustfmt
override: true run: rustup install nightly --profile minimal --component rustfmt
components: rustfmt, clippy
- name: lint - ubuntu-latest - name: lint - ubuntu-latest
if: success() || failure()
run: chmod 777 ./ci_scripts/lint-ubuntu.sh && ./ci_scripts/lint-ubuntu.sh run: chmod 777 ./ci_scripts/lint-ubuntu.sh && ./ci_scripts/lint-ubuntu.sh
- name: test ubuntu-latest - name: test ubuntu-latest
if: success() || failure() if: success() || failure()

View File

@ -1,8 +1,8 @@
set -e set -e
cargo install taplo-cli --locked cargo +nightly fmt -- --check
cargo fmt -- --check cargo install taplo-cli --locked
taplo fmt --check taplo fmt --check
RISC0_SKIP_BUILD=1 cargo clippy --workspace --all-targets -- -D warnings RISC0_SKIP_BUILD=1 cargo clippy --workspace --all-targets -- -D warnings

View File

@ -6,7 +6,7 @@ use crate::transaction::EncodedTransaction;
pub type HashType = [u8; 32]; pub type HashType = [u8; 32];
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
///Our own hasher. /// Our own hasher.
/// Currently it is SHA256 hasher wrapper. May change in a future. /// Currently it is SHA256 hasher wrapper. May change in a future.
pub struct OwnHasher {} pub struct OwnHasher {}

View File

@ -4,8 +4,8 @@ pub mod rpc_primitives;
pub mod sequencer_client; pub mod sequencer_client;
pub mod transaction; pub mod transaction;
//Module for tests utility functions // Module for tests utility functions
//TODO: Compile only for tests // TODO: Compile only for tests
pub mod test_utils; pub mod test_utils;
pub type HashType = [u8; 32]; pub type HashType = [u8; 32];

View File

@ -1,6 +1,7 @@
use serde_json::{Value, to_value};
use std::fmt; use std::fmt;
use serde_json::{Value, to_value};
#[derive(serde::Serialize)] #[derive(serde::Serialize)]
pub struct RpcParseError(pub String); pub struct RpcParseError(pub String);

View File

@ -9,11 +9,14 @@
//! //!
//! The main entrypoint here is the [Message](enum.Message.html). The others are just building //! The main entrypoint here is the [Message](enum.Message.html). The others are just building
//! blocks and you should generally work with `Message` instead. //! 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 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; use super::errors::RpcError;
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -69,6 +72,7 @@ impl Request {
id: self.id.clone(), id: self.id.clone(),
}) })
} }
/// Answer the request with an error. /// Answer the request with an error.
pub fn error(&self, error: RpcError) -> Message { pub fn error(&self, error: RpcError) -> Message {
Message::Response(Response { Message::Response(Response {
@ -207,6 +211,7 @@ impl Message {
id, id,
}) })
} }
/// Create a top-level error (without an ID). /// Create a top-level error (without an ID).
pub fn error(error: RpcError) -> Self { pub fn error(error: RpcError) -> Self {
Message::Response(Response { Message::Response(Response {
@ -215,6 +220,7 @@ impl Message {
id: Value::Null, id: Value::Null,
}) })
} }
/// A constructor for a notification. /// A constructor for a notification.
pub fn notification(method: String, params: Value) -> Self { pub fn notification(method: String, params: Value) -> Self {
Message::Notification(Notification { Message::Notification(Notification {
@ -223,6 +229,7 @@ impl Message {
params, params,
}) })
} }
/// A constructor for a response. /// A constructor for a response.
pub fn response(id: Value, result: Result<Value, RpcError>) -> Self { pub fn response(id: Value, result: Result<Value, RpcError>) -> Self {
Message::Response(Response { Message::Response(Response {
@ -231,6 +238,7 @@ impl Message {
id, id,
}) })
} }
/// Returns id or Null if there is no id. /// Returns id or Null if there is no id.
pub fn id(&self) -> Value { pub fn id(&self) -> Value {
match self { match self {
@ -315,10 +323,7 @@ impl From<Message> for Vec<u8> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use serde_json::Value; use serde_json::{Value, de::from_slice, json, ser::to_vec};
use serde_json::de::from_slice;
use serde_json::json;
use serde_json::ser::to_vec;
use super::*; use super::*;

View File

@ -1,5 +1,3 @@
use std::time::Duration;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
pub mod errors; pub mod errors;
@ -7,21 +5,6 @@ pub mod message;
pub mod parser; pub mod parser;
pub mod requests; 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)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct RpcLimitsConfig { pub struct RpcLimitsConfig {
/// Maximum byte size of the json payload. /// Maximum byte size of the json payload.
@ -40,7 +23,6 @@ impl Default for RpcLimitsConfig {
pub struct RpcConfig { pub struct RpcConfig {
pub addr: String, pub addr: String,
pub cors_allowed_origins: Vec<String>, pub cors_allowed_origins: Vec<String>,
pub polling_config: RpcPollingConfig,
#[serde(default)] #[serde(default)]
pub limits_config: RpcLimitsConfig, pub limits_config: RpcLimitsConfig,
} }
@ -50,7 +32,6 @@ impl Default for RpcConfig {
RpcConfig { RpcConfig {
addr: "0.0.0.0:3040".to_owned(), addr: "0.0.0.0:3040".to_owned(),
cors_allowed_origins: vec!["*".to_owned()], cors_allowed_origins: vec!["*".to_owned()],
polling_config: RpcPollingConfig::default(),
limits_config: RpcLimitsConfig::default(), limits_config: RpcLimitsConfig::default(),
} }
} }

View File

@ -1,20 +1,21 @@
use std::collections::HashMap; 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 nssa_core::program::ProgramId;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
use super::{
errors::RpcParseError,
parser::{RpcRequest, parse_params},
};
use crate::parse_request;
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct HelloRequest {} pub struct HelloRequest {}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct RegisterAccountRequest { pub struct RegisterAccountRequest {
pub address: [u8; 32], pub account_id: [u8; 32],
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -38,7 +39,7 @@ pub struct GetInitialTestnetAccountsRequest {}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct GetAccountBalanceRequest { pub struct GetAccountBalanceRequest {
pub address: String, pub account_id: String,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -48,12 +49,12 @@ pub struct GetTransactionByHashRequest {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct GetAccountsNoncesRequest { pub struct GetAccountsNoncesRequest {
pub addresses: Vec<String>, pub account_ids: Vec<String>,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct GetAccountRequest { pub struct GetAccountRequest {
pub address: String, pub account_id: String,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]

View File

@ -1,13 +1,13 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
//Requests // Requests
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct SendTxRequest { pub struct SendTxRequest {
pub transaction: Vec<u8>, pub transaction: Vec<u8>,
} }
//Responses // Responses
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct SendTxResponse { pub struct SendTxResponse {
@ -15,7 +15,7 @@ pub struct SendTxResponse {
pub tx_hash: String, pub tx_hash: String,
} }
//General // General
#[derive(Debug, Clone, Serialize)] #[derive(Debug, Clone, Serialize)]
pub struct SequencerRpcRequest { pub struct SequencerRpcRequest {
@ -31,7 +31,7 @@ impl SequencerRpcRequest {
jsonrpc: "2.0".to_string(), jsonrpc: "2.0".to_string(),
method, method,
params: payload, params: payload,
//ToDo: Correct checking of id // ToDo: Correct checking of id
id: 1, id: 1,
} }
} }
@ -45,9 +45,9 @@ pub struct SequencerRpcResponse {
} }
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
///Helperstruct for account serialization /// Helperstruct for account serialization
pub struct AccountInitialData { pub struct AccountInitialData {
///Hex encoded `AccountAddress` /// Hex encoded account id
pub addr: String, pub account_id: String,
pub balance: u64, pub balance: u64,
} }

View File

@ -1,24 +1,26 @@
use std::collections::HashMap; use std::collections::HashMap;
use super::rpc_primitives::requests::{
GetAccountBalanceRequest, GetAccountBalanceResponse, GetBlockDataRequest, GetBlockDataResponse,
GetGenesisIdRequest, GetGenesisIdResponse, GetInitialTestnetAccountsRequest,
};
use anyhow::Result; use anyhow::Result;
use json::{SendTxRequest, SendTxResponse, SequencerRpcRequest, SequencerRpcResponse}; use json::{SendTxRequest, SendTxResponse, SequencerRpcRequest, SequencerRpcResponse};
use nssa_core::program::ProgramId; use nssa_core::program::ProgramId;
use reqwest::Client; use reqwest::Client;
use serde_json::Value; use serde_json::Value;
use crate::error::{SequencerClientError, SequencerRpcError}; use super::rpc_primitives::requests::{
use crate::rpc_primitives::requests::{ GetAccountBalanceRequest, GetAccountBalanceResponse, GetBlockDataRequest, GetBlockDataResponse,
GetAccountRequest, GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse, GetGenesisIdRequest, GetGenesisIdResponse, GetInitialTestnetAccountsRequest,
GetLastBlockRequest, GetLastBlockResponse, GetProgramIdsRequest, GetProgramIdsResponse, };
GetProofForCommitmentRequest, GetProofForCommitmentResponse, GetTransactionByHashRequest, use crate::{
GetTransactionByHashResponse, 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; 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( pub async fn get_block(
&self, &self,
block_id: u64, block_id: u64,
@ -78,7 +80,7 @@ impl SequencerClient {
Ok(resp_deser) 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<GetLastBlockResponse, SequencerClientError> { pub async fn get_last_block(&self) -> Result<GetLastBlockResponse, SequencerClientError> {
let block_req = GetLastBlockRequest {}; let block_req = GetLastBlockRequest {};
@ -91,12 +93,13 @@ impl SequencerClient {
Ok(resp_deser) 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( pub async fn get_account_balance(
&self, &self,
address: String, account_id: String,
) -> Result<GetAccountBalanceResponse, SequencerClientError> { ) -> Result<GetAccountBalanceResponse, SequencerClientError> {
let block_req = GetAccountBalanceRequest { address }; let block_req = GetAccountBalanceRequest { account_id };
let req = serde_json::to_value(block_req)?; let req = serde_json::to_value(block_req)?;
@ -109,12 +112,13 @@ impl SequencerClient {
Ok(resp_deser) 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( pub async fn get_accounts_nonces(
&self, &self,
addresses: Vec<String>, account_ids: Vec<String>,
) -> Result<GetAccountsNoncesResponse, SequencerClientError> { ) -> Result<GetAccountsNoncesResponse, SequencerClientError> {
let block_req = GetAccountsNoncesRequest { addresses }; let block_req = GetAccountsNoncesRequest { account_ids };
let req = serde_json::to_value(block_req)?; let req = serde_json::to_value(block_req)?;
@ -129,9 +133,9 @@ impl SequencerClient {
pub async fn get_account( pub async fn get_account(
&self, &self,
address: String, account_id: String,
) -> Result<GetAccountResponse, SequencerClientError> { ) -> Result<GetAccountResponse, SequencerClientError> {
let block_req = GetAccountRequest { address }; let block_req = GetAccountRequest { account_id };
let req = serde_json::to_value(block_req)?; let req = serde_json::to_value(block_req)?;
@ -142,7 +146,7 @@ impl SequencerClient {
Ok(resp_deser) Ok(resp_deser)
} }
///Get transaction details for `hash`. /// Get transaction details for `hash`.
pub async fn get_transaction_by_hash( pub async fn get_transaction_by_hash(
&self, &self,
hash: String, hash: String,
@ -160,7 +164,7 @@ impl SequencerClient {
Ok(resp_deser) Ok(resp_deser)
} }
///Send transaction to sequencer /// Send transaction to sequencer
pub async fn send_tx_public( pub async fn send_tx_public(
&self, &self,
transaction: nssa::PublicTransaction, transaction: nssa::PublicTransaction,
@ -180,7 +184,7 @@ impl SequencerClient {
Ok(resp_deser) Ok(resp_deser)
} }
///Send transaction to sequencer /// Send transaction to sequencer
pub async fn send_tx_private( pub async fn send_tx_private(
&self, &self,
transaction: nssa::PrivacyPreservingTransaction, transaction: nssa::PrivacyPreservingTransaction,
@ -200,7 +204,7 @@ impl SequencerClient {
Ok(resp_deser) Ok(resp_deser)
} }
///Get genesis id from sequencer /// Get genesis id from sequencer
pub async fn get_genesis_id(&self) -> Result<GetGenesisIdResponse, SequencerClientError> { pub async fn get_genesis_id(&self) -> Result<GetGenesisIdResponse, SequencerClientError> {
let genesis_req = GetGenesisIdRequest {}; let genesis_req = GetGenesisIdRequest {};
@ -216,7 +220,7 @@ impl SequencerClient {
Ok(resp_deser) Ok(resp_deser)
} }
///Get initial testnet accounts from sequencer /// Get initial testnet accounts from sequencer
pub async fn get_initial_testnet_accounts( pub async fn get_initial_testnet_accounts(
&self, &self,
) -> Result<Vec<AccountInitialData>, SequencerClientError> { ) -> Result<Vec<AccountInitialData>, SequencerClientError> {
@ -234,7 +238,7 @@ impl SequencerClient {
Ok(resp_deser) Ok(resp_deser)
} }
///Get proof for commitment /// Get proof for commitment
pub async fn get_proof_for_commitment( pub async fn get_proof_for_commitment(
&self, &self,
commitment: nssa_core::Commitment, commitment: nssa_core::Commitment,

View File

@ -3,15 +3,15 @@ use crate::{
transaction::{EncodedTransaction, NSSATransaction}, transaction::{EncodedTransaction, NSSATransaction},
}; };
//Helpers // Helpers
pub fn sequencer_sign_key_for_testing() -> nssa::PrivateKey { pub fn sequencer_sign_key_for_testing() -> nssa::PrivateKey {
nssa::PrivateKey::try_new([37; 32]).unwrap() 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 /// `id` - block id, provide zero for genesis
/// ///
@ -35,12 +35,16 @@ pub fn produce_dummy_block(
pub fn produce_dummy_empty_transaction() -> EncodedTransaction { pub fn produce_dummy_empty_transaction() -> EncodedTransaction {
let program_id = nssa::program::Program::authenticated_transfer_program().id(); let program_id = nssa::program::Program::authenticated_transfer_program().id();
let addresses = vec![]; let account_ids = vec![];
let nonces = vec![]; let nonces = vec![];
let instruction_data: u128 = 0; let instruction_data: u128 = 0;
let message = let message = nssa::public_transaction::Message::try_new(
nssa::public_transaction::Message::try_new(program_id, addresses, nonces, instruction_data) program_id,
.unwrap(); account_ids,
nonces,
instruction_data,
)
.unwrap();
let private_key = nssa::PrivateKey::try_new([1; 32]).unwrap(); let private_key = nssa::PrivateKey::try_new([1; 32]).unwrap();
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[&private_key]); 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, balance_to_move: u128,
signing_key: nssa::PrivateKey, signing_key: nssa::PrivateKey,
) -> EncodedTransaction { ) -> 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 nonces = vec![nonce];
let program_id = nssa::program::Program::authenticated_transfer_program().id(); let program_id = nssa::program::Program::authenticated_transfer_program().id();
let message = let message = nssa::public_transaction::Message::try_new(
nssa::public_transaction::Message::try_new(program_id, addresses, nonces, balance_to_move) program_id,
.unwrap(); account_ids,
nonces,
balance_to_move,
)
.unwrap();
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[&signing_key]); let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[&signing_key]);
let nssa_tx = nssa::PublicTransaction::new(message, witness_set); let nssa_tx = nssa::PublicTransaction::new(message, witness_set);

View File

@ -1,7 +1,6 @@
use borsh::{BorshDeserialize, BorshSerialize}; use borsh::{BorshDeserialize, BorshSerialize};
use log::info; use log::info;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sha2::{Digest, digest::FixedOutput}; use sha2::{Digest, digest::FixedOutput};
pub type HashType = [u8; 32]; pub type HashType = [u8; 32];
@ -41,10 +40,10 @@ pub enum TxKind {
} }
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)] #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize)]
///General transaction object /// General transaction object
pub struct EncodedTransaction { pub struct EncodedTransaction {
pub tx_kind: TxKind, pub tx_kind: TxKind,
///Encoded blobs of data /// Encoded blobs of data
pub encoded_transaction_data: Vec<u8>, pub encoded_transaction_data: Vec<u8>,
} }

View File

@ -9,11 +9,11 @@
"port": 3040, "port": 3040,
"initial_accounts": [ "initial_accounts": [
{ {
"addr": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", "account_id": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy",
"balance": 10000 "balance": 10000
}, },
{ {
"addr": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", "account_id": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw",
"balance": 20000 "balance": 20000
} }
], ],

View File

@ -8,7 +8,7 @@
"initial_accounts": [ "initial_accounts": [
{ {
"Public": { "Public": {
"address": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", "account_id": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy",
"pub_sign_key": [ "pub_sign_key": [
16, 16,
162, 162,
@ -47,7 +47,7 @@
}, },
{ {
"Public": { "Public": {
"address": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", "account_id": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw",
"pub_sign_key": [ "pub_sign_key": [
113, 113,
121, 121,
@ -86,7 +86,7 @@
}, },
{ {
"Private": { "Private": {
"address": "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw", "account_id": "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw",
"account": { "account": {
"program_owner": [ "program_owner": [
0, 0,
@ -315,7 +315,7 @@
}, },
{ {
"Private": { "Private": {
"address": "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX", "account_id": "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX",
"account": { "account": {
"program_owner": [ "program_owner": [
0, 0,

View File

@ -1,8 +1,8 @@
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
use std::path::PathBuf; use std::path::PathBuf;
use actix_web::dev::ServerHandle; use actix_web::dev::ServerHandle;
use anyhow::Result; use anyhow::Result;
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
use clap::Parser; use clap::Parser;
use common::{ use common::{
sequencer_client::SequencerClient, sequencer_client::SequencerClient,
@ -44,12 +44,12 @@ pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12;
pub const NSSA_PROGRAM_FOR_TEST_DATA_CHANGER: &[u8] = include_bytes!("data_changer.bin"); pub const NSSA_PROGRAM_FOR_TEST_DATA_CHANGER: &[u8] = include_bytes!("data_changer.bin");
fn make_public_account_input_from_str(addr: &str) -> String { fn make_public_account_input_from_str(account_id: &str) -> String {
format!("Public/{addr}") format!("Public/{account_id}")
} }
fn make_private_account_input_from_str(addr: &str) -> String { fn make_private_account_input_from_str(account_id: &str) -> String {
format!("Private/{addr}") format!("Private/{account_id}")
} }
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
@ -98,13 +98,13 @@ pub async fn post_test(residual: (ServerHandle, JoinHandle<Result<()>>, TempDir)
let wallet_home = wallet::helperfunctions::get_home().unwrap(); let wallet_home = wallet::helperfunctions::get_home().unwrap();
let persistent_data_home = wallet_home.join("storage.json"); let persistent_data_home = wallet_home.join("storage.json");
//Removing persistent accounts after run to not affect other executions // Removing persistent accounts after run to not affect other executions
//Not necessary an error, if fails as there is tests for failure scenario // Not necessary an error, if fails as there is tests for failure scenario
let _ = std::fs::remove_file(persistent_data_home) let _ = std::fs::remove_file(persistent_data_home)
.inspect_err(|err| warn!("Failed to remove persistent data with err {err:#?}")); .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. // At this point all of the references to sequencer_core must be lost.
//So they are dropped and tempdirs will be dropped too, // So they are dropped and tempdirs will be dropped too,
} }
pub async fn main_tests_runner() -> Result<()> { 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}; use crate::{make_private_account_input_from_str, make_public_account_input_from_str};
#[test] #[test]
fn correct_addr_from_prefix() { fn correct_account_id_from_prefix() {
let addr1 = "cafecafe"; let account_id1 = "cafecafe";
let addr2 = "deadbeaf"; let account_id2 = "deadbeaf";
let addr1_pub = make_public_account_input_from_str(addr1); let account_id1_pub = make_public_account_input_from_str(account_id1);
let addr2_priv = make_private_account_input_from_str(addr2); let account_id2_priv = make_private_account_input_from_str(account_id2);
assert_eq!(addr1_pub, "Public/cafecafe".to_string()); assert_eq!(account_id1_pub, "Public/cafecafe".to_string());
assert_eq!(addr2_priv, "Private/deadbeaf".to_string()); assert_eq!(account_id2_priv, "Private/deadbeaf".to_string());
} }
} }

View File

@ -1,5 +1,4 @@
use anyhow::Result; use anyhow::Result;
use integration_tests::main_tests_runner; use integration_tests::main_tests_runner;
pub const NUM_THREADS: usize = 8; pub const NUM_THREADS: usize = 8;

File diff suppressed because it is too large Load Diff

View File

@ -2,8 +2,7 @@ use std::time::Duration;
use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder;
use nssa::{ use nssa::{
Account, AccountId, Address, PrivacyPreservingTransaction, PrivateKey, PublicKey, Account, AccountId, PrivacyPreservingTransaction, PrivateKey, PublicKey, PublicTransaction,
PublicTransaction,
privacy_preserving_transaction::{self as pptx, circuit}, privacy_preserving_transaction::{self as pptx, circuit},
program::Program, program::Program,
public_transaction as putx, public_transaction as putx,
@ -15,13 +14,13 @@ use nssa_core::{
use sequencer_core::config::{AccountInitialData, CommitmentsInitialData, SequencerConfig}; use sequencer_core::config::{AccountInitialData, CommitmentsInitialData, SequencerConfig};
pub(crate) struct TpsTestManager { pub(crate) struct TpsTestManager {
public_keypairs: Vec<(PrivateKey, Address)>, public_keypairs: Vec<(PrivateKey, AccountId)>,
target_tps: u64, target_tps: u64,
} }
impl TpsTestManager { impl TpsTestManager {
/// Generates public account keypairs. These are used to populate the config and to generate valid /// Generates public account keypairs. These are used to populate the config and to generate
/// public transactions for the tps test. /// valid public transactions for the tps test.
pub(crate) fn new(target_tps: u64, number_transactions: usize) -> Self { pub(crate) fn new(target_tps: u64, number_transactions: usize) -> Self {
let public_keypairs = (1..(number_transactions + 2)) let public_keypairs = (1..(number_transactions + 2))
.map(|i| { .map(|i| {
@ -29,8 +28,8 @@ impl TpsTestManager {
private_key_bytes[..8].copy_from_slice(&i.to_le_bytes()); private_key_bytes[..8].copy_from_slice(&i.to_le_bytes());
let private_key = PrivateKey::try_new(private_key_bytes).unwrap(); let private_key = PrivateKey::try_new(private_key_bytes).unwrap();
let public_key = PublicKey::new_from_private_key(&private_key); let public_key = PublicKey::new_from_private_key(&private_key);
let address = Address::from(&public_key); let account_id = AccountId::from(&public_key);
(private_key, address) (private_key, account_id)
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
Self { Self {
@ -44,7 +43,6 @@ impl TpsTestManager {
Duration::from_secs_f64(number_transactions as f64 / self.target_tps as f64) Duration::from_secs_f64(number_transactions as f64 / self.target_tps as f64)
} }
///
/// Build a batch of public transactions to submit to the node. /// Build a batch of public transactions to submit to the node.
pub fn build_public_txs(&self) -> Vec<PublicTransaction> { pub fn build_public_txs(&self) -> Vec<PublicTransaction> {
// Create valid public transactions // Create valid public transactions
@ -71,15 +69,15 @@ impl TpsTestManager {
} }
/// Generates a sequencer configuration with initial balance in a number of public accounts. /// 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 /// The transactions generated with the function `build_public_txs` will be valid in a node
/// with the config from this method. /// started with the config from this method.
pub(crate) fn generate_tps_test_config(&self) -> SequencerConfig { pub(crate) fn generate_tps_test_config(&self) -> SequencerConfig {
// Create public public keypairs // Create public public keypairs
let initial_public_accounts = self let initial_public_accounts = self
.public_keypairs .public_keypairs
.iter() .iter()
.map(|(_, addr)| AccountInitialData { .map(|(_, account_id)| AccountInitialData {
addr: addr.to_string(), account_id: account_id.to_string(),
balance: 10, balance: 10,
}) })
.collect(); .collect();

View File

@ -6,7 +6,8 @@ use rand::{RngCore, rngs::OsRng};
use sha2::Digest; use sha2::Digest;
#[derive(Debug)] #[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 { pub struct EphemeralKeyHolder {
ephemeral_secret_key: EphemeralSecretKey, ephemeral_secret_key: EphemeralSecretKey,
} }

View File

@ -66,7 +66,7 @@ impl ChainIndex {
pub fn next_in_line(&self) -> ChainIndex { pub fn next_in_line(&self) -> ChainIndex {
let mut chain = self.0.clone(); let mut chain = self.0.clone();
//ToDo: Add overflow check // ToDo: Add overflow check
if let Some(last_p) = chain.last_mut() { if let Some(last_p) = chain.last_mut() {
*last_p += 1 *last_p += 1
} }

View File

@ -125,8 +125,8 @@ impl KeyNode for ChildKeysPrivate {
self.cci self.cci
} }
fn address(&self) -> nssa::Address { fn account_id(&self) -> nssa::AccountId {
nssa::Address::from(&self.value.0.nullifer_public_key) nssa::AccountId::from(&self.value.0.nullifer_public_key)
} }
} }

View File

@ -61,8 +61,8 @@ impl KeyNode for ChildKeysPublic {
self.cci self.cci
} }
fn address(&self) -> nssa::Address { fn account_id(&self) -> nssa::AccountId {
nssa::Address::from(&self.cpk) nssa::AccountId::from(&self.cpk)
} }
} }

View File

@ -18,7 +18,7 @@ pub mod traits;
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct KeyTree<N: KeyNode> { pub struct KeyTree<N: KeyNode> {
pub key_map: BTreeMap<ChainIndex, N>, pub key_map: BTreeMap<ChainIndex, N>,
pub addr_map: HashMap<nssa::Address, ChainIndex>, pub account_id_map: HashMap<nssa::AccountId, ChainIndex>,
} }
pub type KeyTreePublic = KeyTree<ChildKeysPublic>; pub type KeyTreePublic = KeyTree<ChildKeysPublic>;
@ -33,22 +33,28 @@ impl<N: KeyNode> KeyTree<N> {
.expect("SeedHolder seed is 64 bytes long"); .expect("SeedHolder seed is 64 bytes long");
let root_keys = N::root(seed_fit); let root_keys = N::root(seed_fit);
let address = root_keys.address(); let account_id = root_keys.account_id();
let key_map = BTreeMap::from_iter([(ChainIndex::root(), root_keys)]); let key_map = BTreeMap::from_iter([(ChainIndex::root(), root_keys)]);
let addr_map = HashMap::from_iter([(address, ChainIndex::root())]); let account_id_map = HashMap::from_iter([(account_id, ChainIndex::root())]);
Self { key_map, addr_map } Self {
key_map,
account_id_map,
}
} }
pub fn new_from_root(root: N) -> Self { pub fn new_from_root(root: N) -> Self {
let addr_map = HashMap::from_iter([(root.address(), ChainIndex::root())]); let account_id_map = HashMap::from_iter([(root.account_id(), ChainIndex::root())]);
let key_map = BTreeMap::from_iter([(ChainIndex::root(), root)]); let key_map = BTreeMap::from_iter([(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<u32> { pub fn find_next_last_child_of_id(&self, parent_id: &ChainIndex) -> Option<u32> {
if !self.key_map.contains_key(parent_id) { if !self.key_map.contains_key(parent_id) {
@ -90,7 +96,7 @@ impl<N: KeyNode> KeyTree<N> {
} }
} }
pub fn generate_new_node(&mut self, parent_cci: ChainIndex) -> Option<nssa::Address> { pub fn generate_new_node(&mut self, parent_cci: ChainIndex) -> Option<nssa::AccountId> {
let father_keys = self.key_map.get(&parent_cci)?; let father_keys = self.key_map.get(&parent_cci)?;
let next_child_id = self let next_child_id = self
.find_next_last_child_of_id(&parent_cci) .find_next_last_child_of_id(&parent_cci)
@ -99,28 +105,28 @@ impl<N: KeyNode> KeyTree<N> {
let child_keys = father_keys.nth_child(next_child_id); let child_keys = father_keys.nth_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.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<&N> { pub fn get_node(&self, account_id: nssa::AccountId) -> Option<&N> {
self.addr_map self.account_id_map
.get(&addr) .get(&account_id)
.and_then(|chain_id| self.key_map.get(chain_id)) .and_then(|chain_id| self.key_map.get(chain_id))
} }
pub fn get_node_mut(&mut self, addr: nssa::Address) -> Option<&mut N> { pub fn get_node_mut(&mut self, account_id: nssa::AccountId) -> Option<&mut N> {
self.addr_map self.account_id_map
.get(&addr) .get(&account_id)
.and_then(|chain_id| self.key_map.get_mut(chain_id)) .and_then(|chain_id| self.key_map.get_mut(chain_id))
} }
pub fn insert(&mut self, addr: nssa::Address, chain_index: ChainIndex, node: N) { pub fn insert(&mut self, account_id: nssa::AccountId, chain_index: ChainIndex, node: N) {
self.addr_map.insert(addr, chain_index.clone()); self.account_id_map.insert(account_id, chain_index.clone());
self.key_map.insert(chain_index, node); self.key_map.insert(chain_index, node);
} }
} }
@ -129,7 +135,7 @@ impl<N: KeyNode> KeyTree<N> {
mod tests { mod tests {
use std::str::FromStr; use std::str::FromStr;
use nssa::Address; use nssa::AccountId;
use super::*; use super::*;
@ -146,7 +152,7 @@ mod tests {
let tree = KeyTreePublic::new(&seed_holder); let tree = KeyTreePublic::new(&seed_holder);
assert!(tree.key_map.contains_key(&ChainIndex::root())); 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, 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, 159, 14, 238, 1, 192, 91, 8, 210, 165, 199, 41, 60, 104,
]))); ])));

View File

@ -10,5 +10,5 @@ pub trait KeyNode {
fn child_index(&self) -> Option<u32>; fn child_index(&self) -> Option<u32>;
fn address(&self) -> nssa::Address; fn account_id(&self) -> nssa::AccountId;
} }

View File

@ -12,7 +12,7 @@ pub mod key_tree;
pub mod secret_holders; pub mod secret_holders;
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
///Entrypoint to key management /// Entrypoint to key management
pub struct KeyChain { pub struct KeyChain {
pub secret_spending_key: SecretSpendingKey, pub secret_spending_key: SecretSpendingKey,
pub private_key_holder: PrivateKeyHolder, pub private_key_holder: PrivateKeyHolder,
@ -22,8 +22,8 @@ pub struct KeyChain {
impl KeyChain { impl KeyChain {
pub fn new_os_random() -> Self { pub fn new_os_random() -> Self {
//Currently dropping SeedHolder at the end of initialization. // Currently dropping SeedHolder at the end of initialization.
//Now entirely sure if we need it in the future. // Now entirely sure if we need it in the future.
let seed_holder = SeedHolder::new_os_random(); let seed_holder = SeedHolder::new_os_random();
let secret_spending_key = seed_holder.produce_top_secret_key_holder(); let secret_spending_key = seed_holder.produce_top_secret_key_holder();
@ -76,8 +76,7 @@ impl KeyChain {
mod tests { mod tests {
use aes_gcm::aead::OsRng; use aes_gcm::aead::OsRng;
use base58::ToBase58; use base58::ToBase58;
use k256::AffinePoint; use k256::{AffinePoint, elliptic_curve::group::GroupEncoding};
use k256::elliptic_curve::group::GroupEncoding;
use rand::RngCore; use rand::RngCore;
use super::*; use super::*;
@ -85,15 +84,18 @@ mod tests {
#[test] #[test]
fn test_new_os_random() { fn test_new_os_random() {
// Ensure that a new KeyChain instance can be created without errors. // 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 // 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] #[test]
fn test_calculate_shared_secret_receiver() { 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 // Generate a random ephemeral public key sender
let mut scalar = [0; 32]; let mut scalar = [0; 32];
@ -102,7 +104,7 @@ mod tests {
// Calculate shared secret // Calculate shared secret
let _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] #[test]
@ -119,7 +121,7 @@ mod tests {
let public_key = nssa::PublicKey::new_from_private_key(&pub_account_signing_key); 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!("======Prerequisites======");
println!(); println!();
@ -140,7 +142,7 @@ mod tests {
println!("======Public data======"); println!("======Public data======");
println!(); println!();
println!("Address{:?}", address.value().to_base58()); println!("Account {:?}", account.value().to_base58());
println!( println!(
"Nulifier public key {:?}", "Nulifier public key {:?}",
hex::encode(nullifer_public_key.to_byte_array()) hex::encode(nullifer_public_key.to_byte_array())

View File

@ -11,22 +11,23 @@ use sha2::{Digest, digest::FixedOutput};
const NSSA_ENTROPY_BYTES: [u8; 32] = [0; 32]; const NSSA_ENTROPY_BYTES: [u8; 32] = [0; 32];
#[derive(Debug)] #[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. /// Produces `TopSecretKeyHolder` objects.
pub struct SeedHolder { 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<u8>, pub(crate) seed: Vec<u8>,
} }
#[derive(Serialize, Deserialize, Debug, Clone)] #[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 struct SecretSpendingKey(pub(crate) [u8; 32]);
pub type IncomingViewingSecretKey = Scalar; pub type IncomingViewingSecretKey = Scalar;
pub type OutgoingViewingSecretKey = Scalar; pub type OutgoingViewingSecretKey = Scalar;
#[derive(Serialize, Deserialize, Debug, Clone)] #[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 struct PrivateKeyHolder {
pub nullifier_secret_key: NullifierSecretKey, pub nullifier_secret_key: NullifierSecretKey,
pub(crate) incoming_viewing_secret_key: IncomingViewingSecretKey, pub(crate) incoming_viewing_secret_key: IncomingViewingSecretKey,
@ -64,7 +65,7 @@ impl SeedHolder {
hash = hmac_sha512::HMAC::mac(hash, "NSSA_seed"); hash = hmac_sha512::HMAC::mac(hash, "NSSA_seed");
} }
//Safe unwrap // Safe unwrap
*hash.first_chunk::<32>().unwrap() *hash.first_chunk::<32>().unwrap()
} }

View File

@ -15,10 +15,10 @@ pub type PublicKey = AffinePoint;
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct NSSAUserData { pub struct NSSAUserData {
/// Default public accounts /// Default public accounts
pub default_pub_account_signing_keys: HashMap<nssa::Address, nssa::PrivateKey>, pub default_pub_account_signing_keys: HashMap<nssa::AccountId, nssa::PrivateKey>,
/// Default private accounts /// Default private accounts
pub default_user_private_accounts: pub default_user_private_accounts:
HashMap<nssa::Address, (KeyChain, nssa_core::account::Account)>, HashMap<nssa::AccountId, (KeyChain, nssa_core::account::Account)>,
/// Tree of public keys /// Tree of public keys
pub public_key_tree: KeyTreePublic, pub public_key_tree: KeyTreePublic,
/// Tree of private keys /// Tree of private keys
@ -27,13 +27,14 @@ pub struct NSSAUserData {
impl NSSAUserData { impl NSSAUserData {
fn valid_public_key_transaction_pairing_check( fn valid_public_key_transaction_pairing_check(
accounts_keys_map: &HashMap<nssa::Address, nssa::PrivateKey>, accounts_keys_map: &HashMap<nssa::AccountId, nssa::PrivateKey>,
) -> bool { ) -> bool {
let mut check_res = true; let mut check_res = true;
for (addr, key) in accounts_keys_map { for (account_id, key) in accounts_keys_map {
let expected_addr = nssa::Address::from(&nssa::PublicKey::new_from_private_key(key)); let expected_account_id =
if &expected_addr != addr { nssa::AccountId::from(&nssa::PublicKey::new_from_private_key(key));
println!("{}, {}", expected_addr, addr); if &expected_account_id != account_id {
println!("{}, {}", expected_account_id, account_id);
check_res = false; check_res = false;
} }
} }
@ -41,13 +42,13 @@ impl NSSAUserData {
} }
fn valid_private_key_transaction_pairing_check( fn valid_private_key_transaction_pairing_check(
accounts_keys_map: &HashMap<nssa::Address, (KeyChain, nssa_core::account::Account)>, accounts_keys_map: &HashMap<nssa::AccountId, (KeyChain, nssa_core::account::Account)>,
) -> bool { ) -> bool {
let mut check_res = true; let mut check_res = true;
for (addr, (key, _)) in accounts_keys_map { for (account_id, (key, _)) in accounts_keys_map {
let expected_addr = nssa::Address::from(&key.nullifer_public_key); let expected_account_id = nssa::AccountId::from(&key.nullifer_public_key);
if expected_addr != *addr { if expected_account_id != *account_id {
println!("{}, {}", expected_addr, addr); println!("{}, {}", expected_account_id, account_id);
check_res = false; check_res = false;
} }
} }
@ -55,9 +56,9 @@ impl NSSAUserData {
} }
pub fn new_with_accounts( pub fn new_with_accounts(
default_accounts_keys: HashMap<nssa::Address, nssa::PrivateKey>, default_accounts_keys: HashMap<nssa::AccountId, nssa::PrivateKey>,
default_accounts_key_chains: HashMap< default_accounts_key_chains: HashMap<
nssa::Address, nssa::AccountId,
(KeyChain, nssa_core::account::Account), (KeyChain, nssa_core::account::Account),
>, >,
public_key_tree: KeyTreePublic, public_key_tree: KeyTreePublic,
@ -65,13 +66,13 @@ impl NSSAUserData {
) -> Result<Self> { ) -> Result<Self> {
if !Self::valid_public_key_transaction_pairing_check(&default_accounts_keys) { if !Self::valid_public_key_transaction_pairing_check(&default_accounts_keys) {
anyhow::bail!( 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) { if !Self::valid_private_key_transaction_pairing_check(&default_accounts_key_chains) {
anyhow::bail!( 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 /// 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( pub fn generate_new_public_transaction_private_key(
&mut self, &mut self,
parent_cci: ChainIndex, parent_cci: ChainIndex,
) -> nssa::Address { ) -> nssa::AccountId {
self.public_key_tree.generate_new_node(parent_cci).unwrap() self.public_key_tree.generate_new_node(parent_cci).unwrap()
} }
/// Returns the signing key for public transaction signatures /// Returns the signing key for public transaction signatures
pub fn get_pub_account_signing_key( pub fn get_pub_account_signing_key(
&self, &self,
address: &nssa::Address, account_id: &nssa::AccountId,
) -> Option<&nssa::PrivateKey> { ) -> Option<&nssa::PrivateKey> {
//First seek in defaults // First seek in defaults
if let Some(key) = self.default_pub_account_signing_keys.get(address) { if let Some(key) = self.default_pub_account_signing_keys.get(account_id) {
Some(key) Some(key)
//Then seek in tree // Then seek in tree
} else { } 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 /// 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( pub fn generate_new_privacy_preserving_transaction_key_chain(
&mut self, &mut self,
parent_cci: ChainIndex, parent_cci: ChainIndex,
) -> nssa::Address { ) -> nssa::AccountId {
self.private_key_tree.generate_new_node(parent_cci).unwrap() self.private_key_tree.generate_new_node(parent_cci).unwrap()
} }
/// Returns the signing key for public transaction signatures /// Returns the signing key for public transaction signatures
pub fn get_private_account( pub fn get_private_account(
&self, &self,
address: &nssa::Address, account_id: &nssa::AccountId,
) -> Option<&(KeyChain, nssa_core::account::Account)> { ) -> Option<&(KeyChain, nssa_core::account::Account)> {
//First seek in defaults // First seek in defaults
if let Some(key) = self.default_user_private_accounts.get(address) { if let Some(key) = self.default_user_private_accounts.get(account_id) {
Some(key) Some(key)
//Then seek in tree // Then seek in tree
} else { } 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 /// Returns the signing key for public transaction signatures
pub fn get_private_account_mut( pub fn get_private_account_mut(
&mut self, &mut self,
address: &nssa::Address, account_id: &nssa::AccountId,
) -> Option<&mut (KeyChain, nssa_core::account::Account)> { ) -> Option<&mut (KeyChain, nssa_core::account::Account)> {
//First seek in defaults // First seek in defaults
if let Some(key) = self.default_user_private_accounts.get_mut(address) { if let Some(key) = self.default_user_private_accounts.get_mut(account_id) {
Some(key) Some(key)
//Then seek in tree // Then seek in tree
} else { } 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() { fn test_new_account() {
let mut user_data = NSSAUserData::default(); let mut user_data = NSSAUserData::default();
let addr_pub = user_data.generate_new_public_transaction_private_key(ChainIndex::root()); let account_id_pub =
let addr_private = 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()); 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); 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); assert!(is_key_chain_generated);
let addr_private_str = addr_private.to_string(); let account_id_private_str = account_id_private.to_string();
println!("{addr_private_str:#?}"); println!("{account_id_private_str:#?}");
let key_chain = &user_data.get_private_account(&addr_private).unwrap().0; let key_chain = &user_data
.get_private_account(&account_id_private)
.unwrap()
.0;
println!("{key_chain:#?}"); println!("{key_chain:#?}");
} }
} }

View File

@ -4,3 +4,7 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
tokio = { workspace = true, features = ["sync"] }
[dev-dependencies]
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }

View File

@ -1,231 +1,99 @@
use std::collections::VecDeque; use tokio::sync::mpsc::{Receiver, Sender};
pub struct MemPool<Item> { pub struct MemPool<T> {
items: VecDeque<Item>, receiver: Receiver<T>,
} }
impl<Item> MemPool<Item> { impl<T> MemPool<T> {
pub fn new() -> Self { pub fn new(max_size: usize) -> (Self, MemPoolHandle<T>) {
Self { let (sender, receiver) = tokio::sync::mpsc::channel(max_size);
items: VecDeque::new(),
} let mem_pool = Self { receiver };
let sender = MemPoolHandle::new(sender);
(mem_pool, sender)
} }
pub fn pop_last(&mut self) -> Option<Item> { pub fn pop(&mut self) -> Option<T> {
self.items.pop_front() use tokio::sync::mpsc::error::TryRecvError;
}
pub fn peek_last(&self) -> Option<&Item> { match self.receiver.try_recv() {
self.items.front() Ok(item) => Some(item),
} Err(TryRecvError::Empty) => None,
Err(TryRecvError::Disconnected) => {
pub fn push_item(&mut self, item: Item) { panic!("Mempool senders disconnected, cannot receive items, this is a bug")
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<Item> {
let mut ret_vec = vec![];
for _ in 0..size {
let item = self.pop_last();
match item {
Some(item) => ret_vec.push(item),
None => break,
} }
} }
ret_vec
}
pub fn drain_size(&mut self, remainder: usize) -> Vec<Item> {
self.pop_size(self.len().saturating_sub(remainder))
} }
} }
impl<Item> Default for MemPool<Item> { pub struct MemPoolHandle<T> {
fn default() -> Self { sender: Sender<T>,
Self::new() }
impl<T> MemPoolHandle<T> {
fn new(sender: Sender<T>) -> 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<T>> {
self.sender.send(item).await
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::vec; use tokio::test;
use super::*; use super::*;
pub type ItemId = u64; #[test]
async fn test_mempool_new() {
#[derive(Debug, PartialEq, Eq)] let (mut pool, _handle): (MemPool<u64>, _) = MemPool::new(10);
pub struct TestItem { assert_eq!(pool.pop(), None);
id: ItemId,
}
fn test_item_with_id(id: u64) -> TestItem {
TestItem { id }
} }
#[test] #[test]
fn test_create_empty_mempool() { async fn test_push_and_pop() {
let _: MemPool<TestItem> = MemPool::new(); 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] #[test]
fn test_mempool_new() { async fn test_multiple_push_pop() {
let pool: MemPool<TestItem> = MemPool::new(); let (mut pool, handle) = MemPool::new(10);
assert!(pool.is_empty());
assert_eq!(pool.len(), 0); 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] #[test]
fn test_push_item() { async fn test_pop_empty() {
let mut pool = MemPool::new(); let (mut pool, _handle): (MemPool<u64>, _) = MemPool::new(10);
pool.push_item(test_item_with_id(1)); assert_eq!(pool.pop(), None);
assert!(!pool.is_empty());
assert_eq!(pool.len(), 1);
} }
#[test] #[test]
fn test_pop_last() { async fn test_max_size() {
let mut pool = MemPool::new(); let (mut pool, handle) = MemPool::new(2);
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);
}
#[test] handle.push(1).await.unwrap();
fn test_peek_last() { handle.push(2).await.unwrap();
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)));
}
#[test] // This should block if buffer is full, but we'll use try_send in a real scenario
fn test_pop_size() { // For now, just verify we can pop items
let mut pool = MemPool::new(); assert_eq!(pool.pop(), Some(1));
pool.push_item(test_item_with_id(1)); assert_eq!(pool.pop(), Some(2));
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<TestItem> = 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<TestItem> = 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<TestItem> = 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);
} }
} }

View File

@ -1,6 +1,12 @@
use crate::{address::Address, program::ProgramId}; #[cfg(feature = "host")]
use std::{fmt::Display, str::FromStr};
#[cfg(feature = "host")]
use base58::{FromBase58, ToBase58};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::program::ProgramId;
pub type Nonce = u128; pub type Nonce = u128;
pub type Data = Vec<u8>; pub type Data = Vec<u8>;
@ -14,8 +20,6 @@ pub struct Account {
pub nonce: Nonce, pub nonce: Nonce,
} }
pub type AccountId = Address;
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
#[cfg_attr(any(feature = "host", test), derive(Debug, PartialEq, Eq))] #[cfg_attr(any(feature = "host", test), derive(Debug, PartialEq, Eq))]
pub struct AccountWithMetadata { pub struct AccountWithMetadata {
@ -35,11 +39,68 @@ impl AccountWithMetadata {
} }
} }
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
#[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<Self, Self::Err> {
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)] #[cfg(test)]
mod tests { mod tests {
use crate::program::DEFAULT_PROGRAM_ID;
use super::*; use super::*;
use crate::program::DEFAULT_PROGRAM_ID;
#[test] #[test]
fn test_zero_balance_account_data_creation() { fn test_zero_balance_account_data_creation() {
@ -84,4 +145,32 @@ mod tests {
assert!(new_acc_with_metadata.is_authorized); assert!(new_acc_with_metadata.is_authorized);
assert_eq!(new_acc_with_metadata.account_id, fingerprint); 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::<AccountId>().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::<AccountId>().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::<AccountId>().unwrap_err();
assert!(matches!(result, AccountIdError::InvalidLength(_)));
}
} }

View File

@ -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<Self, Self::Err> {
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::<Address>().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::<Address>().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::<Address>().unwrap_err();
assert!(matches!(result, AddressError::InvalidLength(_)));
}
}

View File

@ -38,12 +38,13 @@ impl PrivacyPreservingCircuitOutput {
#[cfg(feature = "host")] #[cfg(feature = "host")]
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use risc0_zkvm::serde::from_slice;
use super::*; use super::*;
use crate::{ use crate::{
Commitment, Nullifier, NullifierPublicKey, Commitment, Nullifier, NullifierPublicKey,
account::{Account, AccountId, AccountWithMetadata}, account::{Account, AccountId, AccountWithMetadata},
}; };
use risc0_zkvm::serde::from_slice;
#[test] #[test]
fn test_privacy_preserving_circuit_output_to_bytes_is_compatible_with_from_slice() { fn test_privacy_preserving_circuit_output_to_bytes_is_compatible_with_from_slice() {

View File

@ -1,25 +1,20 @@
// TODO: Consider switching to deriving Borsh // TODO: Consider switching to deriving Borsh
#[cfg(feature = "host")] #[cfg(feature = "host")]
use std::io::Cursor; use std::io::Cursor;
#[cfg(feature = "host")] #[cfg(feature = "host")]
use std::io::Read; 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")] #[cfg(feature = "host")]
use crate::Nullifier; 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 { impl Account {
pub fn to_bytes(&self) -> Vec<u8> { pub fn to_bytes(&self) -> Vec<u8> {
@ -55,7 +50,7 @@ impl Account {
cursor.read_exact(&mut u128_bytes)?; cursor.read_exact(&mut u128_bytes)?;
let nonce = u128::from_le_bytes(u128_bytes); let nonce = u128::from_le_bytes(u128_bytes);
//data // data
cursor.read_exact(&mut u32_bytes)?; cursor.read_exact(&mut u32_bytes)?;
let data_length = u32::from_le_bytes(u32_bytes); let data_length = u32::from_le_bytes(u32_bytes);
let mut data = vec![0; data_length as usize]; let mut data = vec![0; data_length as usize];

View File

@ -1,5 +1,3 @@
use serde::{Deserialize, Serialize};
use k256::{ use k256::{
AffinePoint, EncodedPoint, FieldBytes, ProjectivePoint, AffinePoint, EncodedPoint, FieldBytes, ProjectivePoint,
elliptic_curve::{ elliptic_curve::{
@ -7,6 +5,7 @@ use k256::{
sec1::{FromEncodedPoint, ToEncodedPoint}, sec1::{FromEncodedPoint, ToEncodedPoint},
}, },
}; };
use serde::{Deserialize, Serialize};
use crate::{SharedSecretKey, encryption::Scalar}; use crate::{SharedSecretKey, encryption::Scalar};

View File

@ -6,8 +6,6 @@ pub mod encryption;
mod nullifier; mod nullifier;
pub mod program; pub mod program;
pub mod address;
pub use circuit_io::{PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput}; pub use circuit_io::{PrivacyPreservingCircuitInput, PrivacyPreservingCircuitOutput};
pub use commitment::{ pub use commitment::{
Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, DUMMY_COMMITMENT_HASH, MembershipProof, Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, DUMMY_COMMITMENT_HASH, MembershipProof,

View File

@ -1,8 +1,8 @@
use crate::account::{Account, AccountWithMetadata}; use risc0_zkvm::{DeserializeOwned, guest::env, serde::Deserializer};
use risc0_zkvm::serde::Deserializer;
use risc0_zkvm::{DeserializeOwned, guest::env};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::account::{Account, AccountWithMetadata};
pub type ProgramId = [u32; 8]; pub type ProgramId = [u32; 8];
pub type InstructionData = Vec<u32>; pub type InstructionData = Vec<u32>;
pub const DEFAULT_PROGRAM_ID: ProgramId = [0; 8]; pub const DEFAULT_PROGRAM_ID: ProgramId = [0; 8];
@ -103,7 +103,8 @@ pub fn validate_execution(
return false; 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() { if post.program_owner == DEFAULT_PROGRAM_ID && pre.account != Account::default() {
return false; return false;
} }

View File

@ -7,7 +7,7 @@ use nssa_core::{
}; };
use crate::{ use crate::{
Address, PrivacyPreservingTransaction, PublicKey, Signature, AccountId, PrivacyPreservingTransaction, PublicKey, Signature,
error::NssaError, error::NssaError,
privacy_preserving_transaction::{ privacy_preserving_transaction::{
circuit::Proof, circuit::Proof,
@ -48,11 +48,11 @@ impl Message {
pub(crate) fn to_bytes(&self) -> Vec<u8> { pub(crate) fn to_bytes(&self) -> Vec<u8> {
let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec(); let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec();
// Public addresses // Public account_ids
let public_addresses_len: u32 = self.public_addresses.len() as u32; let public_account_ids_len: u32 = self.public_account_ids.len() as u32;
bytes.extend_from_slice(&public_addresses_len.to_le_bytes()); bytes.extend_from_slice(&public_account_ids_len.to_le_bytes());
for address in &self.public_addresses { for account_id in &self.public_account_ids {
bytes.extend_from_slice(address.value()); bytes.extend_from_slice(account_id.value());
} }
// Nonces // Nonces
let nonces_len = self.nonces.len() as u32; let nonces_len = self.nonces.len() as u32;
@ -108,14 +108,14 @@ impl Message {
let mut len_bytes = [0u8; 4]; let mut len_bytes = [0u8; 4];
// Public addresses // Public account_ids
cursor.read_exact(&mut len_bytes)?; cursor.read_exact(&mut len_bytes)?;
let public_addresses_len = u32::from_le_bytes(len_bytes) as usize; let public_account_ids_len = u32::from_le_bytes(len_bytes) as usize;
let mut public_addresses = Vec::with_capacity(public_addresses_len); let mut public_account_ids = Vec::with_capacity(public_account_ids_len);
for _ in 0..public_addresses_len { for _ in 0..public_account_ids_len {
let mut value = [0u8; 32]; let mut value = [0u8; 32];
cursor.read_exact(&mut value)?; cursor.read_exact(&mut value)?;
public_addresses.push(Address::new(value)) public_account_ids.push(AccountId::new(value))
} }
// Nonces // Nonces
@ -164,7 +164,7 @@ impl Message {
} }
Ok(Self { Ok(Self {
public_addresses, public_account_ids,
nonces, nonces,
public_post_states, public_post_states,
encrypted_private_post_states, encrypted_private_post_states,

View File

@ -5,7 +5,7 @@ use std::io::{Cursor, Read};
use nssa_core::program::ProgramId; use nssa_core::program::ProgramId;
use crate::{ use crate::{
Address, PublicKey, PublicTransaction, Signature, AccountId, PublicKey, PublicTransaction, Signature,
error::NssaError, error::NssaError,
public_transaction::{Message, WitnessSet}, public_transaction::{Message, WitnessSet},
}; };
@ -16,20 +16,22 @@ const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] =
impl Message { impl Message {
/// Serializes a `Message` into bytes in the following layout: /// Serializes a `Message` into bytes in the following layout:
/// PREFIX || <program_id> (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) /// PREFIX || <program_id> (4 bytes LE) * 8 || account_ids_len (4 bytes LE) || account_ids (32
/// Integers and words are encoded in little-endian byte order, and fields appear in the above order. /// 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<u8> { pub(crate) fn to_bytes(&self) -> Vec<u8> {
let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec(); let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec();
// program_id: [u32; 8] // program_id: [u32; 8]
for word in &self.program_id { for word in &self.program_id {
bytes.extend_from_slice(&word.to_le_bytes()); bytes.extend_from_slice(&word.to_le_bytes());
} }
// addresses: Vec<[u8;32]> // account_ids: Vec<[u8;32]>
// serialize length as u32 little endian, then all addresses concatenated // serialize length as u32 little endian, then all account_ids concatenated
let addresses_len = self.addresses.len() as u32; let account_ids_len = self.account_ids.len() as u32;
bytes.extend(&addresses_len.to_le_bytes()); bytes.extend(&account_ids_len.to_le_bytes());
for addr in &self.addresses { for account_id in &self.account_ids {
bytes.extend_from_slice(addr.value()); bytes.extend_from_slice(account_id.value());
} }
// nonces: Vec<u128> // nonces: Vec<u128>
// serialize length as u32 little endian, then all nonces concatenated in LE // serialize length as u32 little endian, then all nonces concatenated in LE
@ -39,7 +41,7 @@ impl Message {
bytes.extend(&nonce.to_le_bytes()); bytes.extend(&nonce.to_le_bytes());
} }
// instruction_data: Vec<u32> // instruction_data: Vec<u32>
// serialize length as u32 little endian, then all addresses concatenated // serialize length as u32 little endian, then all account_ids concatenated
let instr_len = self.instruction_data.len() as u32; let instr_len = self.instruction_data.len() as u32;
bytes.extend(&instr_len.to_le_bytes()); bytes.extend(&instr_len.to_le_bytes());
for word in &self.instruction_data { for word in &self.instruction_data {
@ -68,12 +70,12 @@ impl Message {
} }
this this
}; };
let addresses_len = u32_from_cursor(cursor)?; let account_ids_len = u32_from_cursor(cursor)?;
let mut addresses = Vec::with_capacity(addresses_len as usize); let mut account_ids = Vec::with_capacity(account_ids_len as usize);
for _ in 0..addresses_len { for _ in 0..account_ids_len {
let mut value = [0u8; 32]; let mut value = [0u8; 32];
cursor.read_exact(&mut value)?; cursor.read_exact(&mut value)?;
addresses.push(Address::new(value)) account_ids.push(AccountId::new(value))
} }
let nonces_len = u32_from_cursor(cursor)?; let nonces_len = u32_from_cursor(cursor)?;
let mut nonces = Vec::with_capacity(nonces_len as usize); let mut nonces = Vec::with_capacity(nonces_len as usize);
@ -90,7 +92,7 @@ impl Message {
} }
Ok(Self { Ok(Self {
program_id, program_id,
addresses, account_ids,
nonces, nonces,
instruction_data, instruction_data,
}) })

View File

@ -18,14 +18,11 @@ mod signature;
mod state; mod state;
pub use nssa_core::account::{Account, AccountId}; pub use nssa_core::account::{Account, AccountId};
pub use nssa_core::address::Address;
pub use privacy_preserving_transaction::{ pub use privacy_preserving_transaction::{
PrivacyPreservingTransaction, circuit::execute_and_prove, PrivacyPreservingTransaction, circuit::execute_and_prove,
}; };
pub use program_deployment_transaction::ProgramDeploymentTransaction; pub use program_deployment_transaction::ProgramDeploymentTransaction;
pub use program_methods::PRIVACY_PRESERVING_CIRCUIT_ID; pub use program_methods::PRIVACY_PRESERVING_CIRCUIT_ID;
pub use public_transaction::PublicTransaction; pub use public_transaction::PublicTransaction;
pub use signature::PrivateKey; pub use signature::{PrivateKey, PublicKey, Signature};
pub use signature::PublicKey;
pub use signature::Signature;
pub use state::V02State; pub use state::V02State;

View File

@ -43,6 +43,7 @@ impl MerkleTree {
(1 << (capacity_depth - tree_depth)) - 1 (1 << (capacity_depth - tree_depth)) - 1
} }
} }
/// Number of levels required to hold all nodes /// Number of levels required to hold all nodes
fn depth(&self) -> usize { fn depth(&self) -> usize {
self.length.next_power_of_two().trailing_zeros() as usize self.length.next_power_of_two().trailing_zeros() as usize

View File

@ -6,9 +6,11 @@ use nssa_core::{
}; };
use risc0_zkvm::{ExecutorEnv, InnerReceipt, Receipt, default_prover}; use risc0_zkvm::{ExecutorEnv, InnerReceipt, Receipt, default_prover};
use crate::{error::NssaError, program::Program}; use crate::{
error::NssaError,
use crate::program_methods::{PRIVACY_PRESERVING_CIRCUIT_ELF, PRIVACY_PRESERVING_CIRCUIT_ID}; program::Program,
program_methods::{PRIVACY_PRESERVING_CIRCUIT_ELF, PRIVACY_PRESERVING_CIRCUIT_ID},
};
/// Proof of the privacy preserving execution circuit /// Proof of the privacy preserving execution circuit
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
@ -95,6 +97,7 @@ mod tests {
account::{Account, AccountId, AccountWithMetadata}, account::{Account, AccountId, AccountWithMetadata},
}; };
use super::*;
use crate::{ use crate::{
privacy_preserving_transaction::circuit::execute_and_prove, privacy_preserving_transaction::circuit::execute_and_prove,
program::Program, program::Program,
@ -104,8 +107,6 @@ mod tests {
}, },
}; };
use super::*;
#[test] #[test]
fn prove_privacy_preserving_execution_circuit_public_and_private_pre_accounts() { fn prove_privacy_preserving_execution_circuit_public_and_private_pre_accounts() {
let recipient_keys = test_private_account_keys_1(); let recipient_keys = test_private_account_keys_1();

View File

@ -5,7 +5,7 @@ use nssa_core::{
}; };
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use crate::{Address, error::NssaError}; use crate::{AccountId, error::NssaError};
pub type ViewTag = u8; pub type ViewTag = u8;
@ -44,7 +44,7 @@ impl EncryptedAccountData {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Message { pub struct Message {
pub(crate) public_addresses: Vec<Address>, pub(crate) public_account_ids: Vec<AccountId>,
pub(crate) nonces: Vec<Nonce>, pub(crate) nonces: Vec<Nonce>,
pub(crate) public_post_states: Vec<Account>, pub(crate) public_post_states: Vec<Account>,
pub encrypted_private_post_states: Vec<EncryptedAccountData>, pub encrypted_private_post_states: Vec<EncryptedAccountData>,
@ -54,7 +54,7 @@ pub struct Message {
impl Message { impl Message {
pub fn try_from_circuit_output( pub fn try_from_circuit_output(
public_addresses: Vec<Address>, public_account_ids: Vec<AccountId>,
nonces: Vec<Nonce>, nonces: Vec<Nonce>,
public_keys: Vec<( public_keys: Vec<(
NullifierPublicKey, NullifierPublicKey,
@ -78,7 +78,7 @@ impl Message {
}) })
.collect(); .collect();
Ok(Self { Ok(Self {
public_addresses, public_account_ids,
nonces, nonces,
public_post_states: output.public_post_states, public_post_states: output.public_post_states,
encrypted_private_post_states, encrypted_private_post_states,
@ -100,7 +100,7 @@ pub mod tests {
use sha2::{Digest, Sha256}; use sha2::{Digest, Sha256};
use crate::{ use crate::{
Address, AccountId,
privacy_preserving_transaction::message::{EncryptedAccountData, Message}, privacy_preserving_transaction::message::{EncryptedAccountData, Message},
}; };
@ -114,7 +114,7 @@ pub mod tests {
let npk1 = NullifierPublicKey::from(&nsk1); let npk1 = NullifierPublicKey::from(&nsk1);
let npk2 = NullifierPublicKey::from(&nsk2); 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]; let nonces = vec![1, 2, 3];
@ -131,7 +131,7 @@ pub mod tests {
)]; )];
Message { Message {
public_addresses: public_addresses.clone(), public_account_ids: public_account_ids.clone(),
nonces: nonces.clone(), nonces: nonces.clone(),
public_post_states: public_post_states.clone(), public_post_states: public_post_states.clone(),
encrypted_private_post_states: encrypted_private_post_states.clone(), encrypted_private_post_states: encrypted_private_post_states.clone(),

View File

@ -5,13 +5,12 @@ use nssa_core::{
account::{Account, AccountWithMetadata}, account::{Account, AccountWithMetadata},
}; };
use crate::error::NssaError; use super::{message::Message, witness_set::WitnessSet};
use crate::privacy_preserving_transaction::circuit::Proof; use crate::{
use crate::privacy_preserving_transaction::message::EncryptedAccountData; AccountId, V02State,
use crate::{Address, 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)]
pub struct PrivacyPreservingTransaction { pub struct PrivacyPreservingTransaction {
@ -30,7 +29,7 @@ impl PrivacyPreservingTransaction {
pub(crate) fn validate_and_produce_public_state_diff( pub(crate) fn validate_and_produce_public_state_diff(
&self, &self,
state: &V02State, state: &V02State,
) -> Result<HashMap<Address, Account>, NssaError> { ) -> Result<HashMap<AccountId, Account>, NssaError> {
let message = &self.message; let message = &self.message;
let witness_set = &self.witness_set; let witness_set = &self.witness_set;
@ -41,10 +40,10 @@ impl PrivacyPreservingTransaction {
)); ));
} }
// 2. Check there are no duplicate addresses in the public_addresses list. // 2. Check there are no duplicate account_ids in the public_account_ids list.
if n_unique(&message.public_addresses) != message.public_addresses.len() { if n_unique(&message.public_account_ids) != message.public_account_ids.len() {
return Err(NssaError::InvalidInput( return Err(NssaError::InvalidInput(
"Duplicate addresses found in message".into(), "Duplicate account_ids found in message".into(),
)); ));
} }
@ -77,10 +76,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. // Check nonces corresponds to the current nonces on the public state.
for (address, nonce) in signer_addresses.iter().zip(&message.nonces) { for (account_id, nonce) in signer_account_ids.iter().zip(&message.nonces) {
let current_nonce = state.get_account_by_address(address).nonce; let current_nonce = state.get_account_by_id(account_id).nonce;
if current_nonce != *nonce { if current_nonce != *nonce {
return Err(NssaError::InvalidInput("Nonce mismatch".into())); return Err(NssaError::InvalidInput("Nonce mismatch".into()));
} }
@ -88,13 +87,13 @@ impl PrivacyPreservingTransaction {
// Build pre_states for proof verification // Build pre_states for proof verification
let public_pre_states: Vec<_> = message let public_pre_states: Vec<_> = message
.public_addresses .public_account_ids
.iter() .iter()
.map(|address| { .map(|account_id| {
AccountWithMetadata::new( AccountWithMetadata::new(
state.get_account_by_address(address), state.get_account_by_id(account_id),
signer_addresses.contains(address), signer_account_ids.contains(account_id),
*address, *account_id,
) )
}) })
.collect(); .collect();
@ -116,7 +115,7 @@ impl PrivacyPreservingTransaction {
state.check_nullifiers_are_valid(&message.new_nullifiers)?; state.check_nullifiers_are_valid(&message.new_nullifiers)?;
Ok(message Ok(message
.public_addresses .public_account_ids
.iter() .iter()
.cloned() .cloned()
.zip(message.public_post_states.clone()) .zip(message.public_post_states.clone())
@ -131,11 +130,11 @@ impl PrivacyPreservingTransaction {
&self.witness_set &self.witness_set
} }
pub(crate) fn signer_addresses(&self) -> Vec<Address> { pub(crate) fn signer_account_ids(&self) -> Vec<AccountId> {
self.witness_set self.witness_set
.signatures_and_public_keys() .signatures_and_public_keys()
.iter() .iter()
.map(|(_, public_key)| Address::from(public_key)) .map(|(_, public_key)| AccountId::from(public_key))
.collect() .collect()
} }
} }
@ -174,17 +173,17 @@ fn n_unique<T: Eq + Hash>(data: &[T]) -> usize {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::{
Address, PrivacyPreservingTransaction, PrivateKey, PublicKey, AccountId, PrivacyPreservingTransaction, PrivateKey, PublicKey,
privacy_preserving_transaction::{ privacy_preserving_transaction::{
circuit::Proof, message::tests::message_for_tests, witness_set::WitnessSet, 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 key1 = PrivateKey::try_new([1; 32]).unwrap();
let key2 = PrivateKey::try_new([2; 32]).unwrap(); let key2 = PrivateKey::try_new([2; 32]).unwrap();
let addr1 = Address::from(&PublicKey::new_from_private_key(&key1)); let addr1 = AccountId::from(&PublicKey::new_from_private_key(&key1));
let addr2 = Address::from(&PublicKey::new_from_private_key(&key2)); let addr2 = AccountId::from(&PublicKey::new_from_private_key(&key2));
(key1, key2, addr1, addr2) (key1, key2, addr1, addr2)
} }

View File

@ -1,13 +1,14 @@
use crate::program_methods::{AUTHENTICATED_TRANSFER_ELF, PINATA_ELF, TOKEN_ELF};
use nssa_core::{ use nssa_core::{
account::AccountWithMetadata, account::AccountWithMetadata,
program::{InstructionData, ProgramId, ProgramOutput}, program::{InstructionData, ProgramId, ProgramOutput},
}; };
use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor, serde::to_vec}; use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor, serde::to_vec};
use serde::Serialize; 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. /// Maximum number of cycles for a public execution.
/// TODO: Make this variable when fees are implemented /// TODO: Make this variable when fees are implemented
@ -107,13 +108,15 @@ impl Program {
#[cfg(test)] #[cfg(test)]
mod tests { 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 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 { impl Program {
/// A program that changes the nonce of an account /// A program that changes the nonce of an account

View File

@ -4,12 +4,12 @@ use nssa_core::{
}; };
use serde::Serialize; 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)]
pub struct Message { pub struct Message {
pub(crate) program_id: ProgramId, pub(crate) program_id: ProgramId,
pub(crate) addresses: Vec<Address>, pub(crate) account_ids: Vec<AccountId>,
pub(crate) nonces: Vec<Nonce>, pub(crate) nonces: Vec<Nonce>,
pub(crate) instruction_data: InstructionData, pub(crate) instruction_data: InstructionData,
} }
@ -17,14 +17,14 @@ pub struct Message {
impl Message { impl Message {
pub fn try_new<T: Serialize>( pub fn try_new<T: Serialize>(
program_id: ProgramId, program_id: ProgramId,
addresses: Vec<Address>, account_ids: Vec<AccountId>,
nonces: Vec<Nonce>, nonces: Vec<Nonce>,
instruction: T, instruction: T,
) -> Result<Self, NssaError> { ) -> Result<Self, NssaError> {
let instruction_data = Program::serialize_instruction(instruction)?; let instruction_data = Program::serialize_instruction(instruction)?;
Ok(Self { Ok(Self {
program_id, program_id,
addresses, account_ids,
nonces, nonces,
instruction_data, instruction_data,
}) })

View File

@ -1,8 +1,7 @@
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use nssa_core::{ use nssa_core::{
account::{Account, AccountWithMetadata}, account::{Account, AccountId, AccountWithMetadata},
address::Address,
program::{DEFAULT_PROGRAM_ID, validate_execution}, program::{DEFAULT_PROGRAM_ID, validate_execution},
}; };
use sha2::{Digest, digest::FixedOutput}; use sha2::{Digest, digest::FixedOutput};
@ -36,11 +35,11 @@ impl PublicTransaction {
&self.witness_set &self.witness_set
} }
pub(crate) fn signer_addresses(&self) -> Vec<Address> { pub(crate) fn signer_account_ids(&self) -> Vec<AccountId> {
self.witness_set self.witness_set
.signatures_and_public_keys() .signatures_and_public_keys()
.iter() .iter()
.map(|(_, public_key)| Address::from(public_key)) .map(|(_, public_key)| AccountId::from(public_key))
.collect() .collect()
} }
@ -54,14 +53,14 @@ impl PublicTransaction {
pub(crate) fn validate_and_produce_public_state_diff( pub(crate) fn validate_and_produce_public_state_diff(
&self, &self,
state: &V02State, state: &V02State,
) -> Result<HashMap<Address, Account>, NssaError> { ) -> Result<HashMap<AccountId, Account>, NssaError> {
let message = self.message(); let message = self.message();
let witness_set = self.witness_set(); let witness_set = self.witness_set();
// All addresses must be different // All account_ids must be different
if message.addresses.iter().collect::<HashSet<_>>().len() != message.addresses.len() { if message.account_ids.iter().collect::<HashSet<_>>().len() != message.account_ids.len() {
return Err(NssaError::InvalidInput( return Err(NssaError::InvalidInput(
"Duplicate addresses found in message".into(), "Duplicate account_ids found in message".into(),
)); ));
} }
@ -79,10 +78,10 @@ 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. // Check nonces corresponds to the current nonces on the public state.
for (address, nonce) in signer_addresses.iter().zip(&message.nonces) { for (account_id, nonce) in signer_account_ids.iter().zip(&message.nonces) {
let current_nonce = state.get_account_by_address(address).nonce; let current_nonce = state.get_account_by_id(account_id).nonce;
if current_nonce != *nonce { if current_nonce != *nonce {
return Err(NssaError::InvalidInput("Nonce mismatch".into())); return Err(NssaError::InvalidInput("Nonce mismatch".into()));
} }
@ -90,18 +89,18 @@ impl PublicTransaction {
// Build pre_states for execution // Build pre_states for execution
let mut input_pre_states: Vec<_> = message let mut input_pre_states: Vec<_> = message
.addresses .account_ids
.iter() .iter()
.map(|address| { .map(|account_id| {
AccountWithMetadata::new( AccountWithMetadata::new(
state.get_account_by_address(address), state.get_account_by_id(account_id),
signer_addresses.contains(address), signer_account_ids.contains(account_id),
*address, *account_id,
) )
}) })
.collect(); .collect();
let mut state_diff: HashMap<Address, Account> = HashMap::new(); let mut state_diff: HashMap<AccountId, Account> = HashMap::new();
let mut program_id = message.program_id; let mut program_id = message.program_id;
let mut instruction_data = message.instruction_data.clone(); let mut instruction_data = message.instruction_data.clone();
@ -189,17 +188,17 @@ pub mod tests {
use sha2::{Digest, digest::FixedOutput}; use sha2::{Digest, digest::FixedOutput};
use crate::{ use crate::{
Address, PrivateKey, PublicKey, PublicTransaction, Signature, V02State, AccountId, PrivateKey, PublicKey, PublicTransaction, Signature, V02State,
error::NssaError, error::NssaError,
program::Program, program::Program,
public_transaction::{Message, WitnessSet}, 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 key1 = PrivateKey::try_new([1; 32]).unwrap();
let key2 = PrivateKey::try_new([2; 32]).unwrap(); let key2 = PrivateKey::try_new([2; 32]).unwrap();
let addr1 = Address::from(&PublicKey::new_from_private_key(&key1)); let addr1 = AccountId::from(&PublicKey::new_from_private_key(&key1));
let addr2 = Address::from(&PublicKey::new_from_private_key(&key2)); let addr2 = AccountId::from(&PublicKey::new_from_private_key(&key2));
(key1, key2, addr1, addr2) (key1, key2, addr1, addr2)
} }
@ -248,20 +247,20 @@ pub mod tests {
} }
#[test] #[test]
fn test_signer_addresses() { fn test_signer_account_ids() {
let tx = transaction_for_tests(); let tx = transaction_for_tests();
let expected_signer_addresses = vec![ let expected_signer_account_ids = vec![
Address::new([ AccountId::new([
208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9, 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, 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, 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, 141, 98, 237, 6, 207, 46, 20, 121, 246, 222, 248, 154, 57, 188,
]), ]),
]; ];
let signer_addresses = tx.signer_addresses(); let signer_account_ids = tx.signer_account_ids();
assert_eq!(signer_addresses, expected_signer_addresses); assert_eq!(signer_account_ids, expected_signer_account_ids);
} }
#[test] #[test]
@ -286,7 +285,7 @@ pub mod tests {
} }
#[test] #[test]
fn test_address_list_cant_have_duplicates() { fn test_account_id_list_cant_have_duplicates() {
let (key1, _, addr1, _) = keys_for_tests(); let (key1, _, addr1, _) = keys_for_tests();
let state = state_for_tests(); let state = state_for_tests();
let nonces = vec![0, 0]; let nonces = vec![0, 0];

View File

@ -39,9 +39,8 @@ impl WitnessSet {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::Address;
use super::*; use super::*;
use crate::AccountId;
#[test] #[test]
fn test_for_message_constructor() { fn test_for_message_constructor() {
@ -49,8 +48,8 @@ mod tests {
let key2 = PrivateKey::try_new([2; 32]).unwrap(); let key2 = PrivateKey::try_new([2; 32]).unwrap();
let pubkey1 = PublicKey::new_from_private_key(&key1); let pubkey1 = PublicKey::new_from_private_key(&key1);
let pubkey2 = PublicKey::new_from_private_key(&key2); let pubkey2 = PublicKey::new_from_private_key(&key2);
let addr1 = Address::from(&pubkey1); let addr1 = AccountId::from(&pubkey1);
let addr2 = Address::from(&pubkey2); let addr2 = AccountId::from(&pubkey2);
let nonces = vec![1, 2]; let nonces = vec![1, 2];
let instruction = vec![1, 2, 3, 4]; let instruction = vec![1, 2, 3, 4];
let message = Message::try_new([0; 8], vec![addr1, addr2], nonces, instruction).unwrap(); let message = Message::try_new([0; 8], vec![addr1, addr2], nonces, instruction).unwrap();

View File

@ -4,7 +4,6 @@ mod public_key;
pub use private_key::PrivateKey; pub use private_key::PrivateKey;
pub use public_key::PublicKey; pub use public_key::PublicKey;
use rand::{RngCore, rngs::OsRng}; use rand::{RngCore, rngs::OsRng};
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]

View File

@ -1,10 +1,9 @@
use nssa_core::address::Address; use nssa_core::account::AccountId;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use crate::{PrivateKey, error::NssaError}; use crate::{PrivateKey, error::NssaError};
use sha2::{Digest, Sha256};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct PublicKey([u8; 32]); pub struct PublicKey([u8; 32]);
@ -32,7 +31,7 @@ impl PublicKey {
} }
} }
impl From<&PublicKey> for Address { impl From<&PublicKey> for AccountId {
fn from(key: &PublicKey) -> Self { fn from(key: &PublicKey) -> Self {
const PUBLIC_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/NSSA/v0.2/AccountId/Public/\x00\x00\x00\x00"; const PUBLIC_ACCOUNT_ID_PREFIX: &[u8; 32] = b"/NSSA/v0.2/AccountId/Public/\x00\x00\x00\x00";

View File

@ -1,14 +1,17 @@
use std::collections::{HashMap, HashSet};
use nssa_core::{
Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, MembershipProof, Nullifier,
account::{Account, AccountId},
program::ProgramId,
};
use crate::{ use crate::{
error::NssaError, merkle_tree::MerkleTree, error::NssaError, merkle_tree::MerkleTree,
privacy_preserving_transaction::PrivacyPreservingTransaction, program::Program, privacy_preserving_transaction::PrivacyPreservingTransaction, program::Program,
program_deployment_transaction::ProgramDeploymentTransaction, program_deployment_transaction::ProgramDeploymentTransaction,
public_transaction::PublicTransaction, public_transaction::PublicTransaction,
}; };
use nssa_core::{
Commitment, CommitmentSetDigest, DUMMY_COMMITMENT, MembershipProof, Nullifier,
account::Account, address::Address, program::ProgramId,
};
use std::collections::{HashMap, HashSet};
pub(crate) struct CommitmentSet { pub(crate) struct CommitmentSet {
merkle_tree: MerkleTree, merkle_tree: MerkleTree,
@ -58,27 +61,27 @@ impl CommitmentSet {
type NullifierSet = HashSet<Nullifier>; type NullifierSet = HashSet<Nullifier>;
pub struct V02State { pub struct V02State {
public_state: HashMap<Address, Account>, public_state: HashMap<AccountId, Account>,
private_state: (CommitmentSet, NullifierSet), private_state: (CommitmentSet, NullifierSet),
programs: HashMap<ProgramId, Program>, programs: HashMap<ProgramId, Program>,
} }
impl V02State { impl V02State {
pub fn new_with_genesis_accounts( pub fn new_with_genesis_accounts(
initial_data: &[(Address, u128)], initial_data: &[(AccountId, u128)],
initial_commitments: &[nssa_core::Commitment], initial_commitments: &[nssa_core::Commitment],
) -> Self { ) -> Self {
let authenticated_transfer_program = Program::authenticated_transfer_program(); let authenticated_transfer_program = Program::authenticated_transfer_program();
let public_state = initial_data let public_state = initial_data
.iter() .iter()
.copied() .copied()
.map(|(address, balance)| { .map(|(account_id, balance)| {
let account = Account { let account = Account {
balance, balance,
program_owner: authenticated_transfer_program.id(), program_owner: authenticated_transfer_program.id(),
..Account::default() ..Account::default()
}; };
(address, account) (account_id, account)
}) })
.collect(); .collect();
@ -108,14 +111,14 @@ impl V02State {
) -> Result<(), NssaError> { ) -> Result<(), NssaError> {
let state_diff = tx.validate_and_produce_public_state_diff(self)?; let state_diff = tx.validate_and_produce_public_state_diff(self)?;
for (address, post) in state_diff.into_iter() { for (account_id, post) in state_diff.into_iter() {
let current_account = self.get_account_by_address_mut(address); let current_account = self.get_account_by_id_mut(account_id);
*current_account = post; *current_account = post;
} }
for address in tx.signer_addresses() { for account_id in tx.signer_account_ids() {
let current_account = self.get_account_by_address_mut(address); let current_account = self.get_account_by_id_mut(account_id);
current_account.nonce += 1; current_account.nonce += 1;
} }
@ -144,8 +147,8 @@ impl V02State {
self.private_state.1.extend(new_nullifiers); self.private_state.1.extend(new_nullifiers);
// 4. Update public accounts // 4. Update public accounts
for (address, post) in public_state_diff.into_iter() { for (account_id, post) in public_state_diff.into_iter() {
let current_account = self.get_account_by_address_mut(address); let current_account = self.get_account_by_id_mut(account_id);
*current_account = post; *current_account = post;
} }
@ -161,13 +164,13 @@ impl V02State {
Ok(()) Ok(())
} }
fn get_account_by_address_mut(&mut self, address: Address) -> &mut Account { fn get_account_by_id_mut(&mut self, account_id: AccountId) -> &mut Account {
self.public_state.entry(address).or_default() 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 self.public_state
.get(address) .get(account_id)
.cloned() .cloned()
.unwrap_or(Account::default()) .unwrap_or(Account::default())
} }
@ -220,11 +223,11 @@ impl V02State {
// TODO: Testnet only. Refactor to prevent compilation on mainnet. // TODO: Testnet only. Refactor to prevent compilation on mainnet.
impl V02State { 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.insert_program(Program::pinata());
self.public_state.insert( self.public_state.insert(
address, account_id,
Account { Account {
program_owner: Program::pinata().id(), program_owner: Program::pinata().id(),
balance: 1500, balance: 1500,
@ -241,8 +244,15 @@ pub mod tests {
use std::collections::HashMap; 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::{ use crate::{
Address, PublicKey, PublicTransaction, V02State, PublicKey, PublicTransaction, V02State,
error::NssaError, error::NssaError,
execute_and_prove, execute_and_prove,
privacy_preserving_transaction::{ privacy_preserving_transaction::{
@ -253,25 +263,18 @@ pub mod tests {
signature::PrivateKey, signature::PrivateKey,
}; };
use nssa_core::{
Commitment, Nullifier, NullifierPublicKey, NullifierSecretKey, SharedSecretKey,
account::{Account, AccountId, AccountWithMetadata, Nonce},
encryption::{EphemeralPublicKey, IncomingViewingPublicKey, Scalar},
program::ProgramId,
};
fn transfer_transaction( fn transfer_transaction(
from: Address, from: AccountId,
from_key: PrivateKey, from_key: PrivateKey,
nonce: u128, nonce: u128,
to: Address, to: AccountId,
balance: u128, balance: u128,
) -> PublicTransaction { ) -> PublicTransaction {
let addresses = vec![from, to]; let account_ids = vec![from, to];
let nonces = vec![nonce]; let nonces = vec![nonce];
let program_id = Program::authenticated_transfer_program().id(); let program_id = Program::authenticated_transfer_program().id();
let message = 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]); let witness_set = public_transaction::WitnessSet::for_message(&message, &[&from_key]);
PublicTransaction::new(message, witness_set) PublicTransaction::new(message, witness_set)
} }
@ -280,8 +283,8 @@ pub mod tests {
fn test_new_with_genesis() { fn test_new_with_genesis() {
let key1 = PrivateKey::try_new([1; 32]).unwrap(); let key1 = PrivateKey::try_new([1; 32]).unwrap();
let key2 = PrivateKey::try_new([2; 32]).unwrap(); let key2 = PrivateKey::try_new([2; 32]).unwrap();
let addr1 = Address::from(&PublicKey::new_from_private_key(&key1)); let addr1 = AccountId::from(&PublicKey::new_from_private_key(&key1));
let addr2 = Address::from(&PublicKey::new_from_private_key(&key2)); let addr2 = AccountId::from(&PublicKey::new_from_private_key(&key2));
let initial_data = [(addr1, 100u128), (addr2, 151u128)]; let initial_data = [(addr1, 100u128), (addr2, 151u128)];
let authenticated_transfers_program = Program::authenticated_transfer_program(); let authenticated_transfers_program = Program::authenticated_transfer_program();
let expected_public_state = { let expected_public_state = {
@ -333,25 +336,25 @@ pub mod tests {
} }
#[test] #[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 key = PrivateKey::try_new([1; 32]).unwrap();
let addr = Address::from(&PublicKey::new_from_private_key(&key)); let account_id = AccountId::from(&PublicKey::new_from_private_key(&key));
let initial_data = [(addr, 100u128)]; let initial_data = [(account_id, 100u128)];
let state = V02State::new_with_genesis_accounts(&initial_data, &[]); 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); assert_eq!(&account, expected_account);
} }
#[test] #[test]
fn test_get_account_by_address_default_account() { fn test_get_account_by_account_id_default_account() {
let addr2 = Address::new([0; 32]); let addr2 = AccountId::new([0; 32]);
let state = V02State::new_with_genesis_accounts(&[], &[]); let state = V02State::new_with_genesis_accounts(&[], &[]);
let expected_account = Account::default(); 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); assert_eq!(account, expected_account);
} }
@ -368,96 +371,96 @@ pub mod tests {
#[test] #[test]
fn transition_from_authenticated_transfer_program_invocation_default_account_destination() { fn transition_from_authenticated_transfer_program_invocation_default_account_destination() {
let key = PrivateKey::try_new([1; 32]).unwrap(); 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_data = [(address, 100)]; let initial_data = [(account_id, 100)];
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]); let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]);
let from = address; let from = account_id;
let to = Address::new([2; 32]); let to = AccountId::new([2; 32]);
assert_eq!(state.get_account_by_address(&to), Account::default()); assert_eq!(state.get_account_by_id(&to), Account::default());
let balance_to_move = 5; let balance_to_move = 5;
let tx = transfer_transaction(from, key, 0, to, balance_to_move); let tx = transfer_transaction(from, key, 0, to, balance_to_move);
state.transition_from_public_transaction(&tx).unwrap(); state.transition_from_public_transaction(&tx).unwrap();
assert_eq!(state.get_account_by_address(&from).balance, 95); assert_eq!(state.get_account_by_id(&from).balance, 95);
assert_eq!(state.get_account_by_address(&to).balance, 5); assert_eq!(state.get_account_by_id(&to).balance, 5);
assert_eq!(state.get_account_by_address(&from).nonce, 1); assert_eq!(state.get_account_by_id(&from).nonce, 1);
assert_eq!(state.get_account_by_address(&to).nonce, 0); assert_eq!(state.get_account_by_id(&to).nonce, 0);
} }
#[test] #[test]
fn transition_from_authenticated_transfer_program_invocation_insuficient_balance() { fn transition_from_authenticated_transfer_program_invocation_insuficient_balance() {
let key = PrivateKey::try_new([1; 32]).unwrap(); 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_data = [(address, 100)]; let initial_data = [(account_id, 100)];
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]); let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]);
let from = address; let from = account_id;
let from_key = key; let from_key = key;
let to = Address::new([2; 32]); let to = AccountId::new([2; 32]);
let balance_to_move = 101; 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 tx = transfer_transaction(from, from_key, 0, to, balance_to_move);
let result = state.transition_from_public_transaction(&tx); let result = state.transition_from_public_transaction(&tx);
assert!(matches!(result, Err(NssaError::ProgramExecutionFailed(_)))); assert!(matches!(result, Err(NssaError::ProgramExecutionFailed(_))));
assert_eq!(state.get_account_by_address(&from).balance, 100); assert_eq!(state.get_account_by_id(&from).balance, 100);
assert_eq!(state.get_account_by_address(&to).balance, 0); assert_eq!(state.get_account_by_id(&to).balance, 0);
assert_eq!(state.get_account_by_address(&from).nonce, 0); assert_eq!(state.get_account_by_id(&from).nonce, 0);
assert_eq!(state.get_account_by_address(&to).nonce, 0); assert_eq!(state.get_account_by_id(&to).nonce, 0);
} }
#[test] #[test]
fn transition_from_authenticated_transfer_program_invocation_non_default_account_destination() { fn transition_from_authenticated_transfer_program_invocation_non_default_account_destination() {
let key1 = PrivateKey::try_new([1; 32]).unwrap(); let key1 = PrivateKey::try_new([1; 32]).unwrap();
let key2 = PrivateKey::try_new([2; 32]).unwrap(); let key2 = PrivateKey::try_new([2; 32]).unwrap();
let address1 = Address::from(&PublicKey::new_from_private_key(&key1)); let account_id1 = AccountId::from(&PublicKey::new_from_private_key(&key1));
let address2 = Address::from(&PublicKey::new_from_private_key(&key2)); let account_id2 = AccountId::from(&PublicKey::new_from_private_key(&key2));
let initial_data = [(address1, 100), (address2, 200)]; let initial_data = [(account_id1, 100), (account_id2, 200)];
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]); let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]);
let from = address2; let from = account_id2;
let from_key = key2; let from_key = key2;
let to = address1; let to = account_id1;
assert_ne!(state.get_account_by_address(&to), Account::default()); assert_ne!(state.get_account_by_id(&to), Account::default());
let balance_to_move = 8; let balance_to_move = 8;
let tx = transfer_transaction(from, from_key, 0, to, balance_to_move); let tx = transfer_transaction(from, from_key, 0, to, balance_to_move);
state.transition_from_public_transaction(&tx).unwrap(); state.transition_from_public_transaction(&tx).unwrap();
assert_eq!(state.get_account_by_address(&from).balance, 192); assert_eq!(state.get_account_by_id(&from).balance, 192);
assert_eq!(state.get_account_by_address(&to).balance, 108); assert_eq!(state.get_account_by_id(&to).balance, 108);
assert_eq!(state.get_account_by_address(&from).nonce, 1); assert_eq!(state.get_account_by_id(&from).nonce, 1);
assert_eq!(state.get_account_by_address(&to).nonce, 0); assert_eq!(state.get_account_by_id(&to).nonce, 0);
} }
#[test] #[test]
fn transition_from_sequence_of_authenticated_transfer_program_invocations() { fn transition_from_sequence_of_authenticated_transfer_program_invocations() {
let key1 = PrivateKey::try_new([8; 32]).unwrap(); 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 key2 = PrivateKey::try_new([2; 32]).unwrap();
let address2 = Address::from(&PublicKey::new_from_private_key(&key2)); let account_id2 = AccountId::from(&PublicKey::new_from_private_key(&key2));
let initial_data = [(address1, 100)]; let initial_data = [(account_id1, 100)];
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]); 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 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(); state.transition_from_public_transaction(&tx).unwrap();
let balance_to_move = 3; 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(); state.transition_from_public_transaction(&tx).unwrap();
assert_eq!(state.get_account_by_address(&address1).balance, 95); assert_eq!(state.get_account_by_id(&account_id1).balance, 95);
assert_eq!(state.get_account_by_address(&address2).balance, 2); assert_eq!(state.get_account_by_id(&account_id2).balance, 2);
assert_eq!(state.get_account_by_address(&address3).balance, 3); assert_eq!(state.get_account_by_id(&account_id3).balance, 3);
assert_eq!(state.get_account_by_address(&address1).nonce, 1); assert_eq!(state.get_account_by_id(&account_id1).nonce, 1);
assert_eq!(state.get_account_by_address(&address2).nonce, 1); assert_eq!(state.get_account_by_id(&account_id2).nonce, 1);
assert_eq!(state.get_account_by_address(&address3).nonce, 0); assert_eq!(state.get_account_by_id(&account_id3).nonce, 0);
} }
impl V02State { impl V02State {
pub fn force_insert_account(&mut self, address: Address, account: Account) { pub fn force_insert_account(&mut self, account_id: AccountId, account: Account) {
self.public_state.insert(address, account); self.public_state.insert(account_id, account);
} }
/// Include test programs in the builtin programs map /// Include test programs in the builtin programs map
@ -488,15 +491,15 @@ pub mod tests {
..Account::default() ..Account::default()
}; };
self.force_insert_account( self.force_insert_account(
Address::new([255; 32]), AccountId::new([255; 32]),
account_with_default_values_except_balance, account_with_default_values_except_balance,
); );
self.force_insert_account( self.force_insert_account(
Address::new([254; 32]), AccountId::new([254; 32]),
account_with_default_values_except_nonce, account_with_default_values_except_nonce,
); );
self.force_insert_account( self.force_insert_account(
Address::new([253; 32]), AccountId::new([253; 32]),
account_with_default_values_except_data, account_with_default_values_except_data,
); );
self self
@ -508,7 +511,7 @@ pub mod tests {
balance: 100, balance: 100,
..Default::default() ..Default::default()
}; };
self.force_insert_account(Address::new([252; 32]), account); self.force_insert_account(AccountId::new([252; 32]), account);
self self
} }
@ -521,13 +524,13 @@ pub mod tests {
#[test] #[test]
fn test_program_should_fail_if_modifies_nonces() { 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 = let mut state =
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); 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 program_id = Program::nonce_changer_program().id();
let message = 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 witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
let tx = PublicTransaction::new(message, witness_set); let tx = PublicTransaction::new(message, witness_set);
@ -538,13 +541,13 @@ pub mod tests {
#[test] #[test]
fn test_program_should_fail_if_output_accounts_exceed_inputs() { 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 = let mut state =
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); 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 program_id = Program::extra_output_program().id();
let message = 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 witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
let tx = PublicTransaction::new(message, witness_set); let tx = PublicTransaction::new(message, witness_set);
@ -555,13 +558,13 @@ pub mod tests {
#[test] #[test]
fn test_program_should_fail_with_missing_output_accounts() { 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 = let mut state =
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); 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 program_id = Program::missing_output_program().id();
let message = 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 witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
let tx = PublicTransaction::new(message, witness_set); let tx = PublicTransaction::new(message, witness_set);
@ -572,19 +575,20 @@ pub mod tests {
#[test] #[test]
fn test_program_should_fail_if_modifies_program_owner_with_only_non_default_program_owner() { 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 = let mut state =
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
let address = Address::new([1; 32]); let account_id = AccountId::new([1; 32]);
let account = state.get_account_by_address(&address); 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 the target account only differs from the default account in the program owner
// field
assert_ne!(account.program_owner, Account::default().program_owner); assert_ne!(account.program_owner, Account::default().program_owner);
assert_eq!(account.balance, Account::default().balance); assert_eq!(account.balance, Account::default().balance);
assert_eq!(account.nonce, Account::default().nonce); assert_eq!(account.nonce, Account::default().nonce);
assert_eq!(account.data, Account::default().data); assert_eq!(account.data, Account::default().data);
let program_id = Program::program_owner_changer().id(); let program_id = Program::program_owner_changer().id();
let message = 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 witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
let tx = PublicTransaction::new(message, witness_set); let tx = PublicTransaction::new(message, witness_set);
@ -599,8 +603,8 @@ pub mod tests {
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]) let mut state = V02State::new_with_genesis_accounts(&initial_data, &[])
.with_test_programs() .with_test_programs()
.with_non_default_accounts_but_default_program_owners(); .with_non_default_accounts_but_default_program_owners();
let address = Address::new([255; 32]); let account_id = AccountId::new([255; 32]);
let account = state.get_account_by_address(&address); let account = state.get_account_by_id(&account_id);
// Assert the target account only differs from the default account in balance field // Assert the target account only differs from the default account in balance field
assert_eq!(account.program_owner, Account::default().program_owner); assert_eq!(account.program_owner, Account::default().program_owner);
assert_ne!(account.balance, Account::default().balance); assert_ne!(account.balance, Account::default().balance);
@ -608,7 +612,7 @@ pub mod tests {
assert_eq!(account.data, Account::default().data); assert_eq!(account.data, Account::default().data);
let program_id = Program::program_owner_changer().id(); let program_id = Program::program_owner_changer().id();
let message = 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 witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
let tx = PublicTransaction::new(message, witness_set); let tx = PublicTransaction::new(message, witness_set);
@ -623,8 +627,8 @@ pub mod tests {
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]) let mut state = V02State::new_with_genesis_accounts(&initial_data, &[])
.with_test_programs() .with_test_programs()
.with_non_default_accounts_but_default_program_owners(); .with_non_default_accounts_but_default_program_owners();
let address = Address::new([254; 32]); let account_id = AccountId::new([254; 32]);
let account = state.get_account_by_address(&address); let account = state.get_account_by_id(&account_id);
// Assert the target account only differs from the default account in nonce field // 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.program_owner, Account::default().program_owner);
assert_eq!(account.balance, Account::default().balance); assert_eq!(account.balance, Account::default().balance);
@ -632,7 +636,7 @@ pub mod tests {
assert_eq!(account.data, Account::default().data); assert_eq!(account.data, Account::default().data);
let program_id = Program::program_owner_changer().id(); let program_id = Program::program_owner_changer().id();
let message = 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 witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
let tx = PublicTransaction::new(message, witness_set); let tx = PublicTransaction::new(message, witness_set);
@ -647,8 +651,8 @@ pub mod tests {
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]) let mut state = V02State::new_with_genesis_accounts(&initial_data, &[])
.with_test_programs() .with_test_programs()
.with_non_default_accounts_but_default_program_owners(); .with_non_default_accounts_but_default_program_owners();
let address = Address::new([253; 32]); let account_id = AccountId::new([253; 32]);
let account = state.get_account_by_address(&address); let account = state.get_account_by_id(&account_id);
// Assert the target account only differs from the default account in data field // 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.program_owner, Account::default().program_owner);
assert_eq!(account.balance, Account::default().balance); assert_eq!(account.balance, Account::default().balance);
@ -656,7 +660,7 @@ pub mod tests {
assert_ne!(account.data, Account::default().data); assert_ne!(account.data, Account::default().data);
let program_id = Program::program_owner_changer().id(); let program_id = Program::program_owner_changer().id();
let message = 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 witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
let tx = PublicTransaction::new(message, witness_set); let tx = PublicTransaction::new(message, witness_set);
@ -667,20 +671,20 @@ pub mod tests {
#[test] #[test]
fn test_program_should_fail_if_transfers_balance_from_non_owned_account() { 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 = let mut state =
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
let sender_address = Address::new([1; 32]); let sender_account_id = AccountId::new([1; 32]);
let receiver_address = Address::new([2; 32]); let receiver_account_id = AccountId::new([2; 32]);
let balance_to_move: u128 = 1; let balance_to_move: u128 = 1;
let program_id = Program::simple_balance_transfer().id(); let program_id = Program::simple_balance_transfer().id();
assert_ne!( assert_ne!(
state.get_account_by_address(&sender_address).program_owner, state.get_account_by_id(&sender_account_id).program_owner,
program_id program_id
); );
let message = public_transaction::Message::try_new( let message = public_transaction::Message::try_new(
program_id, program_id,
vec![sender_address, receiver_address], vec![sender_account_id, receiver_account_id],
vec![], vec![],
balance_to_move, balance_to_move,
) )
@ -699,16 +703,16 @@ pub mod tests {
let mut state = V02State::new_with_genesis_accounts(&initial_data, &[]) let mut state = V02State::new_with_genesis_accounts(&initial_data, &[])
.with_test_programs() .with_test_programs()
.with_non_default_accounts_but_default_program_owners(); .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(); 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!( assert_ne!(
state.get_account_by_address(&address).program_owner, state.get_account_by_id(&account_id).program_owner,
program_id program_id
); );
let message = 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 witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
let tx = PublicTransaction::new(message, witness_set); let tx = PublicTransaction::new(message, witness_set);
@ -722,11 +726,11 @@ pub mod tests {
let initial_data = []; let initial_data = [];
let mut state = let mut state =
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); 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 program_id = Program::minter().id();
let message = 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 witness_set = public_transaction::WitnessSet::for_message(&message, &[]);
let tx = PublicTransaction::new(message, witness_set); let tx = PublicTransaction::new(message, witness_set);
@ -742,17 +746,17 @@ pub mod tests {
.with_test_programs() .with_test_programs()
.with_account_owned_by_burner_program(); .with_account_owned_by_burner_program();
let program_id = Program::burner().id(); let program_id = Program::burner().id();
let address = Address::new([252; 32]); let account_id = AccountId::new([252; 32]);
assert_eq!( assert_eq!(
state.get_account_by_address(&address).program_owner, state.get_account_by_id(&account_id).program_owner,
program_id program_id
); );
let balance_to_burn: u128 = 1; 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( let message = public_transaction::Message::try_new(
program_id, program_id,
vec![address], vec![account_id],
vec![], vec![],
balance_to_burn, balance_to_burn,
) )
@ -769,8 +773,8 @@ pub mod tests {
} }
impl TestPublicKeys { impl TestPublicKeys {
pub fn address(&self) -> Address { pub fn account_id(&self) -> AccountId {
Address::from(&PublicKey::new_from_private_key(&self.signing_key)) AccountId::from(&PublicKey::new_from_private_key(&self.signing_key))
} }
} }
@ -816,9 +820,9 @@ pub mod tests {
state: &V02State, state: &V02State,
) -> PrivacyPreservingTransaction { ) -> PrivacyPreservingTransaction {
let sender = AccountWithMetadata::new( let sender = AccountWithMetadata::new(
state.get_account_by_address(&sender_keys.address()), state.get_account_by_id(&sender_keys.account_id()),
true, true,
sender_keys.address(), sender_keys.account_id(),
); );
let sender_nonce = sender.account.nonce; let sender_nonce = sender.account.nonce;
@ -841,7 +845,7 @@ pub mod tests {
.unwrap(); .unwrap();
let message = Message::try_from_circuit_output( let message = Message::try_from_circuit_output(
vec![sender_keys.address()], vec![sender_keys.account_id()],
vec![sender_nonce], vec![sender_nonce],
vec![(recipient_keys.npk(), recipient_keys.ivk(), epk)], vec![(recipient_keys.npk(), recipient_keys.ivk(), epk)],
output, output,
@ -911,7 +915,7 @@ pub mod tests {
fn deshielded_balance_transfer_for_tests( fn deshielded_balance_transfer_for_tests(
sender_keys: &TestPrivateKeys, sender_keys: &TestPrivateKeys,
sender_private_account: &Account, sender_private_account: &Account,
recipient_address: &Address, recipient_account_id: &AccountId,
balance_to_move: u128, balance_to_move: u128,
new_nonce: Nonce, new_nonce: Nonce,
state: &V02State, state: &V02State,
@ -921,9 +925,9 @@ pub mod tests {
let sender_pre = let sender_pre =
AccountWithMetadata::new(sender_private_account.clone(), true, &sender_keys.npk()); AccountWithMetadata::new(sender_private_account.clone(), true, &sender_keys.npk());
let recipient_pre = AccountWithMetadata::new( let recipient_pre = AccountWithMetadata::new(
state.get_account_by_address(recipient_address), state.get_account_by_id(recipient_account_id),
false, false,
*recipient_address, *recipient_account_id,
); );
let esk = [3; 32]; let esk = [3; 32];
@ -945,7 +949,7 @@ pub mod tests {
.unwrap(); .unwrap();
let message = Message::try_from_circuit_output( let message = Message::try_from_circuit_output(
vec![*recipient_address], vec![*recipient_account_id],
vec![], vec![],
vec![(sender_keys.npk(), sender_keys.ivk(), epk)], vec![(sender_keys.npk(), sender_keys.ivk(), epk)],
output, output,
@ -962,7 +966,8 @@ pub mod tests {
let sender_keys = test_public_account_keys_1(); let sender_keys = test_public_account_keys_1();
let recipient_keys = test_private_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; let balance_to_move = 37;
@ -974,7 +979,7 @@ pub mod tests {
); );
let expected_sender_post = { 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.balance -= balance_to_move;
this.nonce += 1; this.nonce += 1;
this this
@ -987,12 +992,12 @@ pub mod tests {
.transition_from_privacy_preserving_transaction(&tx) .transition_from_privacy_preserving_transaction(&tx)
.unwrap(); .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_eq!(sender_post, expected_sender_post);
assert!(state.private_state.0.contains(&expected_new_commitment)); assert!(state.private_state.0.contains(&expected_new_commitment));
assert_eq!( 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 200 - balance_to_move
); );
} }
@ -1075,7 +1080,7 @@ pub mod tests {
let recipient_keys = test_public_account_keys_1(); let recipient_keys = test_public_account_keys_1();
let recipient_initial_balance = 400; let recipient_initial_balance = 400;
let mut state = V02State::new_with_genesis_accounts( 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); .with_private_account(&sender_keys, &sender_private_account);
@ -1083,7 +1088,7 @@ pub mod tests {
let balance_to_move = 37; let balance_to_move = 37;
let expected_recipient_post = { 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.balance += balance_to_move;
this this
}; };
@ -1091,7 +1096,7 @@ pub mod tests {
let tx = deshielded_balance_transfer_for_tests( let tx = deshielded_balance_transfer_for_tests(
&sender_keys, &sender_keys,
&sender_private_account, &sender_private_account,
&recipient_keys.address(), &recipient_keys.account_id(),
balance_to_move, balance_to_move,
0xcafecafe, 0xcafecafe,
&state, &state,
@ -1119,14 +1124,14 @@ pub mod tests {
.transition_from_privacy_preserving_transaction(&tx) .transition_from_privacy_preserving_transaction(&tx)
.unwrap(); .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_eq!(recipient_post, expected_recipient_post);
assert!(state.private_state.0.contains(&sender_pre_commitment)); assert!(state.private_state.0.contains(&sender_pre_commitment));
assert!(state.private_state.0.contains(&expected_new_commitment)); assert!(state.private_state.0.contains(&expected_new_commitment));
assert!(state.private_state.1.contains(&expected_new_nullifier)); assert!(state.private_state.1.contains(&expected_new_nullifier));
assert_eq!( assert_eq!(
state state
.get_account_by_address(&recipient_keys.address()) .get_account_by_id(&recipient_keys.account_id())
.balance, .balance,
recipient_initial_balance + balance_to_move recipient_initial_balance + balance_to_move
); );
@ -2046,18 +2051,18 @@ pub mod tests {
fn test_claiming_mechanism() { fn test_claiming_mechanism() {
let program = Program::authenticated_transfer_program(); let program = Program::authenticated_transfer_program();
let key = PrivateKey::try_new([1; 32]).unwrap(); 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_balance = 100;
let initial_data = [(address, initial_balance)]; let initial_data = [(account_id, initial_balance)];
let mut state = let mut state =
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
let from = address; let from = account_id;
let from_key = key; let from_key = key;
let to = Address::new([2; 32]); let to = AccountId::new([2; 32]);
let amount: u128 = 37; let amount: u128 = 37;
// Check the recipient is an uninitialized account // 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 { let expected_recipient_post = Account {
program_owner: program.id(), program_owner: program.id(),
@ -2073,7 +2078,7 @@ pub mod tests {
state.transition_from_public_transaction(&tx).unwrap(); 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); assert_eq!(recipient_post, expected_recipient_post);
} }
@ -2082,14 +2087,14 @@ pub mod tests {
fn test_chained_call() { fn test_chained_call() {
let program = Program::chain_caller(); let program = Program::chain_caller();
let key = PrivateKey::try_new([1; 32]).unwrap(); 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_balance = 100;
let initial_data = [(address, initial_balance)]; let initial_data = [(account_id, initial_balance)];
let mut state = let mut state =
V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs(); V02State::new_with_genesis_accounts(&initial_data, &[]).with_test_programs();
let from = address; let from = account_id;
let from_key = key; let from_key = key;
let to = Address::new([2; 32]); let to = AccountId::new([2; 32]);
let amount: u128 = 37; let amount: u128 = 37;
let instruction: (u128, ProgramId) = let instruction: (u128, ProgramId) =
(amount, Program::authenticated_transfer_program().id()); (amount, Program::authenticated_transfer_program().id());
@ -2102,7 +2107,7 @@ pub mod tests {
let message = public_transaction::Message::try_new( let message = public_transaction::Message::try_new(
program.id(), 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 call
vec![0], vec![0],
instruction, instruction,
) )
@ -2112,8 +2117,8 @@ pub mod tests {
state.transition_from_public_transaction(&tx).unwrap(); state.transition_from_public_transaction(&tx).unwrap();
let from_post = state.get_account_by_address(&from); let from_post = state.get_account_by_id(&from);
let to_post = state.get_account_by_address(&to); let to_post = state.get_account_by_id(&to);
assert_eq!(from_post.balance, initial_balance - amount); assert_eq!(from_post.balance, initial_balance - amount);
assert_eq!(to_post, expected_to_post); assert_eq!(to_post, expected_to_post);
} }

View File

@ -1,2 +1,3 @@
[toolchain] [toolchain]
channel = "nightly" channel = "1.91.1"
profile = "default"

View File

@ -1 +1,12 @@
edition = "2024" 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

View File

@ -28,3 +28,7 @@ path = "../nssa"
[features] [features]
default = [] default = []
testnet = [] testnet = []
[dev-dependencies]
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }
futures.workspace = true

View File

@ -4,16 +4,16 @@ use anyhow::Result;
use common::{HashType, block::Block, transaction::EncodedTransaction}; use common::{HashType, block::Block, transaction::EncodedTransaction};
use storage::RocksDBIO; use storage::RocksDBIO;
pub struct SequecerBlockStore { pub struct SequencerBlockStore {
dbio: RocksDBIO, dbio: RocksDBIO,
// TODO: Consider adding the hashmap to the database for faster recovery. // TODO: Consider adding the hashmap to the database for faster recovery.
pub tx_hash_to_block_map: HashMap<HashType, u64>, tx_hash_to_block_map: HashMap<HashType, u64>,
pub genesis_id: u64, genesis_id: u64,
pub signing_key: nssa::PrivateKey, signing_key: nssa::PrivateKey,
} }
impl SequecerBlockStore { impl SequencerBlockStore {
///Starting database at the start of new chain. /// Starting database at the start of new chain.
/// Creates files if necessary. /// Creates files if necessary.
/// ///
/// ATTENTION: Will overwrite genesis block. /// 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<Self> { pub fn open_db_restart(location: &Path, signing_key: nssa::PrivateKey) -> Result<Self> {
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<Block> { pub fn get_block_at_id(&self, id: u64) -> Result<Block> {
@ -69,6 +69,18 @@ impl SequecerBlockStore {
} }
None 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<HashType, u64> { pub(crate) fn block_to_transactions_map(block: &Block) -> HashMap<HashType, u64> {
@ -82,11 +94,11 @@ pub(crate) fn block_to_transactions_map(block: &Block) -> HashMap<HashType, u64>
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use common::{block::HashableBlockData, test_utils::sequencer_sign_key_for_testing}; use common::{block::HashableBlockData, test_utils::sequencer_sign_key_for_testing};
use tempfile::tempdir; use tempfile::tempdir;
use super::*;
#[test] #[test]
fn test_get_transaction_by_hash() { fn test_get_transaction_by_hash() {
let temp_dir = tempdir().unwrap(); let temp_dir = tempdir().unwrap();
@ -104,7 +116,7 @@ mod tests {
let genesis_block = genesis_block_hashable_data.into_block(&signing_key); let genesis_block = genesis_block_hashable_data.into_block(&signing_key);
// Start an empty node store // Start an empty node store
let mut 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(); .unwrap();
let tx = common::test_utils::produce_dummy_empty_transaction(); let tx = common::test_utils::produce_dummy_empty_transaction();

View File

@ -1,43 +1,45 @@
use serde::{Deserialize, Serialize};
use std::path::PathBuf; use std::path::PathBuf;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
///Helperstruct for account serialization /// Helperstruct for account serialization
pub struct AccountInitialData { pub struct AccountInitialData {
///Hex encoded `AccountAddress` /// Hex encoded account id
pub addr: String, pub account_id: String,
pub balance: u128, pub balance: u128,
} }
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
///Helperstruct to initialize commitments /// Helperstruct to initialize commitments
pub struct CommitmentsInitialData { pub struct CommitmentsInitialData {
pub npk: nssa_core::NullifierPublicKey, pub npk: nssa_core::NullifierPublicKey,
pub account: nssa_core::account::Account, pub account: nssa_core::account::Account,
} }
// TODO: Provide default values
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub struct SequencerConfig { pub struct SequencerConfig {
///Home dir of sequencer storage /// Home dir of sequencer storage
pub home: PathBuf, pub home: PathBuf,
///Override rust log (env var logging level) /// Override rust log (env var logging level)
pub override_rust_log: Option<String>, pub override_rust_log: Option<String>,
///Genesis id /// Genesis id
pub genesis_id: u64, 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, pub is_genesis_random: bool,
///Maximum number of transactions in block /// Maximum number of transactions in block
pub max_num_tx_in_block: usize, pub max_num_tx_in_block: usize,
///Mempool maximum size /// Mempool maximum size
pub mempool_max_size: usize, pub mempool_max_size: usize,
///Interval in which blocks produced /// Interval in which blocks produced
pub block_create_timeout_millis: u64, pub block_create_timeout_millis: u64,
///Port to listen /// Port to listen
pub port: u16, pub port: u16,
///List of initial accounts data /// List of initial accounts data
pub initial_accounts: Vec<AccountInitialData>, pub initial_accounts: Vec<AccountInitialData>,
///List of initial commitments /// List of initial commitments
pub initial_commitments: Vec<CommitmentsInitialData>, pub initial_commitments: Vec<CommitmentsInitialData>,
///Sequencer own signing key /// Sequencer own signing key
pub signing_key: [u8; 32], pub signing_key: [u8; 32],
} }

View File

@ -10,25 +10,24 @@ use common::{
}; };
use config::SequencerConfig; use config::SequencerConfig;
use log::warn; use log::warn;
use mempool::MemPool; use mempool::{MemPool, MemPoolHandle};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::block_store::SequecerBlockStore; use crate::block_store::SequencerBlockStore;
pub mod block_store; pub mod block_store;
pub mod config; pub mod config;
pub struct SequencerCore { pub struct SequencerCore {
pub state: nssa::V02State, state: nssa::V02State,
pub block_store: SequecerBlockStore, block_store: SequencerBlockStore,
pub mempool: MemPool<EncodedTransaction>, mempool: MemPool<EncodedTransaction>,
pub sequencer_config: SequencerConfig, sequencer_config: SequencerConfig,
pub chain_height: u64, chain_height: u64,
} }
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum TransactionMalformationError { pub enum TransactionMalformationError {
MempoolFullForRound,
InvalidSignature, InvalidSignature,
FailedToDecode { tx: HashType }, FailedToDecode { tx: HashType },
} }
@ -42,7 +41,8 @@ impl Display for TransactionMalformationError {
impl std::error::Error for TransactionMalformationError {} impl std::error::Error for TransactionMalformationError {}
impl SequencerCore { 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<EncodedTransaction>) {
let hashable_data = HashableBlockData { let hashable_data = HashableBlockData {
block_id: config.genesis_id, block_id: config.genesis_id,
transactions: vec![], transactions: vec![],
@ -53,9 +53,9 @@ impl SequencerCore {
let signing_key = nssa::PrivateKey::try_new(config.signing_key).unwrap(); let signing_key = nssa::PrivateKey::try_new(config.signing_key).unwrap();
let genesis_block = hashable_data.into_block(&signing_key); let genesis_block = hashable_data.into_block(&signing_key);
//Sequencer should panic if unable to open db, // Sequencer should panic if unable to open db,
//as fixing this issue may require actions non-native to program scope // as fixing this issue may require actions non-native to program scope
let block_store = SequecerBlockStore::open_db_with_genesis( let block_store = SequencerBlockStore::open_db_with_genesis(
&config.home.join("rocksdb"), &config.home.join("rocksdb"),
Some(genesis_block), Some(genesis_block),
signing_key, signing_key,
@ -75,10 +75,10 @@ impl SequencerCore {
initial_commitments.push(comm); initial_commitments.push(comm);
} }
let init_accs: Vec<(nssa::Address, u128)> = config let init_accs: Vec<(nssa::AccountId, u128)> = config
.initial_accounts .initial_accounts
.iter() .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(); .collect();
let mut state = nssa::V02State::new_with_genesis_accounts(&init_accs, &initial_commitments); let mut state = nssa::V02State::new_with_genesis_accounts(&init_accs, &initial_commitments);
@ -86,21 +86,23 @@ impl SequencerCore {
#[cfg(feature = "testnet")] #[cfg(feature = "testnet")]
state.add_pinata_program(PINATA_BASE58.parse().unwrap()); state.add_pinata_program(PINATA_BASE58.parse().unwrap());
let (mempool, mempool_handle) = MemPool::new(config.mempool_max_size);
let mut this = Self { let mut this = Self {
state, state,
block_store, block_store,
mempool: MemPool::default(), mempool,
chain_height: config.genesis_id, chain_height: config.genesis_id,
sequencer_config: config, sequencer_config: config,
}; };
this.sync_state_with_stored_blocks(); 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 /// If there are stored blocks ahead of the current height, this method will load and process
/// in them in the order they are stored. The NSSA state will be updated accordingly. /// 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) { fn sync_state_with_stored_blocks(&mut self) {
let mut next_block_id = self.sequencer_config.genesis_id + 1; 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) { 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) self.execute_check_transaction_on_state(transaction)
.unwrap(); .unwrap();
// Update the tx hash to block id map. // Update the tx hash to block id map.
self.block_store self.block_store.insert(&encoded_transaction, next_block_id);
.tx_hash_to_block_map
.insert(encoded_transaction.hash(), next_block_id);
} }
self.chain_height = next_block_id; self.chain_height = next_block_id;
next_block_id += 1; next_block_id += 1;
} }
} }
pub fn transaction_pre_check(
&mut self,
tx: NSSATransaction,
) -> Result<NSSATransaction, TransactionMalformationError> {
// 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( fn execute_check_transaction_on_state(
&mut self, &mut self,
tx: NSSATransaction, tx: NSSATransaction,
) -> Result<NSSATransaction, nssa::error::NssaError> { ) -> Result<NSSATransaction, nssa::error::NssaError> {
match &tx { match &tx {
NSSATransaction::Public(tx) => { NSSATransaction::Public(tx) => self.state.transition_from_public_transaction(tx),
self.state NSSATransaction::PrivacyPreserving(tx) => self
.transition_from_public_transaction(tx) .state
.inspect_err(|err| warn!("Error at transition {err:#?}"))?; .transition_from_privacy_preserving_transaction(tx),
} NSSATransaction::ProgramDeployment(tx) => self
NSSATransaction::PrivacyPreserving(tx) => { .state
self.state .transition_from_program_deployment_transaction(tx),
.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:#?}"))?;
}
} }
.inspect_err(|err| warn!("Error at transition {err:#?}"))?;
Ok(tx) 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<u64> { pub fn produce_new_block_with_mempool_transactions(&mut self) -> Result<u64> {
let now = Instant::now(); let now = Instant::now();
let new_block_height = self.chain_height + 1; let new_block_height = self.chain_height + 1;
let mut num_valid_transactions_in_block = 0;
let mut valid_transactions = vec![]; 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) let nssa_transaction = NSSATransaction::try_from(&tx)
.map_err(|_| TransactionMalformationError::FailedToDecode { tx: tx.hash() })?; .map_err(|_| TransactionMalformationError::FailedToDecode { tx: tx.hash() })?;
if let Ok(valid_tx) = self.execute_check_transaction_on_state(nssa_transaction) { if let Ok(valid_tx) = self.execute_check_transaction_on_state(nssa_transaction) {
valid_transactions.push(valid_tx.into()); valid_transactions.push(valid_tx.into());
num_valid_transactions_in_block += 1; if valid_transactions.len() >= self.sequencer_config.max_num_tx_in_block {
if num_valid_transactions_in_block >= self.sequencer_config.max_num_tx_in_block {
break; break;
} }
} else {
// Probably need to handle unsuccessful transaction execution?
} }
} }
@ -232,12 +176,22 @@ impl SequencerCore {
timestamp: curr_time, 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.block_store.put_block_at_id(block)?;
self.chain_height = new_block_height; 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!( log::info!(
"Created block with {} transactions in {} seconds", "Created block with {} transactions in {} seconds",
num_txs_in_block, num_txs_in_block,
@ -246,17 +200,58 @@ impl SequencerCore {
Ok(self.chain_height) 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<NSSATransaction, TransactionMalformationError> {
// 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)] #[cfg(test)]
mod tests { mod tests {
use std::pin::pin;
use base58::{FromBase58, ToBase58}; use base58::{FromBase58, ToBase58};
use common::test_utils::sequencer_sign_key_for_testing; use common::test_utils::sequencer_sign_key_for_testing;
use nssa::PrivateKey; use nssa::PrivateKey;
use crate::config::AccountInitialData;
use super::*; use super::*;
use crate::config::AccountInitialData;
fn parse_unwrap_tx_body_into_nssa_tx(tx_body: EncodedTransaction) -> NSSATransaction { fn parse_unwrap_tx_body_into_nssa_tx(tx_body: EncodedTransaction) -> NSSATransaction {
NSSATransaction::try_from(&tx_body) NSSATransaction::try_from(&tx_body)
@ -286,23 +281,23 @@ mod tests {
} }
fn setup_sequencer_config() -> SequencerConfig { fn setup_sequencer_config() -> SequencerConfig {
let acc1_addr: Vec<u8> = vec![ let acc1_account_id: Vec<u8> = vec![
208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9, 115, 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, 84, 126, 106, 16, 111, 114, 241, 147, 194, 220, 131, 139, 68,
]; ];
let acc2_addr: Vec<u8> = vec![ let acc2_account_id: Vec<u8> = vec![
231, 174, 119, 197, 239, 26, 5, 153, 147, 68, 175, 73, 159, 199, 138, 23, 5, 57, 141, 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, 98, 237, 6, 207, 46, 20, 121, 246, 222, 248, 154, 57, 188,
]; ];
let initial_acc1 = AccountInitialData { let initial_acc1 = AccountInitialData {
addr: acc1_addr.to_base58(), account_id: acc1_account_id.to_base58(),
balance: 10000, balance: 10000,
}; };
let initial_acc2 = AccountInitialData { let initial_acc2 = AccountInitialData {
addr: acc2_addr.to_base58(), account_id: acc2_account_id.to_base58(),
balance: 20000, balance: 20000,
}; };
@ -319,33 +314,44 @@ mod tests {
nssa::PrivateKey::try_new([2; 32]).unwrap() nssa::PrivateKey::try_new([2; 32]).unwrap()
} }
fn common_setup(sequencer: &mut SequencerCore) { async fn common_setup() -> (SequencerCore, MemPoolHandle<EncodedTransaction>) {
let config = setup_sequencer_config();
common_setup_with_config(config).await
}
async fn common_setup_with_config(
config: SequencerConfig,
) -> (SequencerCore, MemPoolHandle<EncodedTransaction>) {
let (mut sequencer, mempool_handle) = SequencerCore::start_from_config(config);
let tx = common::test_utils::produce_dummy_empty_transaction(); let tx = common::test_utils::produce_dummy_empty_transaction();
sequencer.mempool.push_item(tx); mempool_handle.push(tx).await.unwrap();
sequencer sequencer
.produce_new_block_with_mempool_transactions() .produce_new_block_with_mempool_transactions()
.unwrap(); .unwrap();
(sequencer, mempool_handle)
} }
#[test] #[test]
fn test_start_from_config() { fn test_start_from_config() {
let config = setup_sequencer_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.chain_height, config.genesis_id);
assert_eq!(sequencer.sequencer_config.max_num_tx_in_block, 10); assert_eq!(sequencer.sequencer_config.max_num_tx_in_block, 10);
assert_eq!(sequencer.sequencer_config.port, 8080); assert_eq!(sequencer.sequencer_config.port, 8080);
let acc1_addr = config.initial_accounts[0] let acc1_account_id = config.initial_accounts[0]
.addr .account_id
.clone() .clone()
.from_base58() .from_base58()
.unwrap() .unwrap()
.try_into() .try_into()
.unwrap(); .unwrap();
let acc2_addr = config.initial_accounts[1] let acc2_account_id = config.initial_accounts[1]
.addr .account_id
.clone() .clone()
.from_base58() .from_base58()
.unwrap() .unwrap()
@ -354,11 +360,11 @@ mod tests {
let balance_acc_1 = sequencer let balance_acc_1 = sequencer
.state .state
.get_account_by_address(&nssa::Address::new(acc1_addr)) .get_account_by_id(&nssa::AccountId::new(acc1_account_id))
.balance; .balance;
let balance_acc_2 = sequencer let balance_acc_2 = sequencer
.state .state
.get_account_by_address(&nssa::Address::new(acc2_addr)) .get_account_by_id(&nssa::AccountId::new(acc2_account_id))
.balance; .balance;
assert_eq!(10000, balance_acc_1); assert_eq!(10000, balance_acc_1);
@ -367,40 +373,40 @@ mod tests {
#[test] #[test]
fn test_start_different_intial_accounts_balances() { fn test_start_different_intial_accounts_balances() {
let acc1_addr: Vec<u8> = vec![ let acc1_account_id: Vec<u8> = vec![
27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, 24, 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, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143,
]; ];
let acc2_addr: Vec<u8> = vec![ let acc2_account_id: Vec<u8> = vec![
77, 75, 108, 209, 54, 16, 50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217, 234, 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, 216, 10, 201, 66, 51, 116, 196, 81, 167, 37, 77, 7, 102,
]; ];
let initial_acc1 = AccountInitialData { let initial_acc1 = AccountInitialData {
addr: acc1_addr.to_base58(), account_id: acc1_account_id.to_base58(),
balance: 10000, balance: 10000,
}; };
let initial_acc2 = AccountInitialData { let initial_acc2 = AccountInitialData {
addr: acc2_addr.to_base58(), account_id: acc2_account_id.to_base58(),
balance: 20000, balance: 20000,
}; };
let initial_accounts = vec![initial_acc1, initial_acc2]; let initial_accounts = vec![initial_acc1, initial_acc2];
let config = setup_sequencer_config_variable_initial_accounts(initial_accounts); 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] let acc1_account_id = config.initial_accounts[0]
.addr .account_id
.clone() .clone()
.from_base58() .from_base58()
.unwrap() .unwrap()
.try_into() .try_into()
.unwrap(); .unwrap();
let acc2_addr = config.initial_accounts[1] let acc2_account_id = config.initial_accounts[1]
.addr .account_id
.clone() .clone()
.from_base58() .from_base58()
.unwrap() .unwrap()
@ -411,47 +417,39 @@ mod tests {
10000, 10000,
sequencer sequencer
.state .state
.get_account_by_address(&nssa::Address::new(acc1_addr)) .get_account_by_id(&nssa::AccountId::new(acc1_account_id))
.balance .balance
); );
assert_eq!( assert_eq!(
20000, 20000,
sequencer sequencer
.state .state
.get_account_by_address(&nssa::Address::new(acc2_addr)) .get_account_by_id(&nssa::AccountId::new(acc2_account_id))
.balance .balance
); );
} }
#[test] #[test]
fn test_transaction_pre_check_pass() { 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 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()); assert!(result.is_ok());
} }
#[test] #[tokio::test]
fn test_transaction_pre_check_native_transfer_valid() { async fn test_transaction_pre_check_native_transfer_valid() {
let config = setup_sequencer_config(); let (sequencer, _mempool_handle) = common_setup().await;
let mut sequencer = SequencerCore::start_from_config(config);
common_setup(&mut sequencer);
let acc1 = sequencer.sequencer_config.initial_accounts[0] let acc1 = sequencer.sequencer_config.initial_accounts[0]
.addr .account_id
.clone() .clone()
.from_base58() .from_base58()
.unwrap() .unwrap()
.try_into() .try_into()
.unwrap(); .unwrap();
let acc2 = sequencer.sequencer_config.initial_accounts[1] let acc2 = sequencer.sequencer_config.initial_accounts[1]
.addr .account_id
.clone() .clone()
.from_base58() .from_base58()
.unwrap() .unwrap()
@ -463,27 +461,24 @@ mod tests {
let tx = common::test_utils::create_transaction_native_token_transfer( let tx = common::test_utils::create_transaction_native_token_transfer(
acc1, 0, acc2, 10, sign_key1, 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()); assert!(result.is_ok());
} }
#[test] #[tokio::test]
fn test_transaction_pre_check_native_transfer_other_signature() { async fn test_transaction_pre_check_native_transfer_other_signature() {
let config = setup_sequencer_config(); let (mut sequencer, _mempool_handle) = common_setup().await;
let mut sequencer = SequencerCore::start_from_config(config);
common_setup(&mut sequencer);
let acc1 = sequencer.sequencer_config.initial_accounts[0] let acc1 = sequencer.sequencer_config.initial_accounts[0]
.addr .account_id
.clone() .clone()
.from_base58() .from_base58()
.unwrap() .unwrap()
.try_into() .try_into()
.unwrap(); .unwrap();
let acc2 = sequencer.sequencer_config.initial_accounts[1] let acc2 = sequencer.sequencer_config.initial_accounts[1]
.addr .account_id
.clone() .clone()
.from_base58() .from_base58()
.unwrap() .unwrap()
@ -497,9 +492,7 @@ mod tests {
); );
// Signature is valid, stateless check pass // Signature is valid, stateless check pass
let tx = sequencer let tx = transaction_pre_check(parse_unwrap_tx_body_into_nssa_tx(tx)).unwrap();
.transaction_pre_check(parse_unwrap_tx_body_into_nssa_tx(tx))
.unwrap();
// Signature is not from sender. Execution fails // Signature is not from sender. Execution fails
let result = sequencer.execute_check_transaction_on_state(tx); let result = sequencer.execute_check_transaction_on_state(tx);
@ -510,22 +503,19 @@ mod tests {
)); ));
} }
#[test] #[tokio::test]
fn test_transaction_pre_check_native_transfer_sent_too_much() { async fn test_transaction_pre_check_native_transfer_sent_too_much() {
let config = setup_sequencer_config(); let (mut sequencer, _mempool_handle) = common_setup().await;
let mut sequencer = SequencerCore::start_from_config(config);
common_setup(&mut sequencer);
let acc1 = sequencer.sequencer_config.initial_accounts[0] let acc1 = sequencer.sequencer_config.initial_accounts[0]
.addr .account_id
.clone() .clone()
.from_base58() .from_base58()
.unwrap() .unwrap()
.try_into() .try_into()
.unwrap(); .unwrap();
let acc2 = sequencer.sequencer_config.initial_accounts[1] let acc2 = sequencer.sequencer_config.initial_accounts[1]
.addr .account_id
.clone() .clone()
.from_base58() .from_base58()
.unwrap() .unwrap()
@ -538,9 +528,9 @@ mod tests {
acc1, 0, acc2, 10000000, sign_key1, 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()); assert!(result.is_ok());
let result = sequencer.execute_check_transaction_on_state(result.unwrap()); let result = sequencer.execute_check_transaction_on_state(result.unwrap());
@ -552,22 +542,19 @@ mod tests {
assert!(is_failed_at_balance_mismatch); assert!(is_failed_at_balance_mismatch);
} }
#[test] #[tokio::test]
fn test_transaction_execute_native_transfer() { async fn test_transaction_execute_native_transfer() {
let config = setup_sequencer_config(); let (mut sequencer, _mempool_handle) = common_setup().await;
let mut sequencer = SequencerCore::start_from_config(config);
common_setup(&mut sequencer);
let acc1 = sequencer.sequencer_config.initial_accounts[0] let acc1 = sequencer.sequencer_config.initial_accounts[0]
.addr .account_id
.clone() .clone()
.from_base58() .from_base58()
.unwrap() .unwrap()
.try_into() .try_into()
.unwrap(); .unwrap();
let acc2 = sequencer.sequencer_config.initial_accounts[1] let acc2 = sequencer.sequencer_config.initial_accounts[1]
.addr .account_id
.clone() .clone()
.from_base58() .from_base58()
.unwrap() .unwrap()
@ -586,84 +573,70 @@ mod tests {
let bal_from = sequencer let bal_from = sequencer
.state .state
.get_account_by_address(&nssa::Address::new(acc1)) .get_account_by_id(&nssa::AccountId::new(acc1))
.balance; .balance;
let bal_to = sequencer let bal_to = sequencer
.state .state
.get_account_by_address(&nssa::Address::new(acc2)) .get_account_by_id(&nssa::AccountId::new(acc2))
.balance; .balance;
assert_eq!(bal_from, 9900); assert_eq!(bal_from, 9900);
assert_eq!(bal_to, 20100); assert_eq!(bal_to, 20100);
} }
#[test] #[tokio::test]
fn test_push_tx_into_mempool_fails_mempool_full() { async fn test_push_tx_into_mempool_blocks_until_mempool_is_full() {
let config = SequencerConfig { let config = SequencerConfig {
mempool_max_size: 1, mempool_max_size: 1,
..setup_sequencer_config() ..setup_sequencer_config()
}; };
let mut sequencer = SequencerCore::start_from_config(config); let (mut sequencer, mempool_handle) = common_setup_with_config(config).await;
common_setup(&mut sequencer);
let tx = common::test_utils::produce_dummy_empty_transaction(); let tx = common::test_utils::produce_dummy_empty_transaction();
// Fill the mempool // 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!( // Empty the mempool by producing a block
result, sequencer
Err(TransactionMalformationError::MempoolFullForRound) .produce_new_block_with_mempool_transactions()
)); .unwrap();
// Resolve the pending push
assert!(push_fut.await.is_ok());
} }
#[test] #[tokio::test]
fn test_push_tx_into_mempool_pre_check() { async fn test_produce_new_block_with_mempool_transactions() {
let config = setup_sequencer_config(); let (mut sequencer, mempool_handle) = common_setup().await;
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);
let genesis_height = sequencer.chain_height; let genesis_height = sequencer.chain_height;
let tx = common::test_utils::produce_dummy_empty_transaction(); 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(); let block_id = sequencer.produce_new_block_with_mempool_transactions();
assert!(block_id.is_ok()); assert!(block_id.is_ok());
assert_eq!(block_id.unwrap(), genesis_height + 1); assert_eq!(block_id.unwrap(), genesis_height + 1);
} }
#[test] #[tokio::test]
fn test_replay_transactions_are_rejected_in_the_same_block() { async fn test_replay_transactions_are_rejected_in_the_same_block() {
let config = setup_sequencer_config(); let (mut sequencer, mempool_handle) = common_setup().await;
let mut sequencer = SequencerCore::start_from_config(config);
common_setup(&mut sequencer);
let acc1 = sequencer.sequencer_config.initial_accounts[0] let acc1 = sequencer.sequencer_config.initial_accounts[0]
.addr .account_id
.clone() .clone()
.from_base58() .from_base58()
.unwrap() .unwrap()
.try_into() .try_into()
.unwrap(); .unwrap();
let acc2 = sequencer.sequencer_config.initial_accounts[1] let acc2 = sequencer.sequencer_config.initial_accounts[1]
.addr .account_id
.clone() .clone()
.from_base58() .from_base58()
.unwrap() .unwrap()
@ -679,8 +652,8 @@ mod tests {
let tx_original = tx.clone(); let tx_original = tx.clone();
let tx_replay = tx.clone(); let tx_replay = tx.clone();
// Pushing two copies of the same tx to the mempool // Pushing two copies of the same tx to the mempool
sequencer.mempool.push_item(tx_original); mempool_handle.push(tx_original).await.unwrap();
sequencer.mempool.push_item(tx_replay); mempool_handle.push(tx_replay).await.unwrap();
// Create block // Create block
let current_height = sequencer let current_height = sequencer
@ -695,22 +668,19 @@ mod tests {
assert_eq!(block.body.transactions, vec![tx.clone()]); assert_eq!(block.body.transactions, vec![tx.clone()]);
} }
#[test] #[tokio::test]
fn test_replay_transactions_are_rejected_in_different_blocks() { async fn test_replay_transactions_are_rejected_in_different_blocks() {
let config = setup_sequencer_config(); let (mut sequencer, mempool_handle) = common_setup().await;
let mut sequencer = SequencerCore::start_from_config(config);
common_setup(&mut sequencer);
let acc1 = sequencer.sequencer_config.initial_accounts[0] let acc1 = sequencer.sequencer_config.initial_accounts[0]
.addr .account_id
.clone() .clone()
.from_base58() .from_base58()
.unwrap() .unwrap()
.try_into() .try_into()
.unwrap(); .unwrap();
let acc2 = sequencer.sequencer_config.initial_accounts[1] let acc2 = sequencer.sequencer_config.initial_accounts[1]
.addr .account_id
.clone() .clone()
.from_base58() .from_base58()
.unwrap() .unwrap()
@ -724,7 +694,7 @@ mod tests {
); );
// The transaction should be included the first time // 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 let current_height = sequencer
.produce_new_block_with_mempool_transactions() .produce_new_block_with_mempool_transactions()
.unwrap(); .unwrap();
@ -735,7 +705,7 @@ mod tests {
assert_eq!(block.body.transactions, vec![tx.clone()]); assert_eq!(block.body.transactions, vec![tx.clone()]);
// Add same transaction should fail // Add same transaction should fail
sequencer.mempool.push_item(tx); mempool_handle.push(tx.clone()).await.unwrap();
let current_height = sequencer let current_height = sequencer
.produce_new_block_with_mempool_transactions() .produce_new_block_with_mempool_transactions()
.unwrap(); .unwrap();
@ -746,29 +716,31 @@ mod tests {
assert!(block.body.transactions.is_empty()); assert!(block.body.transactions.is_empty());
} }
#[test] #[tokio::test]
fn test_restart_from_storage() { async fn test_restart_from_storage() {
let config = setup_sequencer_config(); let config = setup_sequencer_config();
let acc1_addr: nssa::Address = config.initial_accounts[0].addr.parse().unwrap(); let acc1_account_id: nssa::AccountId =
let acc2_addr: nssa::Address = config.initial_accounts[1].addr.parse().unwrap(); 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; let balance_to_move = 13;
// In the following code block a transaction will be processed that moves `balance_to_move` // 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 // 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. // 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 signing_key = PrivateKey::try_new([1; 32]).unwrap();
let tx = common::test_utils::create_transaction_native_token_transfer( let tx = common::test_utils::create_transaction_native_token_transfer(
*acc1_addr.value(), *acc1_account_id.value(),
0, 0,
*acc2_addr.value(), *acc2_account_id.value(),
balance_to_move, balance_to_move,
signing_key, signing_key,
); );
sequencer.mempool.push_item(tx.clone()); mempool_handle.push(tx.clone()).await.unwrap();
let current_height = sequencer let current_height = sequencer
.produce_new_block_with_mempool_transactions() .produce_new_block_with_mempool_transactions()
.unwrap(); .unwrap();
@ -781,9 +753,9 @@ mod tests {
// Instantiating a new sequencer from the same config. This should load the existing block // 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. // with the above transaction and update the state to reflect that.
let sequencer = SequencerCore::start_from_config(config.clone()); let (sequencer, _mempool_handle) = SequencerCore::start_from_config(config.clone());
let balance_acc_1 = sequencer.state.get_account_by_address(&acc1_addr).balance; let balance_acc_1 = sequencer.state.get_account_by_id(&acc1_account_id).balance;
let balance_acc_2 = sequencer.state.get_account_by_address(&acc2_addr).balance; let balance_acc_2 = sequencer.state.get_account_by_id(&acc2_account_id).balance;
// Balances should be consistent with the stored block // Balances should be consistent with the stored block
assert_eq!( assert_eq!(

View File

@ -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 }
}
}

View File

@ -19,6 +19,8 @@ actix-web.workspace = true
tokio.workspace = true tokio.workspace = true
borsh.workspace = true borsh.workspace = true
# TODO: Move to workspace
[dependencies.sequencer_core] [dependencies.sequencer_core]
path = "../sequencer_core" path = "../sequencer_core"
@ -27,3 +29,6 @@ path = "../common"
[dependencies.nssa] [dependencies.nssa]
path = "../nssa" path = "../nssa"
[dependencies.mempool]
path = "../mempool"

View File

@ -4,23 +4,23 @@ pub mod types;
use std::sync::Arc; use std::sync::Arc;
use common::rpc_primitives::{ use common::{
RpcPollingConfig, rpc_primitives::errors::{RpcError, RpcErrorKind},
errors::{RpcError, RpcErrorKind}, transaction::EncodedTransaction,
}; };
use mempool::MemPoolHandle;
pub use net_utils::*;
use sequencer_core::SequencerCore; use sequencer_core::SequencerCore;
use serde::Serialize; use serde::Serialize;
use serde_json::Value; use serde_json::Value;
pub use net_utils::*;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use self::types::err_rpc::RpcErr; use self::types::err_rpc::RpcErr;
//ToDo: Add necessary fields // ToDo: Add necessary fields
pub struct JsonHandler { pub struct JsonHandler {
pub polling_config: RpcPollingConfig, sequencer_state: Arc<Mutex<SequencerCore>>,
pub sequencer_state: Arc<Mutex<SequencerCore>>, mempool_handle: MemPoolHandle<EncodedTransaction>,
} }
fn respond<T: Serialize>(val: T) -> Result<Value, RpcErr> { fn respond<T: Serialize>(val: T) -> Result<Value, RpcErr> {

View File

@ -1,14 +1,14 @@
use std::io; use std::{io, sync::Arc};
use std::sync::Arc;
use actix_cors::Cors; use actix_cors::Cors;
use actix_web::{App, Error as HttpError, HttpResponse, HttpServer, http, middleware, web}; use actix_web::{App, Error as HttpError, HttpResponse, HttpServer, http, middleware, web};
use futures::Future; use common::{
use futures::FutureExt; rpc_primitives::{RpcConfig, message::Message},
transaction::EncodedTransaction,
};
use futures::{Future, FutureExt};
use log::info; use log::info;
use mempool::MemPoolHandle;
use common::rpc_primitives::RpcConfig;
use common::rpc_primitives::message::Message;
use sequencer_core::SequencerCore; use sequencer_core::SequencerCore;
use tokio::sync::Mutex; use tokio::sync::Mutex;
@ -46,17 +46,17 @@ fn get_cors(cors_allowed_origins: &[String]) -> Cors {
pub fn new_http_server( pub fn new_http_server(
config: RpcConfig, config: RpcConfig,
seuquencer_core: Arc<Mutex<SequencerCore>>, seuquencer_core: Arc<Mutex<SequencerCore>>,
mempool_handle: MemPoolHandle<EncodedTransaction>,
) -> io::Result<actix_web::dev::Server> { ) -> io::Result<actix_web::dev::Server> {
let RpcConfig { let RpcConfig {
addr, addr,
cors_allowed_origins, cors_allowed_origins,
polling_config,
limits_config, limits_config,
} = config; } = config;
info!(target:NETWORK, "Starting http server at {addr}"); info!(target:NETWORK, "Starting http server at {addr}");
let handler = web::Data::new(JsonHandler { let handler = web::Data::new(JsonHandler {
polling_config,
sequencer_state: seuquencer_core.clone(), sequencer_state: seuquencer_core.clone(),
mempool_handle,
}); });
// HTTP server // HTTP server

View File

@ -3,10 +3,6 @@ use std::collections::HashMap;
use actix_web::Error as HttpError; use actix_web::Error as HttpError;
use base58::FromBase58; use base58::FromBase58;
use base64::{Engine, engine::general_purpose}; use base64::{Engine, engine::general_purpose};
use nssa::{self, program::Program};
use sequencer_core::config::AccountInitialData;
use serde_json::Value;
use common::{ use common::{
HashType, HashType,
block::HashableBlockData, block::HashableBlockData,
@ -17,19 +13,20 @@ use common::{
requests::{ requests::{
GetAccountBalanceRequest, GetAccountBalanceResponse, GetAccountRequest, GetAccountBalanceRequest, GetAccountBalanceResponse, GetAccountRequest,
GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse, GetAccountResponse, GetAccountsNoncesRequest, GetAccountsNoncesResponse,
GetInitialTestnetAccountsRequest, GetProgramIdsRequest, GetProgramIdsResponse, GetBlockDataRequest, GetBlockDataResponse, GetGenesisIdRequest, GetGenesisIdResponse,
GetProofForCommitmentRequest, GetProofForCommitmentResponse, GetInitialTestnetAccountsRequest, GetLastBlockRequest, GetLastBlockResponse,
GetTransactionByHashRequest, GetTransactionByHashResponse, GetProgramIdsRequest, GetProgramIdsResponse, GetProofForCommitmentRequest,
GetProofForCommitmentResponse, GetTransactionByHashRequest,
GetTransactionByHashResponse, HelloRequest, HelloResponse, SendTxRequest,
SendTxResponse,
}, },
}, },
transaction::EncodedTransaction, transaction::{EncodedTransaction, NSSATransaction},
};
use common::rpc_primitives::requests::{
GetBlockDataRequest, GetBlockDataResponse, GetGenesisIdRequest, GetGenesisIdResponse,
GetLastBlockRequest, GetLastBlockResponse, HelloRequest, HelloResponse, SendTxRequest,
SendTxResponse,
}; };
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}; use super::{JsonHandler, respond, types::err_rpc::RpcErr};
@ -67,16 +64,16 @@ impl JsonHandler {
} }
} }
/// Example of request processing
#[allow(clippy::unused_async)] #[allow(clippy::unused_async)]
///Example of request processing
async fn process_temp_hello(&self, request: Request) -> Result<Value, RpcErr> { async fn process_temp_hello(&self, request: Request) -> Result<Value, RpcErr> {
let _hello_request = HelloRequest::parse(Some(request.params))?; let _hello_request = HelloRequest::parse(Some(request.params))?;
let helperstruct = HelloResponse { let response = HelloResponse {
greeting: HELLO_FROM_SEQUENCER.to_string(), greeting: HELLO_FROM_SEQUENCER.to_string(),
}; };
respond(helperstruct) respond(response)
} }
async fn process_send_tx(&self, request: Request) -> Result<Value, RpcErr> { async fn process_send_tx(&self, request: Request) -> Result<Value, RpcErr> {
@ -84,18 +81,25 @@ impl JsonHandler {
let tx = borsh::from_slice::<EncodedTransaction>(&send_tx_req.transaction).unwrap(); let tx = borsh::from_slice::<EncodedTransaction>(&send_tx_req.transaction).unwrap();
let tx_hash = hex::encode(tx.hash()); let tx_hash = hex::encode(tx.hash());
{ let transaction = NSSATransaction::try_from(&tx)
let mut state = self.sequencer_state.lock().await; .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(), status: TRANSACTION_SUBMITTED.to_string(),
tx_hash, tx_hash,
}; };
respond(helperstruct) respond(response)
} }
async fn process_get_block_data(&self, request: Request) -> Result<Value, RpcErr> { async fn process_get_block_data(&self, request: Request) -> Result<Value, RpcErr> {
@ -104,14 +108,16 @@ impl JsonHandler {
let block = { let block = {
let state = self.sequencer_state.lock().await; 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(), block: borsh::to_vec(&HashableBlockData::from(block)).unwrap(),
}; };
respond(helperstruct) respond(response)
} }
async fn process_get_genesis(&self, request: Request) -> Result<Value, RpcErr> { async fn process_get_genesis(&self, request: Request) -> Result<Value, RpcErr> {
@ -120,12 +126,12 @@ impl JsonHandler {
let genesis_id = { let genesis_id = {
let state = self.sequencer_state.lock().await; 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<Value, RpcErr> { async fn process_get_last_block(&self, request: Request) -> Result<Value, RpcErr> {
@ -134,12 +140,12 @@ impl JsonHandler {
let last_block = { let last_block = {
let state = self.sequencer_state.lock().await; 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 /// Returns the initial accounts for testnet
@ -151,83 +157,83 @@ impl JsonHandler {
let initial_accounts: Vec<AccountInitialData> = { let initial_accounts: Vec<AccountInitialData> = {
let state = self.sequencer_state.lock().await; let state = self.sequencer_state.lock().await;
state.sequencer_config.initial_accounts.clone() state.sequencer_config().initial_accounts.clone()
}; };
respond(initial_accounts) respond(initial_accounts)
} }
/// Returns the balance of the account at the given address. /// Returns the balance of the account at the given account_id.
/// The address must be a valid hex string of the correct length. /// The account_id must be a valid hex string of the correct length.
async fn process_get_account_balance(&self, request: Request) -> Result<Value, RpcErr> { async fn process_get_account_balance(&self, request: Request) -> Result<Value, RpcErr> {
let get_account_req = GetAccountBalanceRequest::parse(Some(request.params))?; let get_account_req = GetAccountBalanceRequest::parse(Some(request.params))?;
let address_bytes = get_account_req let account_id_bytes = get_account_req
.address .account_id
.from_base58() .from_base58()
.map_err(|_| RpcError::invalid_params("invalid base58".to_string()))?; .map_err(|_| RpcError::invalid_params("invalid base58".to_string()))?;
let address = nssa::Address::new( let account_id = nssa::AccountId::new(
address_bytes account_id_bytes
.try_into() .try_into()
.map_err(|_| RpcError::invalid_params("invalid length".to_string()))?, .map_err(|_| RpcError::invalid_params("invalid length".to_string()))?,
); );
let balance = { let balance = {
let state = self.sequencer_state.lock().await; 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 account.balance
}; };
let helperstruct = GetAccountBalanceResponse { balance }; let response = GetAccountBalanceResponse { balance };
respond(helperstruct) respond(response)
} }
/// Returns the nonces of the accounts at the given addresses. /// Returns the nonces of the accounts at the given account_ids.
/// Each address must be a valid hex string of the correct length. /// Each account_id must be a valid hex string of the correct length.
async fn process_get_accounts_nonces(&self, request: Request) -> Result<Value, RpcErr> { async fn process_get_accounts_nonces(&self, request: Request) -> Result<Value, RpcErr> {
let get_account_nonces_req = GetAccountsNoncesRequest::parse(Some(request.params))?; let get_account_nonces_req = GetAccountsNoncesRequest::parse(Some(request.params))?;
let mut addresses = vec![]; let mut account_ids = vec![];
for address_raw in get_account_nonces_req.addresses { for account_id_raw in get_account_nonces_req.account_ids {
let address = address_raw let account_id = account_id_raw
.parse::<nssa::Address>() .parse::<nssa::AccountId>()
.map_err(|e| RpcError::invalid_params(e.to_string()))?; .map_err(|e| RpcError::invalid_params(e.to_string()))?;
addresses.push(address); account_ids.push(account_id);
} }
let nonces = { let nonces = {
let state = self.sequencer_state.lock().await; let state = self.sequencer_state.lock().await;
addresses account_ids
.into_iter() .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() .collect()
}; };
let helperstruct = GetAccountsNoncesResponse { nonces }; let response = GetAccountsNoncesResponse { nonces };
respond(helperstruct) respond(response)
} }
/// Returns account struct for given address. /// Returns account struct for given account_id.
/// Address must be a valid hex string of the correct length. /// AccountId must be a valid hex string of the correct length.
async fn process_get_account(&self, request: Request) -> Result<Value, RpcErr> { async fn process_get_account(&self, request: Request) -> Result<Value, RpcErr> {
let get_account_nonces_req = GetAccountRequest::parse(Some(request.params))?; let get_account_nonces_req = GetAccountRequest::parse(Some(request.params))?;
let address = get_account_nonces_req let account_id = get_account_nonces_req
.address .account_id
.parse::<nssa::Address>() .parse::<nssa::AccountId>()
.map_err(|e| RpcError::invalid_params(e.to_string()))?; .map_err(|e| RpcError::invalid_params(e.to_string()))?;
let account = { let account = {
let state = self.sequencer_state.lock().await; 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. /// Returns the transaction corresponding to the given hash, if it exists in the blockchain.
@ -243,15 +249,15 @@ impl JsonHandler {
let transaction = { let transaction = {
let state = self.sequencer_state.lock().await; let state = self.sequencer_state.lock().await;
state state
.block_store .block_store()
.get_transaction_by_hash(hash) .get_transaction_by_hash(hash)
.map(|tx| borsh::to_vec(&tx).unwrap()) .map(|tx| borsh::to_vec(&tx).unwrap())
}; };
let base64_encoded = transaction.map(|tx| general_purpose::STANDARD.encode(tx)); let base64_encoded = transaction.map(|tx| general_purpose::STANDARD.encode(tx));
let helperstruct = GetTransactionByHashResponse { let response = GetTransactionByHashResponse {
transaction: base64_encoded, transaction: base64_encoded,
}; };
respond(helperstruct) respond(response)
} }
/// Returns the commitment proof, corresponding to commitment /// Returns the commitment proof, corresponding to commitment
@ -261,11 +267,11 @@ impl JsonHandler {
let membership_proof = { let membership_proof = {
let state = self.sequencer_state.lock().await; let state = self.sequencer_state.lock().await;
state state
.state .state()
.get_proof_for_commitment(&get_proof_req.commitment) .get_proof_for_commitment(&get_proof_req.commitment)
}; };
let helperstruct = GetProofForCommitmentResponse { membership_proof }; let response = GetProofForCommitmentResponse { membership_proof };
respond(helperstruct) respond(response)
} }
async fn process_get_program_ids(&self, request: Request) -> Result<Value, RpcErr> { async fn process_get_program_ids(&self, request: Request) -> Result<Value, RpcErr> {
@ -282,8 +288,8 @@ impl JsonHandler {
"privacy_preserving_circuit".to_string(), "privacy_preserving_circuit".to_string(),
nssa::PRIVACY_PRESERVING_CIRCUIT_ID, nssa::PRIVACY_PRESERVING_CIRCUIT_ID,
); );
let helperstruct = GetProgramIdsResponse { program_ids }; let response = GetProgramIdsResponse { program_ids };
respond(helperstruct) respond(response)
} }
pub async fn process_request_internal(&self, request: Request) -> Result<Value, RpcErr> { pub async fn process_request_internal(&self, request: Request) -> Result<Value, RpcErr> {
@ -309,14 +315,9 @@ impl JsonHandler {
mod tests { mod tests {
use std::sync::Arc; use std::sync::Arc;
use crate::{JsonHandler, rpc_handler};
use base58::ToBase58; use base58::ToBase58;
use base64::{Engine, engine::general_purpose}; use base64::{Engine, engine::general_purpose};
use common::{ use common::{test_utils::sequencer_sign_key_for_testing, transaction::EncodedTransaction};
rpc_primitives::RpcPollingConfig, test_utils::sequencer_sign_key_for_testing,
transaction::EncodedTransaction,
};
use sequencer_core::{ use sequencer_core::{
SequencerCore, SequencerCore,
config::{AccountInitialData, SequencerConfig}, config::{AccountInitialData, SequencerConfig},
@ -325,26 +326,28 @@ mod tests {
use tempfile::tempdir; use tempfile::tempdir;
use tokio::sync::Mutex; use tokio::sync::Mutex;
use crate::{JsonHandler, rpc_handler};
fn sequencer_config_for_tests() -> SequencerConfig { fn sequencer_config_for_tests() -> SequencerConfig {
let tempdir = tempdir().unwrap(); let tempdir = tempdir().unwrap();
let home = tempdir.path().to_path_buf(); let home = tempdir.path().to_path_buf();
let acc1_addr: Vec<u8> = vec![ let acc1_id: Vec<u8> = vec![
208, 122, 210, 232, 75, 39, 250, 0, 194, 98, 240, 161, 238, 160, 255, 53, 202, 9, 115, 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, 84, 126, 106, 16, 111, 114, 241, 147, 194, 220, 131, 139, 68,
]; ];
let acc2_addr: Vec<u8> = vec![ let acc2_id: Vec<u8> = vec![
231, 174, 119, 197, 239, 26, 5, 153, 147, 68, 175, 73, 159, 199, 138, 23, 5, 57, 141, 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, 98, 237, 6, 207, 46, 20, 121, 246, 222, 248, 154, 57, 188,
]; ];
let initial_acc1 = AccountInitialData { let initial_acc1 = AccountInitialData {
addr: acc1_addr.to_base58(), account_id: acc1_id.to_base58(),
balance: 10000, balance: 10000,
}; };
let initial_acc2 = AccountInitialData { let initial_acc2 = AccountInitialData {
addr: acc2_addr.to_base58(), account_id: acc2_id.to_base58(),
balance: 20000, balance: 20000,
}; };
@ -365,10 +368,10 @@ mod tests {
} }
} }
fn components_for_tests() -> (JsonHandler, Vec<AccountInitialData>, EncodedTransaction) { async fn components_for_tests() -> (JsonHandler, Vec<AccountInitialData>, EncodedTransaction) {
let config = sequencer_config_for_tests(); let config = sequencer_config_for_tests();
let mut sequencer_core = SequencerCore::start_from_config(config); let (mut sequencer_core, mempool_handle) = SequencerCore::start_from_config(config);
let initial_accounts = sequencer_core.sequencer_config.initial_accounts.clone(); let initial_accounts = sequencer_core.sequencer_config().initial_accounts.clone();
let signing_key = nssa::PrivateKey::try_new([1; 32]).unwrap(); let signing_key = nssa::PrivateKey::try_new([1; 32]).unwrap();
let balance_to_move = 10; let balance_to_move = 10;
@ -383,9 +386,10 @@ mod tests {
signing_key, signing_key,
); );
sequencer_core mempool_handle
.push_tx_into_mempool_pre_check(tx.clone()) .push(tx.clone())
.unwrap(); .await
.expect("Mempool is closed, this is a bug");
sequencer_core sequencer_core
.produce_new_block_with_mempool_transactions() .produce_new_block_with_mempool_transactions()
@ -395,8 +399,8 @@ mod tests {
( (
JsonHandler { JsonHandler {
polling_config: RpcPollingConfig::default(),
sequencer_state: sequencer_core, sequencer_state: sequencer_core,
mempool_handle,
}, },
initial_accounts, initial_accounts,
tx, tx,
@ -426,11 +430,11 @@ mod tests {
#[actix_web::test] #[actix_web::test]
async fn test_get_account_balance_for_non_existent_account() { 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!({ let request = serde_json::json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "get_account_balance", "method": "get_account_balance",
"params": { "address": "11".repeat(16) }, "params": { "account_id": "11".repeat(16) },
"id": 1 "id": 1
}); });
let expected_response = serde_json::json!({ let expected_response = serde_json::json!({
@ -448,11 +452,11 @@ mod tests {
#[actix_web::test] #[actix_web::test]
async fn test_get_account_balance_for_invalid_base58() { 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!({ let request = serde_json::json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "get_account_balance", "method": "get_account_balance",
"params": { "address": "not_a_valid_base58" }, "params": { "account_id": "not_a_valid_base58" },
"id": 1 "id": 1
}); });
let expected_response = serde_json::json!({ let expected_response = serde_json::json!({
@ -471,11 +475,11 @@ mod tests {
#[actix_web::test] #[actix_web::test]
async fn test_get_account_balance_for_invalid_length() { 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!({ let request = serde_json::json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "get_account_balance", "method": "get_account_balance",
"params": { "address": "cafecafe" }, "params": { "account_id": "cafecafe" },
"id": 1 "id": 1
}); });
let expected_response = serde_json::json!({ let expected_response = serde_json::json!({
@ -494,14 +498,14 @@ mod tests {
#[actix_web::test] #[actix_web::test]
async fn test_get_account_balance_for_existing_account() { 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!({ let request = serde_json::json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "get_account_balance", "method": "get_account_balance",
"params": { "address": acc1_addr }, "params": { "account_id": acc1_id },
"id": 1 "id": 1
}); });
let expected_response = serde_json::json!({ let expected_response = serde_json::json!({
@ -519,11 +523,11 @@ mod tests {
#[actix_web::test] #[actix_web::test]
async fn test_get_accounts_nonces_for_non_existent_account() { 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!({ let request = serde_json::json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "get_accounts_nonces", "method": "get_accounts_nonces",
"params": { "addresses": ["11".repeat(16)] }, "params": { "account_ids": ["11".repeat(16)] },
"id": 1 "id": 1
}); });
let expected_response = serde_json::json!({ let expected_response = serde_json::json!({
@ -541,15 +545,15 @@ mod tests {
#[actix_web::test] #[actix_web::test]
async fn test_get_accounts_nonces_for_existent_account() { 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 acc1_id = initial_accounts[0].account_id.clone();
let acc_2_addr = initial_accounts[1].addr.clone(); let acc2_id = initial_accounts[1].account_id.clone();
let request = serde_json::json!({ let request = serde_json::json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "get_accounts_nonces", "method": "get_accounts_nonces",
"params": { "addresses": [acc_1_addr, acc_2_addr] }, "params": { "account_ids": [acc1_id, acc2_id] },
"id": 1 "id": 1
}); });
let expected_response = serde_json::json!({ let expected_response = serde_json::json!({
@ -567,11 +571,11 @@ mod tests {
#[actix_web::test] #[actix_web::test]
async fn test_get_account_data_for_non_existent_account() { 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!({ let request = serde_json::json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "get_account", "method": "get_account",
"params": { "address": "11".repeat(16) }, "params": { "account_id": "11".repeat(16) },
"id": 1 "id": 1
}); });
let expected_response = serde_json::json!({ let expected_response = serde_json::json!({
@ -594,7 +598,7 @@ mod tests {
#[actix_web::test] #[actix_web::test]
async fn test_get_transaction_by_hash_for_non_existent_hash() { 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!({ let request = serde_json::json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "get_transaction_by_hash", "method": "get_transaction_by_hash",
@ -616,7 +620,7 @@ mod tests {
#[actix_web::test] #[actix_web::test]
async fn test_get_transaction_by_hash_for_invalid_hex() { 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!({ let request = serde_json::json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "get_transaction_by_hash", "method": "get_transaction_by_hash",
@ -640,7 +644,7 @@ mod tests {
#[actix_web::test] #[actix_web::test]
async fn test_get_transaction_by_hash_for_invalid_length() { 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!({ let request = serde_json::json!({
"jsonrpc": "2.0", "jsonrpc": "2.0",
"method": "get_transaction_by_hash", "method": "get_transaction_by_hash",
@ -664,7 +668,7 @@ mod tests {
#[actix_web::test] #[actix_web::test]
async fn test_get_transaction_by_hash_for_existing_transaction() { 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 tx_hash_hex = hex::encode(tx.hash());
let expected_base64_encoded = general_purpose::STANDARD.encode(borsh::to_vec(&tx).unwrap()); let expected_base64_encoded = general_purpose::STANDARD.encode(borsh::to_vec(&tx).unwrap());

View File

@ -1,6 +1,5 @@
use log::debug;
use common::rpc_primitives::errors::{RpcError, RpcParseError}; use common::rpc_primitives::errors::{RpcError, RpcParseError};
use log::debug;
use sequencer_core::TransactionMalformationError; use sequencer_core::TransactionMalformationError;
pub struct RpcErr(pub RpcError); pub struct RpcErr(pub RpcError);

View File

@ -9,11 +9,11 @@
"port": 3040, "port": 3040,
"initial_accounts": [ "initial_accounts": [
{ {
"addr": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", "account_id": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy",
"balance": 10000 "balance": 10000
}, },
{ {
"addr": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", "account_id": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw",
"balance": 20000 "balance": 20000
} }
], ],

View File

@ -1,11 +1,8 @@
use std::path::PathBuf; use std::{fs::File, io::BufReader, path::PathBuf};
use anyhow::Result; use anyhow::Result;
use sequencer_core::config::SequencerConfig; use sequencer_core::config::SequencerConfig;
use std::fs::File;
use std::io::BufReader;
pub fn from_file(config_home: PathBuf) -> Result<SequencerConfig> { pub fn from_file(config_home: PathBuf) -> Result<SequencerConfig> {
let file = File::open(config_home)?; let file = File::open(config_home)?;
let reader = BufReader::new(file); let reader = BufReader::new(file);

View File

@ -26,13 +26,17 @@ pub async fn startup_sequencer(
let block_timeout = app_config.block_create_timeout_millis; let block_timeout = app_config.block_create_timeout_millis;
let port = app_config.port; 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"); info!("Sequencer core set up");
let seq_core_wrapped = Arc::new(Mutex::new(sequencer_core)); 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"); info!("HTTP server started");
let http_server_handle = http_server.handle(); let http_server_handle = http_server.handle();
tokio::spawn(http_server); 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?; let (_, main_loop_handle) = startup_sequencer(app_config).await?;
main_loop_handle.await??; main_loop_handle.await??;

View File

@ -1,9 +1,9 @@
use anyhow::Result; use anyhow::Result;
use sequencer_runner::main_runner; use sequencer_runner::main_runner;
pub const NUM_THREADS: usize = 4; pub const NUM_THREADS: usize = 4;
// TODO: Why it requires config as a directory and not as a file?
fn main() -> Result<()> { fn main() -> Result<()> {
actix::System::with_tokio_rt(|| { actix::System::with_tokio_rt(|| {
tokio::runtime::Builder::new_multi_thread() tokio::runtime::Builder::new_multi_thread()

View File

@ -8,33 +8,33 @@ use rocksdb::{
pub mod error; 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; 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; 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"; 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"; 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"; 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"; 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"; 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"; 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 const CF_SNAPSHOT_NAME: &str = "cf_snapshot";
pub type DbResult<T> = Result<T, DbError>; pub type DbResult<T> = Result<T, DbError>;
@ -47,7 +47,7 @@ impl RocksDBIO {
pub fn open_or_create(path: &Path, start_block: Option<Block>) -> DbResult<Self> { pub fn open_or_create(path: &Path, start_block: Option<Block>) -> DbResult<Self> {
let mut cf_opts = Options::default(); let mut cf_opts = Options::default();
cf_opts.set_max_write_buffer_number(16); 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 cfb = ColumnFamilyDescriptor::new(CF_BLOCK_NAME, cf_opts.clone());
let cfmeta = ColumnFamilyDescriptor::new(CF_META_NAME, cf_opts.clone()); let cfmeta = ColumnFamilyDescriptor::new(CF_META_NAME, cf_opts.clone());
let cfsnapshot = ColumnFamilyDescriptor::new(CF_SNAPSHOT_NAME, cf_opts.clone()); let cfsnapshot = ColumnFamilyDescriptor::new(CF_SNAPSHOT_NAME, cf_opts.clone());
@ -62,7 +62,7 @@ impl RocksDBIO {
); );
let dbio = Self { 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(), db: db.unwrap(),
}; };
@ -86,7 +86,7 @@ impl RocksDBIO {
pub fn destroy(path: &Path) -> DbResult<()> { pub fn destroy(path: &Path) -> DbResult<()> {
let mut cf_opts = Options::default(); let mut cf_opts = Options::default();
cf_opts.set_max_write_buffer_number(16); 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 _cfb = ColumnFamilyDescriptor::new(CF_BLOCK_NAME, cf_opts.clone());
let _cfmeta = ColumnFamilyDescriptor::new(CF_META_NAME, cf_opts.clone()); let _cfmeta = ColumnFamilyDescriptor::new(CF_META_NAME, cf_opts.clone());
let _cfsnapshot = ColumnFamilyDescriptor::new(CF_SNAPSHOT_NAME, cf_opts.clone()); let _cfsnapshot = ColumnFamilyDescriptor::new(CF_SNAPSHOT_NAME, cf_opts.clone());

View File

@ -59,18 +59,18 @@ impl WalletChainStore {
for pers_acc_data in persistent_accounts { for pers_acc_data in persistent_accounts {
match pers_acc_data { match pers_acc_data {
PersistentAccountData::Public(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) => { 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 { PersistentAccountData::Preconfigured(acc_data) => match acc_data {
InitialAccountData::Public(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) => { InitialAccountData::Private(data) => {
private_init_acc_map 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() { for init_acc_data in config.initial_accounts.clone() {
match init_acc_data { match init_acc_data {
InitialAccountData::Public(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) => { InitialAccountData::Private(data) => {
let mut account = data.account; let mut account = data.account;
@ -102,7 +102,8 @@ impl WalletChainStore {
// the config. Therefore we overwrite it here on startup. Fix this when program // 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. // id can be fetched from the node and queried from the wallet.
account.program_owner = Program::authenticated_transfer_program().id(); 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,23 +124,23 @@ impl WalletChainStore {
pub fn insert_private_account_data( pub fn insert_private_account_data(
&mut self, &mut self,
addr: nssa::Address, account_id: nssa::AccountId,
account: nssa_core::account::Account, account: nssa_core::account::Account,
) { ) {
println!("inserting at address {addr}, this account {account:?}"); println!("inserting at address {account_id}, this account {account:?}");
let entry = self let entry = self
.user_data .user_data
.default_user_private_accounts .default_user_private_accounts
.entry(addr) .entry(account_id)
.and_modify(|data| data.1 = account.clone()); .and_modify(|data| data.1 = account.clone());
if matches!(entry, Entry::Vacant(_)) { if matches!(entry, Entry::Vacant(_)) {
} else { } else {
self.user_data self.user_data
.private_key_tree .private_key_tree
.addr_map .account_id_map
.get(&addr) .get(&account_id)
.map(|chain_index| { .map(|chain_index| {
self.user_data self.user_data
.private_key_tree .private_key_tree
@ -157,17 +158,16 @@ mod tests {
keys_private::ChildKeysPrivate, keys_public::ChildKeysPublic, traits::KeyNode, keys_private::ChildKeysPrivate, keys_public::ChildKeysPublic, traits::KeyNode,
}; };
use super::*;
use crate::config::{ use crate::config::{
InitialAccountData, PersistentAccountDataPrivate, PersistentAccountDataPublic, InitialAccountData, PersistentAccountDataPrivate, PersistentAccountDataPublic,
}; };
use super::*;
fn create_initial_accounts() -> Vec<InitialAccountData> { fn create_initial_accounts() -> Vec<InitialAccountData> {
let initial_acc1 = serde_json::from_str( let initial_acc1 = serde_json::from_str(
r#"{ r#"{
"Public": { "Public": {
"address": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", "account_id": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy",
"pub_sign_key": [ "pub_sign_key": [
16, 16,
162, 162,
@ -210,7 +210,7 @@ mod tests {
let initial_acc2 = serde_json::from_str( let initial_acc2 = serde_json::from_str(
r#"{ r#"{
"Public": { "Public": {
"address": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", "account_id": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw",
"pub_sign_key": [ "pub_sign_key": [
113, 113,
121, 121,
@ -273,12 +273,12 @@ mod tests {
vec![ vec![
PersistentAccountData::Public(PersistentAccountDataPublic { PersistentAccountData::Public(PersistentAccountDataPublic {
address: public_data.address(), account_id: public_data.account_id(),
chain_index: ChainIndex::root(), chain_index: ChainIndex::root(),
data: public_data, data: public_data,
}), }),
PersistentAccountData::Private(PersistentAccountDataPrivate { PersistentAccountData::Private(PersistentAccountDataPrivate {
address: private_data.address(), account_id: private_data.account_id(),
chain_index: ChainIndex::root(), chain_index: ChainIndex::root(),
data: private_data, data: private_data,
}), }),

View File

@ -2,13 +2,13 @@ use anyhow::Result;
use base58::ToBase58; use base58::ToBase58;
use clap::Subcommand; use clap::Subcommand;
use key_protocol::key_management::key_tree::chain_index::ChainIndex; 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 serde::Serialize;
use crate::{ use crate::{
SubcommandReturnValue, WalletCore, SubcommandReturnValue, WalletCore,
cli::WalletSubcommand, cli::WalletSubcommand,
helperfunctions::{AddressPrivacyKind, HumanReadableAccount, parse_addr_with_privacy_prefix}, helperfunctions::{AccountPrivacyKind, HumanReadableAccount, parse_addr_with_privacy_prefix},
parse_block_range, parse_block_range,
}; };
@ -28,7 +28,7 @@ struct TokenDefinition {
struct TokenHolding { struct TokenHolding {
#[allow(unused)] #[allow(unused)]
account_type: u8, account_type: u8,
definition_id: Address, definition_id: AccountId,
balance: u128, balance: u128,
} }
@ -56,7 +56,7 @@ impl TokenHolding {
None None
} else { } else {
let account_type = data[0]; 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()); let balance = u128::from_le_bytes(data[33..].try_into().unwrap());
Some(Self { Some(Self {
definition_id, definition_id,
@ -67,35 +67,35 @@ impl TokenHolding {
} }
} }
///Represents generic chain CLI subcommand /// Represents generic chain CLI subcommand
#[derive(Subcommand, Debug, Clone)] #[derive(Subcommand, Debug, Clone)]
pub enum AccountSubcommand { pub enum AccountSubcommand {
///Get account data /// Get account data
Get { Get {
///Flag to get raw account data /// Flag to get raw account data
#[arg(short, long)] #[arg(short, long)]
raw: bool, raw: bool,
///Valid 32 byte base58 string with privacy prefix /// Valid 32 byte base58 string with privacy prefix
#[arg(short, long)] #[arg(short, long)]
addr: String, account_id: String,
}, },
///Produce new public or private account /// Produce new public or private account
#[command(subcommand)] #[command(subcommand)]
New(NewSubcommand), New(NewSubcommand),
///Sync private accounts /// Sync private accounts
SyncPrivate {}, SyncPrivate {},
} }
///Represents generic register CLI subcommand /// Represents generic register CLI subcommand
#[derive(Subcommand, Debug, Clone)] #[derive(Subcommand, Debug, Clone)]
pub enum NewSubcommand { pub enum NewSubcommand {
///Register new public account /// Register new public account
Public { Public {
#[arg(long)] #[arg(long)]
/// Chain index of a parent node /// Chain index of a parent node
cci: ChainIndex, cci: ChainIndex,
}, },
///Register new private account /// Register new private account
Private { Private {
#[arg(long)] #[arg(long)]
/// Chain index of a parent node /// Chain index of a parent node
@ -110,28 +110,28 @@ impl WalletSubcommand for NewSubcommand {
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
match self { match self {
NewSubcommand::Public { cci } => { 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?; let path = wallet_core.store_persistent_data().await?;
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");
Ok(SubcommandReturnValue::RegisterAccount { addr }) Ok(SubcommandReturnValue::RegisterAccount { account_id })
} }
NewSubcommand::Private { cci } => { 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 let (key, _) = wallet_core
.storage .storage
.user_data .user_data
.get_private_account(&addr) .get_private_account(&account_id)
.unwrap(); .unwrap();
println!( println!(
"Generated new account with addr Private/{}", "Generated new account with account_id Private/{}",
addr.to_bytes().to_base58() account_id.to_bytes().to_base58()
); );
println!("With npk {}", hex::encode(key.nullifer_public_key.0)); println!("With npk {}", hex::encode(key.nullifer_public_key.0));
println!( println!(
@ -143,7 +143,7 @@ impl WalletSubcommand for NewSubcommand {
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");
Ok(SubcommandReturnValue::RegisterAccount { addr }) Ok(SubcommandReturnValue::RegisterAccount { account_id })
} }
} }
} }
@ -202,15 +202,17 @@ impl WalletSubcommand for AccountSubcommand {
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
match self { match self {
AccountSubcommand::Get { raw, addr } => { AccountSubcommand::Get { raw, account_id } => {
let (addr, addr_kind) = parse_addr_with_privacy_prefix(&addr)?; 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 { let account = match addr_kind {
AddressPrivacyKind::Public => wallet_core.get_account_public(addr).await?, AccountPrivacyKind::Public => {
AddressPrivacyKind::Private => wallet_core wallet_core.get_account_public(account_id).await?
.get_account_private(&addr) }
AccountPrivacyKind::Private => wallet_core
.get_account_private(&account_id)
.ok_or(anyhow::anyhow!("Private account not found in storage"))?, .ok_or(anyhow::anyhow!("Private account not found in storage"))?,
}; };
@ -252,7 +254,9 @@ impl WalletSubcommand for AccountSubcommand {
serde_json::to_string(&acc_view)? serde_json::to_string(&acc_view)?
} else { } else {
anyhow::bail!("Invalid data for account {addr:#?} with token program"); anyhow::bail!(
"Invalid data for account {account_id:#?} with token program"
);
} }
} }
_ => { _ => {
@ -280,7 +284,7 @@ impl WalletSubcommand for AccountSubcommand {
.storage .storage
.user_data .user_data
.private_key_tree .private_key_tree
.addr_map .account_id_map
.is_empty() .is_empty()
{ {
wallet_core.last_synced_block = curr_last_block; wallet_core.last_synced_block = curr_last_block;

View File

@ -3,19 +3,19 @@ use clap::Subcommand;
use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand}; use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand};
///Represents generic chain CLI subcommand /// Represents generic chain CLI subcommand
#[derive(Subcommand, Debug, Clone)] #[derive(Subcommand, Debug, Clone)]
pub enum ChainSubcommand { pub enum ChainSubcommand {
///Get current block id from sequencer /// Get current block id from sequencer
CurrentBlockId {}, CurrentBlockId {},
///Get block at id from sequencer /// Get block at id from sequencer
Block { Block {
#[arg(short, long)] #[arg(short, long)]
id: u64, id: u64,
}, },
///Get transaction at hash from sequencer /// Get transaction at hash from sequencer
Transaction { Transaction {
///hash - valid 32 byte hex string /// hash - valid 32 byte hex string
#[arg(short, long)] #[arg(short, long)]
hash: String, hash: String,
}, },

View File

@ -3,7 +3,7 @@ use clap::Subcommand;
use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand}; use crate::{SubcommandReturnValue, WalletCore, cli::WalletSubcommand};
///Represents generic config CLI subcommand /// Represents generic config CLI subcommand
#[derive(Subcommand, Debug, Clone)] #[derive(Subcommand, Debug, Clone)]
pub enum ConfigSubcommand { pub enum ConfigSubcommand {
/// Command to explicitly setup config and storage /// Command to explicitly setup config and storage
@ -115,7 +115,7 @@ impl WalletSubcommand for ConfigSubcommand {
println!("Value of variable RUST_LOG to override, affects logging"); println!("Value of variable RUST_LOG to override, affects logging");
} }
"sequencer_addr" => { "sequencer_addr" => {
println!("HTTP V4 address of sequencer"); println!("HTTP V4 account_id of sequencer");
} }
"seq_poll_timeout_millis" => { "seq_poll_timeout_millis" => {
println!( println!(

View File

@ -1,42 +1,43 @@
use anyhow::Result; use anyhow::Result;
use clap::Subcommand; use clap::Subcommand;
use common::transaction::NSSATransaction; use common::transaction::NSSATransaction;
use nssa::Address; use nssa::AccountId;
use crate::{ use crate::{
SubcommandReturnValue, WalletCore, SubcommandReturnValue, WalletCore,
cli::WalletSubcommand, 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)] #[derive(Subcommand, Debug, Clone)]
pub enum AuthTransferSubcommand { pub enum AuthTransferSubcommand {
///Initialize account under authenticated transfer program /// Initialize account under authenticated transfer program
Init { Init {
///addr - valid 32 byte base58 string with privacy prefix /// account_id - valid 32 byte base58 string with privacy prefix
#[arg(long)] #[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 { Send {
///from - valid 32 byte base58 string with privacy prefix /// from - valid 32 byte base58 string with privacy prefix
#[arg(long)] #[arg(long)]
from: String, from: String,
///to - valid 32 byte base58 string with privacy prefix /// to - valid 32 byte base58 string with privacy prefix
#[arg(long)] #[arg(long)]
to: Option<String>, to: Option<String>,
///to_npk - valid 32 byte hex string /// to_npk - valid 32 byte hex string
#[arg(long)] #[arg(long)]
to_npk: Option<String>, to_npk: Option<String>,
///to_ipk - valid 33 byte hex string /// to_ipk - valid 33 byte hex string
#[arg(long)] #[arg(long)]
to_ipk: Option<String>, to_ipk: Option<String>,
///amount - amount of balance to move /// amount - amount of balance to move
#[arg(long)] #[arg(long)]
amount: u128, amount: u128,
}, },
@ -48,15 +49,15 @@ impl WalletSubcommand for AuthTransferSubcommand {
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
match self { match self {
AuthTransferSubcommand::Init { addr } => { AuthTransferSubcommand::Init { account_id } => {
let (addr, addr_privacy) = parse_addr_with_privacy_prefix(&addr)?; let (account_id, addr_privacy) = parse_addr_with_privacy_prefix(&account_id)?;
match addr_privacy { match addr_privacy {
AddressPrivacyKind::Public => { AccountPrivacyKind::Public => {
let addr = addr.parse()?; let account_id = account_id.parse()?;
let res = wallet_core let res = wallet_core
.register_account_under_authenticated_transfers_programs(addr) .register_account_under_authenticated_transfers_programs(account_id)
.await?; .await?;
println!("Results of tx send is {res:#?}"); println!("Results of tx send is {res:#?}");
@ -70,11 +71,13 @@ impl WalletSubcommand for AuthTransferSubcommand {
println!("Stored persistent accounts at {path:#?}"); println!("Stored persistent accounts at {path:#?}");
} }
AddressPrivacyKind::Private => { AccountPrivacyKind::Private => {
let addr = addr.parse()?; let account_id = account_id.parse()?;
let (res, [secret]) = wallet_core let (res, [secret]) = wallet_core
.register_account_under_authenticated_transfers_programs_private(addr) .register_account_under_authenticated_transfers_programs_private(
account_id,
)
.await?; .await?;
println!("Results of tx send is {res:#?}"); println!("Results of tx send is {res:#?}");
@ -85,7 +88,7 @@ impl WalletSubcommand for AuthTransferSubcommand {
.await?; .await?;
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { 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( wallet_core.decode_insert_privacy_preserving_transaction_results(
tx, tx,
@ -111,12 +114,12 @@ impl WalletSubcommand for AuthTransferSubcommand {
let underlying_subcommand = match (to, to_npk, to_ipk) { let underlying_subcommand = match (to, to_npk, to_ipk) {
(None, None, None) => { (None, None, None) => {
anyhow::bail!( 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(_)) => { (Some(_), Some(_), Some(_)) => {
anyhow::bail!( 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(_)) => { (_, Some(_), None) | (_, None, Some(_)) => {
@ -127,10 +130,10 @@ impl WalletSubcommand for AuthTransferSubcommand {
let (to, to_privacy) = parse_addr_with_privacy_prefix(&to)?; let (to, to_privacy) = parse_addr_with_privacy_prefix(&to)?;
match (from_privacy, to_privacy) { match (from_privacy, to_privacy) {
(AddressPrivacyKind::Public, AddressPrivacyKind::Public) => { (AccountPrivacyKind::Public, AccountPrivacyKind::Public) => {
NativeTokenTransferProgramSubcommand::Public { from, to, amount } NativeTokenTransferProgramSubcommand::Public { from, to, amount }
} }
(AddressPrivacyKind::Private, AddressPrivacyKind::Private) => { (AccountPrivacyKind::Private, AccountPrivacyKind::Private) => {
NativeTokenTransferProgramSubcommand::Private( NativeTokenTransferProgramSubcommand::Private(
NativeTokenTransferProgramSubcommandPrivate::PrivateOwned { NativeTokenTransferProgramSubcommandPrivate::PrivateOwned {
from, from,
@ -139,14 +142,14 @@ impl WalletSubcommand for AuthTransferSubcommand {
}, },
) )
} }
(AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { (AccountPrivacyKind::Private, AccountPrivacyKind::Public) => {
NativeTokenTransferProgramSubcommand::Deshielded { NativeTokenTransferProgramSubcommand::Deshielded {
from, from,
to, to,
amount, amount,
} }
} }
(AddressPrivacyKind::Public, AddressPrivacyKind::Private) => { (AccountPrivacyKind::Public, AccountPrivacyKind::Private) => {
NativeTokenTransferProgramSubcommand::Shielded( NativeTokenTransferProgramSubcommand::Shielded(
NativeTokenTransferProgramSubcommandShielded::ShieldedOwned { NativeTokenTransferProgramSubcommandShielded::ShieldedOwned {
from, from,
@ -161,7 +164,7 @@ impl WalletSubcommand for AuthTransferSubcommand {
let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?; let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?;
match from_privacy { match from_privacy {
AddressPrivacyKind::Private => { AccountPrivacyKind::Private => {
NativeTokenTransferProgramSubcommand::Private( NativeTokenTransferProgramSubcommand::Private(
NativeTokenTransferProgramSubcommandPrivate::PrivateForeign { NativeTokenTransferProgramSubcommandPrivate::PrivateForeign {
from, from,
@ -171,7 +174,7 @@ impl WalletSubcommand for AuthTransferSubcommand {
}, },
) )
} }
AddressPrivacyKind::Public => { AccountPrivacyKind::Public => {
NativeTokenTransferProgramSubcommand::Shielded( NativeTokenTransferProgramSubcommand::Shielded(
NativeTokenTransferProgramSubcommandShielded::ShieldedForeign { NativeTokenTransferProgramSubcommandShielded::ShieldedForeign {
from, 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)] #[derive(Subcommand, Debug, Clone)]
pub enum NativeTokenTransferProgramSubcommand { 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 operation
Public { Public {
///from - valid 32 byte hex string /// from - valid 32 byte hex string
#[arg(long)] #[arg(long)]
from: String, from: String,
///to - valid 32 byte hex string /// to - valid 32 byte hex string
#[arg(long)] #[arg(long)]
to: String, to: String,
///amount - amount of balance to move /// amount - amount of balance to move
#[arg(long)] #[arg(long)]
amount: u128, amount: u128,
}, },
///Private execution /// Private execution
#[command(subcommand)] #[command(subcommand)]
Private(NativeTokenTransferProgramSubcommandPrivate), 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 operation
Deshielded { Deshielded {
///from - valid 32 byte hex string /// from - valid 32 byte hex string
#[arg(long)] #[arg(long)]
from: String, from: String,
///to - valid 32 byte hex string /// to - valid 32 byte hex string
#[arg(long)] #[arg(long)]
to: String, to: String,
///amount - amount of balance to move /// amount - amount of balance to move
#[arg(long)] #[arg(long)]
amount: u128, amount: u128,
}, },
///Shielded execution /// Shielded execution
#[command(subcommand)] #[command(subcommand)]
Shielded(NativeTokenTransferProgramSubcommandShielded), 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)] #[derive(Subcommand, Debug, Clone)]
pub enum NativeTokenTransferProgramSubcommandShielded { 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 /// Shielded operation
ShieldedOwned { ShieldedOwned {
///from - valid 32 byte hex string /// from - valid 32 byte hex string
#[arg(long)] #[arg(long)]
from: String, from: String,
///to - valid 32 byte hex string /// to - valid 32 byte hex string
#[arg(long)] #[arg(long)]
to: String, to: String,
///amount - amount of balance to move /// amount - amount of balance to move
#[arg(long)] #[arg(long)]
amount: u128, amount: u128,
}, },
///Send native token transfer from `from` to `to` for `amount` /// Send native token transfer from `from` to `to` for `amount`
/// ///
/// Shielded operation /// Shielded operation
ShieldedForeign { ShieldedForeign {
///from - valid 32 byte hex string /// from - valid 32 byte hex string
#[arg(long)] #[arg(long)]
from: String, from: String,
///to_npk - valid 32 byte hex string /// to_npk - valid 32 byte hex string
#[arg(long)] #[arg(long)]
to_npk: String, to_npk: String,
///to_ipk - valid 33 byte hex string /// to_ipk - valid 33 byte hex string
#[arg(long)] #[arg(long)]
to_ipk: String, to_ipk: String,
///amount - amount of balance to move /// amount - amount of balance to move
#[arg(long)] #[arg(long)]
amount: u128, 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)] #[derive(Subcommand, Debug, Clone)]
pub enum NativeTokenTransferProgramSubcommandPrivate { 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 /// Private operation
PrivateOwned { PrivateOwned {
///from - valid 32 byte hex string /// from - valid 32 byte hex string
#[arg(long)] #[arg(long)]
from: String, from: String,
///to - valid 32 byte hex string /// to - valid 32 byte hex string
#[arg(long)] #[arg(long)]
to: String, to: String,
///amount - amount of balance to move /// amount - amount of balance to move
#[arg(long)] #[arg(long)]
amount: u128, amount: u128,
}, },
///Send native token transfer from `from` to `to` for `amount` /// Send native token transfer from `from` to `to` for `amount`
/// ///
/// Private operation /// Private operation
PrivateForeign { PrivateForeign {
///from - valid 32 byte hex string /// from - valid 32 byte hex string
#[arg(long)] #[arg(long)]
from: String, from: String,
///to_npk - valid 32 byte hex string /// to_npk - valid 32 byte hex string
#[arg(long)] #[arg(long)]
to_npk: String, to_npk: String,
///to_ipk - valid 33 byte hex string /// to_ipk - valid 33 byte hex string
#[arg(long)] #[arg(long)]
to_ipk: String, to_ipk: String,
///amount - amount of balance to move /// amount - amount of balance to move
#[arg(long)] #[arg(long)]
amount: u128, amount: u128,
}, },
@ -309,8 +314,8 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
match self { match self {
NativeTokenTransferProgramSubcommandPrivate::PrivateOwned { from, to, amount } => { NativeTokenTransferProgramSubcommandPrivate::PrivateOwned { from, to, amount } => {
let from: Address = from.parse().unwrap(); let from: AccountId = from.parse().unwrap();
let to: Address = to.parse().unwrap(); let to: AccountId = to.parse().unwrap();
let to_initialization = wallet_core.check_private_account_initialized(&to).await?; let to_initialization = wallet_core.check_private_account_initialized(&to).await?;
@ -356,7 +361,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandPrivate {
to_ipk, to_ipk,
amount, amount,
} => { } => {
let from: Address = from.parse().unwrap(); let from: AccountId = from.parse().unwrap();
let to_npk_res = hex::decode(to_npk)?; let to_npk_res = hex::decode(to_npk)?;
let mut to_npk = [0; 32]; let mut to_npk = [0; 32];
to_npk.copy_from_slice(&to_npk_res); to_npk.copy_from_slice(&to_npk_res);
@ -405,8 +410,8 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
match self { match self {
NativeTokenTransferProgramSubcommandShielded::ShieldedOwned { from, to, amount } => { NativeTokenTransferProgramSubcommandShielded::ShieldedOwned { from, to, amount } => {
let from: Address = from.parse().unwrap(); let from: AccountId = from.parse().unwrap();
let to: Address = to.parse().unwrap(); let to: AccountId = to.parse().unwrap();
let to_initialization = wallet_core.check_private_account_initialized(&to).await?; let to_initialization = wallet_core.check_private_account_initialized(&to).await?;
@ -450,7 +455,7 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommandShielded {
to_ipk, to_ipk,
amount, amount,
} => { } => {
let from: Address = from.parse().unwrap(); let from: AccountId = from.parse().unwrap();
let to_npk_res = hex::decode(to_npk)?; let to_npk_res = hex::decode(to_npk)?;
let mut to_npk = [0; 32]; let mut to_npk = [0; 32];
@ -494,8 +499,8 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand {
shielded_subcommand.handle_subcommand(wallet_core).await shielded_subcommand.handle_subcommand(wallet_core).await
} }
NativeTokenTransferProgramSubcommand::Deshielded { from, to, amount } => { NativeTokenTransferProgramSubcommand::Deshielded { from, to, amount } => {
let from: Address = from.parse().unwrap(); let from: AccountId = from.parse().unwrap();
let to: Address = to.parse().unwrap(); let to: AccountId = to.parse().unwrap();
let (res, [secret]) = wallet_core let (res, [secret]) = wallet_core
.send_deshielded_native_token_transfer(from, to, amount) .send_deshielded_native_token_transfer(from, to, amount)
@ -524,8 +529,8 @@ impl WalletSubcommand for NativeTokenTransferProgramSubcommand {
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
} }
NativeTokenTransferProgramSubcommand::Public { from, to, amount } => { NativeTokenTransferProgramSubcommand::Public { from, to, amount } => {
let from: Address = from.parse().unwrap(); let from: AccountId = from.parse().unwrap();
let to: Address = to.parse().unwrap(); let to: AccountId = to.parse().unwrap();
let res = wallet_core let res = wallet_core
.send_public_native_token_transfer(from, to, amount) .send_public_native_token_transfer(from, to, amount)

View File

@ -6,18 +6,18 @@ use log::info;
use crate::{ use crate::{
SubcommandReturnValue, WalletCore, SubcommandReturnValue, WalletCore,
cli::WalletSubcommand, 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)] #[derive(Subcommand, Debug, Clone)]
pub enum PinataProgramAgnosticSubcommand { pub enum PinataProgramAgnosticSubcommand {
///Claim pinata /// Claim pinata
Claim { Claim {
///to_addr - valid 32 byte base58 string with privacy prefix /// to_account_id - valid 32 byte base58 string with privacy prefix
#[arg(long)] #[arg(long)]
to_addr: String, to_account_id: String,
///solution - solution to pinata challenge /// solution - solution to pinata challenge
#[arg(long)] #[arg(long)]
solution: u128, solution: u128,
}, },
@ -29,21 +29,25 @@ impl WalletSubcommand for PinataProgramAgnosticSubcommand {
wallet_core: &mut WalletCore, wallet_core: &mut WalletCore,
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
let underlying_subcommand = match self { let underlying_subcommand = match self {
PinataProgramAgnosticSubcommand::Claim { to_addr, solution } => { PinataProgramAgnosticSubcommand::Claim {
let (to_addr, to_addr_privacy) = parse_addr_with_privacy_prefix(&to_addr)?; to_account_id,
solution,
} => {
let (to_account_id, to_addr_privacy) =
parse_addr_with_privacy_prefix(&to_account_id)?;
match to_addr_privacy { match to_addr_privacy {
AddressPrivacyKind::Public => { AccountPrivacyKind::Public => {
PinataProgramSubcommand::Public(PinataProgramSubcommandPublic::Claim { PinataProgramSubcommand::Public(PinataProgramSubcommandPublic::Claim {
pinata_addr: PINATA_BASE58.to_string(), pinata_account_id: PINATA_BASE58.to_string(),
winner_addr: to_addr, winner_account_id: to_account_id,
solution, solution,
}) })
} }
AddressPrivacyKind::Private => PinataProgramSubcommand::Private( AccountPrivacyKind::Private => PinataProgramSubcommand::Private(
PinataProgramSubcommandPrivate::ClaimPrivateOwned { PinataProgramSubcommandPrivate::ClaimPrivateOwned {
pinata_addr: PINATA_BASE58.to_string(), pinata_account_id: PINATA_BASE58.to_string(),
winner_addr: to_addr, winner_account_id: to_account_id,
solution, 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)] #[derive(Subcommand, Debug, Clone)]
pub enum PinataProgramSubcommand { pub enum PinataProgramSubcommand {
///Public execution /// Public execution
#[command(subcommand)] #[command(subcommand)]
Public(PinataProgramSubcommandPublic), Public(PinataProgramSubcommandPublic),
///Private execution /// Private execution
#[command(subcommand)] #[command(subcommand)]
Private(PinataProgramSubcommandPrivate), 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)] #[derive(Subcommand, Debug, Clone)]
pub enum PinataProgramSubcommandPublic { pub enum PinataProgramSubcommandPublic {
// TODO: Testnet only. Refactor to prevent compilation on mainnet. // TODO: Testnet only. Refactor to prevent compilation on mainnet.
// Claim piñata prize // Claim piñata prize
Claim { Claim {
///pinata_addr - valid 32 byte hex string /// pinata_account_id - valid 32 byte hex string
#[arg(long)] #[arg(long)]
pinata_addr: String, pinata_account_id: String,
///winner_addr - valid 32 byte hex string /// winner_account_id - valid 32 byte hex string
#[arg(long)] #[arg(long)]
winner_addr: String, winner_account_id: String,
///solution - solution to pinata challenge /// solution - solution to pinata challenge
#[arg(long)] #[arg(long)]
solution: u128, 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)] #[derive(Subcommand, Debug, Clone)]
pub enum PinataProgramSubcommandPrivate { pub enum PinataProgramSubcommandPrivate {
// TODO: Testnet only. Refactor to prevent compilation on mainnet. // TODO: Testnet only. Refactor to prevent compilation on mainnet.
// Claim piñata prize // Claim piñata prize
ClaimPrivateOwned { ClaimPrivateOwned {
///pinata_addr - valid 32 byte hex string /// pinata_account_id - valid 32 byte hex string
#[arg(long)] #[arg(long)]
pinata_addr: String, pinata_account_id: String,
///winner_addr - valid 32 byte hex string /// winner_account_id - valid 32 byte hex string
#[arg(long)] #[arg(long)]
winner_addr: String, winner_account_id: String,
///solution - solution to pinata challenge /// solution - solution to pinata challenge
#[arg(long)] #[arg(long)]
solution: u128, solution: u128,
}, },
@ -109,14 +113,14 @@ impl WalletSubcommand for PinataProgramSubcommandPublic {
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
match self { match self {
PinataProgramSubcommandPublic::Claim { PinataProgramSubcommandPublic::Claim {
pinata_addr, pinata_account_id,
winner_addr, winner_account_id,
solution, solution,
} => { } => {
let res = wallet_core let res = wallet_core
.claim_pinata( .claim_pinata(
pinata_addr.parse().unwrap(), pinata_account_id.parse().unwrap(),
winner_addr.parse().unwrap(), winner_account_id.parse().unwrap(),
solution, solution,
) )
.await?; .await?;
@ -135,22 +139,22 @@ impl WalletSubcommand for PinataProgramSubcommandPrivate {
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
match self { match self {
PinataProgramSubcommandPrivate::ClaimPrivateOwned { PinataProgramSubcommandPrivate::ClaimPrivateOwned {
pinata_addr, pinata_account_id,
winner_addr, winner_account_id,
solution, solution,
} => { } => {
let pinata_addr = pinata_addr.parse().unwrap(); let pinata_account_id = pinata_account_id.parse().unwrap();
let winner_addr = winner_addr.parse().unwrap(); let winner_account_id = winner_account_id.parse().unwrap();
let winner_initialization = wallet_core let winner_initialization = wallet_core
.check_private_account_initialized(&winner_addr) .check_private_account_initialized(&winner_account_id)
.await?; .await?;
let (res, [secret_winner]) = if let Some(winner_proof) = winner_initialization { let (res, [secret_winner]) = if let Some(winner_proof) = winner_initialization {
wallet_core wallet_core
.claim_pinata_private_owned_account_already_initialized( .claim_pinata_private_owned_account_already_initialized(
pinata_addr, pinata_account_id,
winner_addr, winner_account_id,
solution, solution,
winner_proof, winner_proof,
) )
@ -158,8 +162,8 @@ impl WalletSubcommand for PinataProgramSubcommandPrivate {
} else { } else {
wallet_core wallet_core
.claim_pinata_private_owned_account_not_initialized( .claim_pinata_private_owned_account_not_initialized(
pinata_addr, pinata_account_id,
winner_addr, winner_account_id,
solution, solution,
) )
.await? .await?
@ -173,7 +177,7 @@ impl WalletSubcommand for PinataProgramSubcommandPrivate {
.await?; .await?;
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { 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( wallet_core.decode_insert_privacy_preserving_transaction_results(
tx, tx,

View File

@ -1,51 +1,52 @@
use anyhow::Result; use anyhow::Result;
use clap::Subcommand; use clap::Subcommand;
use common::transaction::NSSATransaction; use common::transaction::NSSATransaction;
use nssa::Address; use nssa::AccountId;
use crate::{ use crate::{
SubcommandReturnValue, WalletCore, SubcommandReturnValue, WalletCore,
cli::WalletSubcommand, 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)] #[derive(Subcommand, Debug, Clone)]
pub enum TokenProgramAgnosticSubcommand { 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 { New {
///definition_addr - valid 32 byte base58 string with privacy prefix /// definition_account_id - valid 32 byte base58 string with privacy prefix
#[arg(long)] #[arg(long)]
definition_addr: String, definition_account_id: String,
///supply_addr - valid 32 byte base58 string with privacy prefix /// supply_account_id - valid 32 byte base58 string with privacy prefix
#[arg(long)] #[arg(long)]
supply_addr: String, supply_account_id: String,
#[arg(short, long)] #[arg(short, long)]
name: String, name: String,
#[arg(short, long)] #[arg(short, long)]
total_supply: u128, 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 { Send {
///from - valid 32 byte base58 string with privacy prefix /// from - valid 32 byte base58 string with privacy prefix
#[arg(long)] #[arg(long)]
from: String, from: String,
///to - valid 32 byte base58 string with privacy prefix /// to - valid 32 byte base58 string with privacy prefix
#[arg(long)] #[arg(long)]
to: Option<String>, to: Option<String>,
///to_npk - valid 32 byte hex string /// to_npk - valid 32 byte hex string
#[arg(long)] #[arg(long)]
to_npk: Option<String>, to_npk: Option<String>,
///to_ipk - valid 33 byte hex string /// to_ipk - valid 33 byte hex string
#[arg(long)] #[arg(long)]
to_ipk: Option<String>, to_ipk: Option<String>,
///amount - amount of balance to move /// amount - amount of balance to move
#[arg(long)] #[arg(long)]
amount: u128, amount: u128,
}, },
@ -58,43 +59,45 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
match self { match self {
TokenProgramAgnosticSubcommand::New { TokenProgramAgnosticSubcommand::New {
definition_addr, definition_account_id,
supply_addr, supply_account_id,
name, name,
total_supply, total_supply,
} => { } => {
let (definition_addr, definition_addr_privacy) = let (definition_account_id, definition_addr_privacy) =
parse_addr_with_privacy_prefix(&definition_addr)?; parse_addr_with_privacy_prefix(&definition_account_id)?;
let (supply_addr, supply_addr_privacy) = let (supply_account_id, supply_addr_privacy) =
parse_addr_with_privacy_prefix(&supply_addr)?; parse_addr_with_privacy_prefix(&supply_account_id)?;
let underlying_subcommand = match (definition_addr_privacy, supply_addr_privacy) { let underlying_subcommand = match (definition_addr_privacy, supply_addr_privacy) {
(AddressPrivacyKind::Public, AddressPrivacyKind::Public) => { (AccountPrivacyKind::Public, AccountPrivacyKind::Public) => {
TokenProgramSubcommand::Public( TokenProgramSubcommand::Public(
TokenProgramSubcommandPublic::CreateNewToken { TokenProgramSubcommandPublic::CreateNewToken {
definition_addr, definition_account_id,
supply_addr, supply_account_id,
name, name,
total_supply, total_supply,
}, },
) )
} }
(AddressPrivacyKind::Public, AddressPrivacyKind::Private) => { (AccountPrivacyKind::Public, AccountPrivacyKind::Private) => {
TokenProgramSubcommand::Private( TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned { TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned {
definition_addr, definition_account_id,
supply_addr, supply_account_id,
name, name,
total_supply, total_supply,
}, },
) )
} }
(AddressPrivacyKind::Private, AddressPrivacyKind::Private) => { (AccountPrivacyKind::Private, AccountPrivacyKind::Private) => {
//ToDo: maybe implement this one. It is not immediately clear why definition should be private. // ToDo: maybe implement this one. It is not immediately clear why
// definition should be private.
anyhow::bail!("Unavailable privacy pairing") anyhow::bail!("Unavailable privacy pairing")
} }
(AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { (AccountPrivacyKind::Private, AccountPrivacyKind::Public) => {
//ToDo: Probably valid. If definition is not public, but supply is it is very suspicious. // ToDo: Probably valid. If definition is not public, but supply is it is
// very suspicious.
anyhow::bail!("Unavailable privacy pairing") anyhow::bail!("Unavailable privacy pairing")
} }
}; };
@ -111,12 +114,12 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
let underlying_subcommand = match (to, to_npk, to_ipk) { let underlying_subcommand = match (to, to_npk, to_ipk) {
(None, None, None) => { (None, None, None) => {
anyhow::bail!( 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(_)) => { (Some(_), Some(_), Some(_)) => {
anyhow::bail!( 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(_)) => { (_, Some(_), None) | (_, None, Some(_)) => {
@ -127,38 +130,38 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
let (to, to_privacy) = parse_addr_with_privacy_prefix(&to)?; let (to, to_privacy) = parse_addr_with_privacy_prefix(&to)?;
match (from_privacy, to_privacy) { match (from_privacy, to_privacy) {
(AddressPrivacyKind::Public, AddressPrivacyKind::Public) => { (AccountPrivacyKind::Public, AccountPrivacyKind::Public) => {
TokenProgramSubcommand::Public( TokenProgramSubcommand::Public(
TokenProgramSubcommandPublic::TransferToken { TokenProgramSubcommandPublic::TransferToken {
sender_addr: from, sender_account_id: from,
recipient_addr: to, recipient_account_id: to,
balance_to_move: amount, balance_to_move: amount,
}, },
) )
} }
(AddressPrivacyKind::Private, AddressPrivacyKind::Private) => { (AccountPrivacyKind::Private, AccountPrivacyKind::Private) => {
TokenProgramSubcommand::Private( TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::TransferTokenPrivateOwned { TokenProgramSubcommandPrivate::TransferTokenPrivateOwned {
sender_addr: from, sender_account_id: from,
recipient_addr: to, recipient_account_id: to,
balance_to_move: amount, balance_to_move: amount,
}, },
) )
} }
(AddressPrivacyKind::Private, AddressPrivacyKind::Public) => { (AccountPrivacyKind::Private, AccountPrivacyKind::Public) => {
TokenProgramSubcommand::Deshielded( TokenProgramSubcommand::Deshielded(
TokenProgramSubcommandDeshielded::TransferTokenDeshielded { TokenProgramSubcommandDeshielded::TransferTokenDeshielded {
sender_addr: from, sender_account_id: from,
recipient_addr: to, recipient_account_id: to,
balance_to_move: amount, balance_to_move: amount,
}, },
) )
} }
(AddressPrivacyKind::Public, AddressPrivacyKind::Private) => { (AccountPrivacyKind::Public, AccountPrivacyKind::Private) => {
TokenProgramSubcommand::Shielded( TokenProgramSubcommand::Shielded(
TokenProgramSubcommandShielded::TransferTokenShieldedOwned { TokenProgramSubcommandShielded::TransferTokenShieldedOwned {
sender_addr: from, sender_account_id: from,
recipient_addr: to, recipient_account_id: to,
balance_to_move: amount, balance_to_move: amount,
}, },
) )
@ -169,17 +172,17 @@ impl WalletSubcommand for TokenProgramAgnosticSubcommand {
let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?; let (from, from_privacy) = parse_addr_with_privacy_prefix(&from)?;
match from_privacy { match from_privacy {
AddressPrivacyKind::Private => TokenProgramSubcommand::Private( AccountPrivacyKind::Private => TokenProgramSubcommand::Private(
TokenProgramSubcommandPrivate::TransferTokenPrivateForeign { TokenProgramSubcommandPrivate::TransferTokenPrivateForeign {
sender_addr: from, sender_account_id: from,
recipient_npk: to_npk, recipient_npk: to_npk,
recipient_ipk: to_ipk, recipient_ipk: to_ipk,
balance_to_move: amount, balance_to_move: amount,
}, },
), ),
AddressPrivacyKind::Public => TokenProgramSubcommand::Shielded( AccountPrivacyKind::Public => TokenProgramSubcommand::Shielded(
TokenProgramSubcommandShielded::TransferTokenShieldedForeign { TokenProgramSubcommandShielded::TransferTokenShieldedForeign {
sender_addr: from, sender_account_id: from,
recipient_npk: to_npk, recipient_npk: to_npk,
recipient_ipk: to_ipk, recipient_ipk: to_ipk,
balance_to_move: amount, 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)] #[derive(Subcommand, Debug, Clone)]
pub enum TokenProgramSubcommand { pub enum TokenProgramSubcommand {
///Public execution /// Public execution
#[command(subcommand)] #[command(subcommand)]
Public(TokenProgramSubcommandPublic), Public(TokenProgramSubcommandPublic),
///Private execution /// Private execution
#[command(subcommand)] #[command(subcommand)]
Private(TokenProgramSubcommandPrivate), Private(TokenProgramSubcommandPrivate),
///Deshielded execution /// Deshielded execution
#[command(subcommand)] #[command(subcommand)]
Deshielded(TokenProgramSubcommandDeshielded), Deshielded(TokenProgramSubcommandDeshielded),
///Shielded execution /// Shielded execution
#[command(subcommand)] #[command(subcommand)]
Shielded(TokenProgramSubcommandShielded), 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)] #[derive(Subcommand, Debug, Clone)]
pub enum TokenProgramSubcommandPublic { pub enum TokenProgramSubcommandPublic {
//Create a new token using the token program // Create a new token using the token program
CreateNewToken { CreateNewToken {
#[arg(short, long)] #[arg(short, long)]
definition_addr: String, definition_account_id: String,
#[arg(short, long)] #[arg(short, long)]
supply_addr: String, supply_account_id: String,
#[arg(short, long)] #[arg(short, long)]
name: String, name: String,
#[arg(short, long)] #[arg(short, long)]
total_supply: u128, total_supply: u128,
}, },
//Transfer tokens using the token program // Transfer tokens using the token program
TransferToken { TransferToken {
#[arg(short, long)] #[arg(short, long)]
sender_addr: String, sender_account_id: String,
#[arg(short, long)] #[arg(short, long)]
recipient_addr: String, recipient_account_id: String,
#[arg(short, long)] #[arg(short, long)]
balance_to_move: u128, 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)] #[derive(Subcommand, Debug, Clone)]
pub enum TokenProgramSubcommandPrivate { pub enum TokenProgramSubcommandPrivate {
//Create a new token using the token program // Create a new token using the token program
CreateNewTokenPrivateOwned { CreateNewTokenPrivateOwned {
#[arg(short, long)] #[arg(short, long)]
definition_addr: String, definition_account_id: String,
#[arg(short, long)] #[arg(short, long)]
supply_addr: String, supply_account_id: String,
#[arg(short, long)] #[arg(short, long)]
name: String, name: String,
#[arg(short, long)] #[arg(short, long)]
total_supply: u128, total_supply: u128,
}, },
//Transfer tokens using the token program // Transfer tokens using the token program
TransferTokenPrivateOwned { TransferTokenPrivateOwned {
#[arg(short, long)] #[arg(short, long)]
sender_addr: String, sender_account_id: String,
#[arg(short, long)] #[arg(short, long)]
recipient_addr: String, recipient_account_id: String,
#[arg(short, long)] #[arg(short, long)]
balance_to_move: u128, balance_to_move: u128,
}, },
//Transfer tokens using the token program // Transfer tokens using the token program
TransferTokenPrivateForeign { TransferTokenPrivateForeign {
#[arg(short, long)] #[arg(short, long)]
sender_addr: String, sender_account_id: String,
///recipient_npk - valid 32 byte hex string /// recipient_npk - valid 32 byte hex string
#[arg(long)] #[arg(long)]
recipient_npk: String, recipient_npk: String,
///recipient_ipk - valid 33 byte hex string /// recipient_ipk - valid 33 byte hex string
#[arg(long)] #[arg(long)]
recipient_ipk: String, recipient_ipk: String,
#[arg(short, long)] #[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)] #[derive(Subcommand, Debug, Clone)]
pub enum TokenProgramSubcommandDeshielded { pub enum TokenProgramSubcommandDeshielded {
//Transfer tokens using the token program // Transfer tokens using the token program
TransferTokenDeshielded { TransferTokenDeshielded {
#[arg(short, long)] #[arg(short, long)]
sender_addr: String, sender_account_id: String,
#[arg(short, long)] #[arg(short, long)]
recipient_addr: String, recipient_account_id: String,
#[arg(short, long)] #[arg(short, long)]
balance_to_move: u128, 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)] #[derive(Subcommand, Debug, Clone)]
pub enum TokenProgramSubcommandShielded { pub enum TokenProgramSubcommandShielded {
//Transfer tokens using the token program // Transfer tokens using the token program
TransferTokenShieldedOwned { TransferTokenShieldedOwned {
#[arg(short, long)] #[arg(short, long)]
sender_addr: String, sender_account_id: String,
#[arg(short, long)] #[arg(short, long)]
recipient_addr: String, recipient_account_id: String,
#[arg(short, long)] #[arg(short, long)]
balance_to_move: u128, balance_to_move: u128,
}, },
//Transfer tokens using the token program // Transfer tokens using the token program
TransferTokenShieldedForeign { TransferTokenShieldedForeign {
#[arg(short, long)] #[arg(short, long)]
sender_addr: String, sender_account_id: String,
///recipient_npk - valid 32 byte hex string /// recipient_npk - valid 32 byte hex string
#[arg(long)] #[arg(long)]
recipient_npk: String, recipient_npk: String,
///recipient_ipk - valid 33 byte hex string /// recipient_ipk - valid 33 byte hex string
#[arg(long)] #[arg(long)]
recipient_ipk: String, recipient_ipk: String,
#[arg(short, long)] #[arg(short, long)]
@ -323,8 +326,8 @@ impl WalletSubcommand for TokenProgramSubcommandPublic {
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
match self { match self {
TokenProgramSubcommandPublic::CreateNewToken { TokenProgramSubcommandPublic::CreateNewToken {
definition_addr, definition_account_id,
supply_addr, supply_account_id,
name, name,
total_supply, total_supply,
} => { } => {
@ -337,8 +340,8 @@ impl WalletSubcommand for TokenProgramSubcommandPublic {
name_bytes[..name.len()].copy_from_slice(name); name_bytes[..name.len()].copy_from_slice(name);
wallet_core wallet_core
.send_new_token_definition( .send_new_token_definition(
definition_addr.parse().unwrap(), definition_account_id.parse().unwrap(),
supply_addr.parse().unwrap(), supply_account_id.parse().unwrap(),
name_bytes, name_bytes,
total_supply, total_supply,
) )
@ -346,14 +349,14 @@ impl WalletSubcommand for TokenProgramSubcommandPublic {
Ok(SubcommandReturnValue::Empty) Ok(SubcommandReturnValue::Empty)
} }
TokenProgramSubcommandPublic::TransferToken { TokenProgramSubcommandPublic::TransferToken {
sender_addr, sender_account_id,
recipient_addr, recipient_account_id,
balance_to_move, balance_to_move,
} => { } => {
wallet_core wallet_core
.send_transfer_token_transaction( .send_transfer_token_transaction(
sender_addr.parse().unwrap(), sender_account_id.parse().unwrap(),
recipient_addr.parse().unwrap(), recipient_account_id.parse().unwrap(),
balance_to_move, balance_to_move,
) )
.await?; .await?;
@ -370,8 +373,8 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
match self { match self {
TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned { TokenProgramSubcommandPrivate::CreateNewTokenPrivateOwned {
definition_addr, definition_account_id,
supply_addr, supply_account_id,
name, name,
total_supply, total_supply,
} => { } => {
@ -383,13 +386,13 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
let mut name_bytes = [0; 6]; let mut name_bytes = [0; 6];
name_bytes[..name.len()].copy_from_slice(name); name_bytes[..name.len()].copy_from_slice(name);
let definition_addr: Address = definition_addr.parse().unwrap(); let definition_account_id: AccountId = definition_account_id.parse().unwrap();
let supply_addr: Address = supply_addr.parse().unwrap(); let supply_account_id: AccountId = supply_account_id.parse().unwrap();
let (res, [secret_supply]) = wallet_core let (res, [secret_supply]) = wallet_core
.send_new_token_definition_private_owned( .send_new_token_definition_private_owned(
definition_addr, definition_account_id,
supply_addr, supply_account_id,
name_bytes, name_bytes,
total_supply, total_supply,
) )
@ -403,7 +406,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
.await?; .await?;
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { 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( wallet_core.decode_insert_privacy_preserving_transaction_results(
tx, tx,
@ -418,23 +421,23 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
} }
TokenProgramSubcommandPrivate::TransferTokenPrivateOwned { TokenProgramSubcommandPrivate::TransferTokenPrivateOwned {
sender_addr, sender_account_id,
recipient_addr, recipient_account_id,
balance_to_move, balance_to_move,
} => { } => {
let sender_addr: Address = sender_addr.parse().unwrap(); let sender_account_id: AccountId = sender_account_id.parse().unwrap();
let recipient_addr: Address = recipient_addr.parse().unwrap(); let recipient_account_id: AccountId = recipient_account_id.parse().unwrap();
let recipient_initialization = wallet_core let recipient_initialization = wallet_core
.check_private_account_initialized(&recipient_addr) .check_private_account_initialized(&recipient_account_id)
.await?; .await?;
let (res, [secret_sender, secret_recipient]) = let (res, [secret_sender, secret_recipient]) =
if let Some(recipient_proof) = recipient_initialization { if let Some(recipient_proof) = recipient_initialization {
wallet_core wallet_core
.send_transfer_token_transaction_private_owned_account_already_initialized( .send_transfer_token_transaction_private_owned_account_already_initialized(
sender_addr, sender_account_id,
recipient_addr, recipient_account_id,
balance_to_move, balance_to_move,
recipient_proof, recipient_proof,
) )
@ -442,8 +445,8 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
} else { } else {
wallet_core wallet_core
.send_transfer_token_transaction_private_owned_account_not_initialized( .send_transfer_token_transaction_private_owned_account_not_initialized(
sender_addr, sender_account_id,
recipient_addr, recipient_account_id,
balance_to_move, balance_to_move,
) )
.await? .await?
@ -458,8 +461,8 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx {
let acc_decode_data = vec![ let acc_decode_data = vec![
(secret_sender, sender_addr), (secret_sender, sender_account_id),
(secret_recipient, recipient_addr), (secret_recipient, recipient_account_id),
]; ];
wallet_core.decode_insert_privacy_preserving_transaction_results( wallet_core.decode_insert_privacy_preserving_transaction_results(
@ -475,12 +478,12 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
} }
TokenProgramSubcommandPrivate::TransferTokenPrivateForeign { TokenProgramSubcommandPrivate::TransferTokenPrivateForeign {
sender_addr, sender_account_id,
recipient_npk, recipient_npk,
recipient_ipk, recipient_ipk,
balance_to_move, 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 recipient_npk_res = hex::decode(recipient_npk)?;
let mut recipient_npk = [0; 32]; let mut recipient_npk = [0; 32];
recipient_npk.copy_from_slice(&recipient_npk_res); recipient_npk.copy_from_slice(&recipient_npk_res);
@ -495,7 +498,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
let (res, [secret_sender, _]) = wallet_core let (res, [secret_sender, _]) = wallet_core
.send_transfer_token_transaction_private_foreign_account( .send_transfer_token_transaction_private_foreign_account(
sender_addr, sender_account_id,
recipient_npk, recipient_npk,
recipient_ipk, recipient_ipk,
balance_to_move, balance_to_move,
@ -510,7 +513,7 @@ impl WalletSubcommand for TokenProgramSubcommandPrivate {
.await?; .await?;
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { 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( wallet_core.decode_insert_privacy_preserving_transaction_results(
tx, tx,
@ -535,17 +538,17 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded {
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
match self { match self {
TokenProgramSubcommandDeshielded::TransferTokenDeshielded { TokenProgramSubcommandDeshielded::TransferTokenDeshielded {
sender_addr, sender_account_id,
recipient_addr, recipient_account_id,
balance_to_move, balance_to_move,
} => { } => {
let sender_addr: Address = sender_addr.parse().unwrap(); let sender_account_id: AccountId = sender_account_id.parse().unwrap();
let recipient_addr: Address = recipient_addr.parse().unwrap(); let recipient_account_id: AccountId = recipient_account_id.parse().unwrap();
let (res, [secret_sender]) = wallet_core let (res, [secret_sender]) = wallet_core
.send_transfer_token_transaction_deshielded( .send_transfer_token_transaction_deshielded(
sender_addr, sender_account_id,
recipient_addr, recipient_account_id,
balance_to_move, balance_to_move,
) )
.await?; .await?;
@ -558,7 +561,7 @@ impl WalletSubcommand for TokenProgramSubcommandDeshielded {
.await?; .await?;
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { 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( wallet_core.decode_insert_privacy_preserving_transaction_results(
tx, tx,
@ -583,12 +586,12 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
) -> Result<SubcommandReturnValue> { ) -> Result<SubcommandReturnValue> {
match self { match self {
TokenProgramSubcommandShielded::TransferTokenShieldedForeign { TokenProgramSubcommandShielded::TransferTokenShieldedForeign {
sender_addr, sender_account_id,
recipient_npk, recipient_npk,
recipient_ipk, recipient_ipk,
balance_to_move, 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 recipient_npk_res = hex::decode(recipient_npk)?;
let mut recipient_npk = [0; 32]; let mut recipient_npk = [0; 32];
recipient_npk.copy_from_slice(&recipient_npk_res); recipient_npk.copy_from_slice(&recipient_npk_res);
@ -603,7 +606,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
let res = wallet_core let res = wallet_core
.send_transfer_token_transaction_shielded_foreign_account( .send_transfer_token_transaction_shielded_foreign_account(
sender_addr, sender_account_id,
recipient_npk, recipient_npk,
recipient_ipk, recipient_ipk,
balance_to_move, balance_to_move,
@ -628,23 +631,23 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash }) Ok(SubcommandReturnValue::PrivacyPreservingTransfer { tx_hash })
} }
TokenProgramSubcommandShielded::TransferTokenShieldedOwned { TokenProgramSubcommandShielded::TransferTokenShieldedOwned {
sender_addr, sender_account_id,
recipient_addr, recipient_account_id,
balance_to_move, balance_to_move,
} => { } => {
let sender_addr: Address = sender_addr.parse().unwrap(); let sender_account_id: AccountId = sender_account_id.parse().unwrap();
let recipient_addr: Address = recipient_addr.parse().unwrap(); let recipient_account_id: AccountId = recipient_account_id.parse().unwrap();
let recipient_initialization = wallet_core let recipient_initialization = wallet_core
.check_private_account_initialized(&recipient_addr) .check_private_account_initialized(&recipient_account_id)
.await?; .await?;
let (res, [secret_recipient]) = let (res, [secret_recipient]) =
if let Some(recipient_proof) = recipient_initialization { if let Some(recipient_proof) = recipient_initialization {
wallet_core wallet_core
.send_transfer_token_transaction_shielded_owned_account_already_initialized( .send_transfer_token_transaction_shielded_owned_account_already_initialized(
sender_addr, sender_account_id,
recipient_addr, recipient_account_id,
balance_to_move, balance_to_move,
recipient_proof, recipient_proof,
) )
@ -652,8 +655,8 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
} else { } else {
wallet_core wallet_core
.send_transfer_token_transaction_shielded_owned_account_not_initialized( .send_transfer_token_transaction_shielded_owned_account_not_initialized(
sender_addr, sender_account_id,
recipient_addr, recipient_account_id,
balance_to_move, balance_to_move,
) )
.await? .await?
@ -667,7 +670,7 @@ impl WalletSubcommand for TokenProgramSubcommandShielded {
.await?; .await?;
if let NSSATransaction::PrivacyPreserving(tx) = transfer_tx { 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( wallet_core.decode_insert_privacy_preserving_transaction_results(
tx, tx,

View File

@ -8,33 +8,34 @@ use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InitialAccountDataPublic { pub struct InitialAccountDataPublic {
pub address: String, pub account_id: String,
pub pub_sign_key: nssa::PrivateKey, pub pub_sign_key: nssa::PrivateKey,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PersistentAccountDataPublic { pub struct PersistentAccountDataPublic {
pub address: nssa::Address, pub account_id: nssa::AccountId,
pub chain_index: ChainIndex, pub chain_index: ChainIndex,
pub data: ChildKeysPublic, pub data: ChildKeysPublic,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InitialAccountDataPrivate { pub struct InitialAccountDataPrivate {
pub address: String, pub account_id: String,
pub account: nssa_core::account::Account, pub account: nssa_core::account::Account,
pub key_chain: KeyChain, pub key_chain: KeyChain,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PersistentAccountDataPrivate { pub struct PersistentAccountDataPrivate {
pub address: nssa::Address, pub account_id: nssa::AccountId,
pub chain_index: ChainIndex, pub chain_index: ChainIndex,
pub data: ChildKeysPrivate, pub data: ChildKeysPrivate,
} }
//Big difference in enum variants sizes // Big difference in enum variants sizes
//however it is improbable, that we will have that much accounts, that it will substantialy affect memory // however it is improbable, that we will have that much accounts, that it will substantialy affect
// memory
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum InitialAccountData { pub enum InitialAccountData {
@ -42,8 +43,9 @@ pub enum InitialAccountData {
Private(InitialAccountDataPrivate), Private(InitialAccountDataPrivate),
} }
//Big difference in enum variants sizes // Big difference in enum variants sizes
//however it is improbable, that we will have that much accounts, that it will substantialy affect memory // however it is improbable, that we will have that much accounts, that it will substantialy affect
// memory
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum PersistentAccountData { pub enum PersistentAccountData {
@ -59,20 +61,20 @@ pub struct PersistentStorage {
} }
impl InitialAccountData { impl InitialAccountData {
pub fn address(&self) -> nssa::Address { pub fn account_id(&self) -> nssa::AccountId {
match &self { match &self {
Self::Public(acc) => acc.address.parse().unwrap(), Self::Public(acc) => acc.account_id.parse().unwrap(),
Self::Private(acc) => acc.address.parse().unwrap(), Self::Private(acc) => acc.account_id.parse().unwrap(),
} }
} }
} }
impl PersistentAccountData { impl PersistentAccountData {
pub fn address(&self) -> nssa::Address { pub fn account_id(&self) -> nssa::AccountId {
match &self { match &self {
Self::Public(acc) => acc.address, Self::Public(acc) => acc.account_id,
Self::Private(acc) => acc.address, Self::Private(acc) => acc.account_id,
Self::Preconfigured(acc) => acc.address(), Self::Preconfigured(acc) => acc.account_id(),
} }
} }
} }
@ -127,19 +129,19 @@ pub struct GasConfig {
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WalletConfig { pub struct WalletConfig {
///Override rust log (env var logging level) /// Override rust log (env var logging level)
pub override_rust_log: Option<String>, pub override_rust_log: Option<String>,
///Sequencer URL /// Sequencer URL
pub sequencer_addr: String, 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, pub seq_poll_timeout_millis: u64,
///Sequencer polling max number of blocks /// Sequencer polling max number of blocks
pub seq_poll_max_blocks: usize, pub seq_poll_max_blocks: usize,
///Sequencer polling max number error retries /// Sequencer polling max number error retries
pub seq_poll_max_retries: u64, 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, pub seq_poll_retry_delay_millis: u64,
///Initial accounts for wallet /// Initial accounts for wallet
pub initial_accounts: Vec<InitialAccountData>, pub initial_accounts: Vec<InitialAccountData>,
} }
@ -157,7 +159,7 @@ impl Default for WalletConfig {
[ [
{ {
"Public": { "Public": {
"address": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy", "account_id": "BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy",
"pub_sign_key": [ "pub_sign_key": [
16, 16,
162, 162,
@ -196,7 +198,7 @@ impl Default for WalletConfig {
}, },
{ {
"Public": { "Public": {
"address": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw", "account_id": "Gj1mJy5W7J5pfmLRujmQaLfLMWidNxQ6uwnhb666ZwHw",
"pub_sign_key": [ "pub_sign_key": [
113, 113,
121, 121,
@ -235,7 +237,7 @@ impl Default for WalletConfig {
}, },
{ {
"Private": { "Private": {
"address": "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw", "account_id": "3oCG8gqdKLMegw4rRfyaMQvuPHpcASt7xwttsmnZLSkw",
"account": { "account": {
"program_owner": [ "program_owner": [
0, 0,
@ -464,7 +466,7 @@ impl Default for WalletConfig {
}, },
{ {
"Private": { "Private": {
"address": "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX", "account_id": "AKTcXgJ1xoynta1Ec7y6Jso1z1JQtHqd7aPQ1h9er6xX",
"account": { "account": {
"program_owner": [ "program_owner": [
0, 0,

View File

@ -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 std::{path::PathBuf, str::FromStr};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use anyhow::Result; use anyhow::Result;
use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
use key_protocol::key_protocol_core::NSSAUserData; use key_protocol::key_protocol_core::NSSAUserData;
use nssa::Account; use nssa::Account;
use nssa_core::account::Nonce;
use rand::{RngCore, rngs::OsRng};
use serde::Serialize; use serde::Serialize;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use crate::{ use crate::{
HOME_DIR_ENV_VAR, HOME_DIR_ENV_VAR,
@ -120,11 +120,11 @@ pub fn produce_data_for_storage(
) -> PersistentStorage { ) -> PersistentStorage {
let mut vec_for_storage = vec![]; 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) { if let Some(data) = user_data.public_key_tree.key_map.get(key) {
vec_for_storage.push( vec_for_storage.push(
PersistentAccountDataPublic { PersistentAccountDataPublic {
address: *addr, account_id: *account_id,
chain_index: key.clone(), chain_index: key.clone(),
data: data.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) { if let Some(data) = user_data.private_key_tree.key_map.get(key) {
vec_for_storage.push( vec_for_storage.push(
PersistentAccountDataPrivate { PersistentAccountDataPrivate {
address: *addr, account_id: *account_id,
chain_index: key.clone(), chain_index: key.clone(),
data: data.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( vec_for_storage.push(
InitialAccountData::Public(InitialAccountDataPublic { InitialAccountData::Public(InitialAccountDataPublic {
address: addr.to_string(), account_id: account_id.to_string(),
pub_sign_key: key.clone(), pub_sign_key: key.clone(),
}) })
.into(), .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( vec_for_storage.push(
InitialAccountData::Private(InitialAccountDataPrivate { InitialAccountData::Private(InitialAccountDataPrivate {
address: addr.to_string(), account_id: account_id.to_string(),
account: account.clone(), account: account.clone(),
key_chain: key_chain.clone(), key_chain: key_chain.clone(),
}) })
@ -180,23 +180,23 @@ pub(crate) fn produce_random_nonces(size: usize) -> Vec<Nonce> {
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AddressPrivacyKind { pub enum AccountPrivacyKind {
Public, Public,
Private, Private,
} }
pub(crate) fn parse_addr_with_privacy_prefix( pub(crate) fn parse_addr_with_privacy_prefix(
addr_base58: &str, account_base58: &str,
) -> Result<(String, AddressPrivacyKind)> { ) -> Result<(String, AccountPrivacyKind)> {
if addr_base58.starts_with("Public/") { if account_base58.starts_with("Public/") {
Ok(( Ok((
addr_base58.strip_prefix("Public/").unwrap().to_string(), account_base58.strip_prefix("Public/").unwrap().to_string(),
AddressPrivacyKind::Public, AccountPrivacyKind::Public,
)) ))
} else if addr_base58.starts_with("Private/") { } else if account_base58.starts_with("Private/") {
Ok(( Ok((
addr_base58.strip_prefix("Private/").unwrap().to_string(), account_base58.strip_prefix("Private/").unwrap().to_string(),
AddressPrivacyKind::Private, AccountPrivacyKind::Private,
)) ))
} else { } else {
anyhow::bail!("Unsupported privacy kind, available variants is Public/ and Private/"); anyhow::bail!("Unsupported privacy kind, available variants is Public/ and Private/");
@ -249,12 +249,12 @@ mod tests {
let addr_base58 = "Public/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy"; let addr_base58 = "Public/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy";
let (_, addr_kind) = parse_addr_with_privacy_prefix(addr_base58).unwrap(); 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_base58 = "Private/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy";
let (_, addr_kind) = parse_addr_with_privacy_prefix(addr_base58).unwrap(); 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"; let addr_base58 = "asdsada/BLgCRDXYdQPMMWVHYRFGQZbgeHx9frkipa8GtpG2Syqy";
assert!(parse_addr_with_privacy_prefix(addr_base58).is_err()); assert!(parse_addr_with_privacy_prefix(addr_base58).is_err());

View File

@ -1,23 +1,21 @@
use std::{path::PathBuf, sync::Arc}; use std::{path::PathBuf, sync::Arc};
use anyhow::Result;
use base64::{Engine, engine::general_purpose::STANDARD as BASE64}; use base64::{Engine, engine::general_purpose::STANDARD as BASE64};
use chain_storage::WalletChainStore;
use clap::{Parser, Subcommand};
use common::{ use common::{
block::HashableBlockData, block::HashableBlockData,
sequencer_client::SequencerClient, sequencer_client::SequencerClient,
transaction::{EncodedTransaction, NSSATransaction}, transaction::{EncodedTransaction, NSSATransaction},
}; };
use anyhow::Result;
use chain_storage::WalletChainStore;
use config::WalletConfig; use config::WalletConfig;
use key_protocol::key_management::key_tree::{chain_index::ChainIndex, traits::KeyNode}; use key_protocol::key_management::key_tree::{chain_index::ChainIndex, traits::KeyNode};
use log::info; use log::info;
use nssa::{ use nssa::{
Account, Address, privacy_preserving_transaction::message::EncryptedAccountData, Account, AccountId, privacy_preserving_transaction::message::EncryptedAccountData,
program::Program, program::Program,
}; };
use clap::{Parser, Subcommand};
use nssa_core::{Commitment, MembershipProof}; use nssa_core::{Commitment, MembershipProof};
use tokio::io::AsyncWriteExt; use tokio::io::AsyncWriteExt;
@ -29,10 +27,7 @@ use crate::{
token_program::TokenProgramAgnosticSubcommand, token_program::TokenProgramAgnosticSubcommand,
}, },
config::PersistentStorage, config::PersistentStorage,
helperfunctions::fetch_persistent_storage, helperfunctions::{fetch_config, fetch_persistent_storage, get_home, produce_data_for_storage},
};
use crate::{
helperfunctions::{fetch_config, get_home, produce_data_for_storage},
poller::TxPoller, 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<PathBuf> { pub async fn store_persistent_data(&self) -> Result<PathBuf> {
let home = get_home()?; let home = get_home()?;
let storage_path = home.join("storage.json"); let storage_path = home.join("storage.json");
@ -108,7 +103,7 @@ impl WalletCore {
Ok(storage_path) Ok(storage_path)
} }
///Store persistent data at home /// Store persistent data at home
pub async fn store_config_changes(&self) -> Result<PathBuf> { pub async fn store_config_changes(&self) -> Result<PathBuf> {
let home = get_home()?; let home = get_home()?;
let config_path = home.join("wallet_config.json"); let config_path = home.join("wallet_config.json");
@ -122,20 +117,20 @@ impl WalletCore {
Ok(config_path) 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 self.storage
.user_data .user_data
.generate_new_public_transaction_private_key(chain_index) .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 self.storage
.user_data .user_data
.generate_new_privacy_preserving_transaction_key_chain(chain_index) .generate_new_privacy_preserving_transaction_key_chain(chain_index)
} }
///Get account balance /// Get account balance
pub async fn get_account_balance(&self, acc: Address) -> Result<u128> { pub async fn get_account_balance(&self, acc: AccountId) -> Result<u128> {
Ok(self Ok(self
.sequencer_client .sequencer_client
.get_account_balance(acc.to_string()) .get_account_balance(acc.to_string())
@ -143,8 +138,8 @@ impl WalletCore {
.balance) .balance)
} }
///Get accounts nonces /// Get accounts nonces
pub async fn get_accounts_nonces(&self, accs: Vec<Address>) -> Result<Vec<u128>> { pub async fn get_accounts_nonces(&self, accs: Vec<AccountId>) -> Result<Vec<u128>> {
Ok(self Ok(self
.sequencer_client .sequencer_client
.get_accounts_nonces(accs.into_iter().map(|acc| acc.to_string()).collect()) .get_accounts_nonces(accs.into_iter().map(|acc| acc.to_string()).collect())
@ -152,25 +147,28 @@ impl WalletCore {
.nonces) .nonces)
} }
///Get account /// Get account
pub async fn get_account_public(&self, addr: Address) -> Result<Account> { pub async fn get_account_public(&self, account_id: AccountId) -> Result<Account> {
let response = self.sequencer_client.get_account(addr.to_string()).await?; let response = self
.sequencer_client
.get_account(account_id.to_string())
.await?;
Ok(response.account) Ok(response.account)
} }
pub fn get_account_private(&self, addr: &Address) -> Option<Account> { pub fn get_account_private(&self, account_id: &AccountId) -> Option<Account> {
self.storage self.storage
.user_data .user_data
.get_private_account(addr) .get_private_account(account_id)
.map(|value| value.1.clone()) .map(|value| value.1.clone())
} }
pub fn get_private_account_commitment(&self, addr: &Address) -> Option<Commitment> { pub fn get_private_account_commitment(&self, account_id: &AccountId) -> Option<Commitment> {
let (keys, account) = self.storage.user_data.get_private_account(addr)?; let (keys, account) = self.storage.user_data.get_private_account(account_id)?;
Some(Commitment::new(&keys.nullifer_public_key, account)) Some(Commitment::new(&keys.nullifer_public_key, account))
} }
///Poll transactions /// Poll transactions
pub async fn poll_native_token_transfer(&self, hash: String) -> Result<NSSATransaction> { pub async fn poll_native_token_transfer(&self, hash: String) -> Result<NSSATransaction> {
let transaction_encoded = self.poller.poll_tx(hash).await?; let transaction_encoded = self.poller.poll_tx(hash).await?;
let tx_base64_decode = BASE64.decode(transaction_encoded)?; let tx_base64_decode = BASE64.decode(transaction_encoded)?;
@ -181,9 +179,9 @@ impl WalletCore {
pub async fn check_private_account_initialized( pub async fn check_private_account_initialized(
&self, &self,
addr: &Address, account_id: &AccountId,
) -> Result<Option<MembershipProof>> { ) -> Result<Option<MembershipProof>> {
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 self.sequencer_client
.get_proof_for_commitment(acc_comm) .get_proof_for_commitment(acc_comm)
.await .await
@ -196,9 +194,9 @@ impl WalletCore {
pub fn decode_insert_privacy_preserving_transaction_results( pub fn decode_insert_privacy_preserving_transaction_results(
&mut self, &mut self,
tx: nssa::privacy_preserving_transaction::PrivacyPreservingTransaction, tx: nssa::privacy_preserving_transaction::PrivacyPreservingTransaction,
acc_decode_data: &[(nssa_core::SharedSecretKey, Address)], acc_decode_data: &[(nssa_core::SharedSecretKey, AccountId)],
) -> Result<()> { ) -> 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_ead = tx.message.encrypted_private_post_states[output_index].clone();
let acc_comm = tx.message.new_commitments[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:#?}"); println!("Received new acc {res_acc:#?}");
self.storage 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); 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)] #[derive(Subcommand, Debug, Clone)]
#[clap(about)] #[clap(about)]
pub enum Command { pub enum Command {
///Authenticated transfer subcommand /// Authenticated transfer subcommand
#[command(subcommand)] #[command(subcommand)]
AuthTransfer(AuthTransferSubcommand), AuthTransfer(AuthTransferSubcommand),
///Generic chain info subcommand /// Generic chain info subcommand
#[command(subcommand)] #[command(subcommand)]
ChainInfo(ChainSubcommand), ChainInfo(ChainSubcommand),
///Account view and sync subcommand /// Account view and sync subcommand
#[command(subcommand)] #[command(subcommand)]
Account(AccountSubcommand), Account(AccountSubcommand),
///Pinata program interaction subcommand /// Pinata program interaction subcommand
#[command(subcommand)] #[command(subcommand)]
Pinata(PinataProgramAgnosticSubcommand), Pinata(PinataProgramAgnosticSubcommand),
///Token program interaction subcommand /// Token program interaction subcommand
#[command(subcommand)] #[command(subcommand)]
Token(TokenProgramAgnosticSubcommand), Token(TokenProgramAgnosticSubcommand),
/// Check the wallet can connect to the node and builtin local programs /// Check the wallet can connect to the node and builtin local programs
@ -263,11 +261,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 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` /// where valid options for `privacy_prefix` is `Public` and `Private`
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[clap(version, about)] #[clap(version, about)]
@ -283,7 +281,7 @@ pub struct Args {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum SubcommandReturnValue { pub enum SubcommandReturnValue {
PrivacyPreservingTransfer { tx_hash: String }, PrivacyPreservingTransfer { tx_hash: String },
RegisterAccount { addr: nssa::Address }, RegisterAccount { account_id: nssa::AccountId },
Account(nssa::Account), Account(nssa::Account),
Empty, Empty,
SyncedToBlock(u64), SyncedToBlock(u64),
@ -371,7 +369,7 @@ pub async fn parse_block_range(
if let NSSATransaction::PrivacyPreserving(tx) = nssa_tx { if let NSSATransaction::PrivacyPreserving(tx) = nssa_tx {
let mut affected_accounts = vec![]; let mut affected_accounts = vec![];
for (acc_addr, (key_chain, _)) in for (acc_account_id, (key_chain, _)) in
&wallet_core.storage.user_data.default_user_private_accounts &wallet_core.storage.user_data.default_user_private_accounts
{ {
let view_tag = EncryptedAccountData::compute_view_tag( let view_tag = EncryptedAccountData::compute_view_tag(
@ -400,10 +398,10 @@ pub async fn parse_block_range(
if let Some(res_acc) = res_acc { if let Some(res_acc) = res_acc {
println!( 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));
} }
} }
} }
@ -416,7 +414,7 @@ pub async fn parse_block_range(
.key_map .key_map
.values() .values()
{ {
let acc_addr = keys_node.address(); let acc_account_id = keys_node.account_id();
let key_chain = &keys_node.value.0; let key_chain = &keys_node.value.0;
let view_tag = EncryptedAccountData::compute_view_tag( let view_tag = EncryptedAccountData::compute_view_tag(
@ -445,19 +443,19 @@ pub async fn parse_block_range(
if let Some(res_acc) = res_acc { if let Some(res_acc) = res_acc {
println!( 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 wallet_core
.storage .storage
.insert_private_account_data(affected_addr, new_acc); .insert_private_account_data(affected_account_id, new_acc);
} }
} }
} }

View File

@ -5,6 +5,10 @@ use wallet::{Args, OverCommand, execute_continious_run, execute_setup, execute_s
pub const NUM_THREADS: usize = 2; 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<()> { fn main() -> Result<()> {
let runtime = Builder::new_multi_thread() let runtime = Builder::new_multi_thread()
.worker_threads(NUM_THREADS) .worker_threads(NUM_THREADS)

View File

@ -1,6 +1,6 @@
use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse}; use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse};
use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; 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 nssa_core::{MembershipProof, SharedSecretKey, account::AccountWithMetadata};
use crate::{ use crate::{
@ -10,14 +10,14 @@ use crate::{
impl WalletCore { impl WalletCore {
pub async fn claim_pinata( pub async fn claim_pinata(
&self, &self,
pinata_addr: Address, pinata_account_id: AccountId,
winner_addr: Address, winner_account_id: AccountId,
solution: u128, solution: u128,
) -> Result<SendTxResponse, ExecutionFailureKind> { ) -> Result<SendTxResponse, ExecutionFailureKind> {
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 program_id = nssa::program::Program::pinata().id();
let message = 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(); .unwrap();
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]); 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( pub async fn claim_pinata_private_owned_account_already_initialized(
&self, &self,
pinata_addr: Address, pinata_account_id: AccountId,
winner_addr: Address, winner_account_id: AccountId,
solution: u128, solution: u128,
winner_proof: MembershipProof, winner_proof: MembershipProof,
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
@ -40,14 +40,14 @@ impl WalletCore {
auth_acc: winner_pre, auth_acc: winner_pre,
proof: _, proof: _,
} = self } = self
.private_acc_preparation(winner_addr, true, false) .private_acc_preparation(winner_account_id, true, false)
.await?; .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 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 eph_holder_winner = EphemeralKeyHolder::new(&winner_npk);
let shared_secret_winner = eph_holder_winner.calculate_shared_secret_sender(&winner_ipk); let shared_secret_winner = eph_holder_winner.calculate_shared_secret_sender(&winner_ipk);
@ -65,7 +65,7 @@ impl WalletCore {
let message = let message =
nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output(
vec![pinata_addr], vec![pinata_account_id],
vec![], vec![],
vec![( vec![(
winner_npk.clone(), winner_npk.clone(),
@ -95,8 +95,8 @@ impl WalletCore {
pub async fn claim_pinata_private_owned_account_not_initialized( pub async fn claim_pinata_private_owned_account_not_initialized(
&self, &self,
pinata_addr: Address, pinata_account_id: AccountId,
winner_addr: Address, winner_account_id: AccountId,
solution: u128, solution: u128,
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
let AccountPreparedData { let AccountPreparedData {
@ -106,14 +106,14 @@ impl WalletCore {
auth_acc: winner_pre, auth_acc: winner_pre,
proof: _, proof: _,
} = self } = self
.private_acc_preparation(winner_addr, false, false) .private_acc_preparation(winner_account_id, false, false)
.await?; .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 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 eph_holder_winner = EphemeralKeyHolder::new(&winner_npk);
let shared_secret_winner = eph_holder_winner.calculate_shared_secret_sender(&winner_ipk); let shared_secret_winner = eph_holder_winner.calculate_shared_secret_sender(&winner_ipk);
@ -131,7 +131,7 @@ impl WalletCore {
let message = let message =
nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output( nssa::privacy_preserving_transaction::message::Message::try_from_circuit_output(
vec![pinata_addr], vec![pinata_account_id],
vec![], vec![],
vec![( vec![(
winner_npk.clone(), winner_npk.clone(),

View File

@ -7,10 +7,11 @@ use log::{info, warn};
use crate::config::WalletConfig; use crate::config::WalletConfig;
#[derive(Clone)] #[derive(Clone)]
///Helperstruct to poll transactions /// Helperstruct to poll transactions
pub struct TxPoller { pub struct TxPoller {
pub polling_max_blocks_to_query: usize, pub polling_max_blocks_to_query: usize,
pub polling_max_error_attempts: u64, pub polling_max_error_attempts: u64,
// TODO: This should be Duration
pub polling_error_delay_millis: u64, pub polling_error_delay_millis: u64,
pub polling_delay_millis: u64, pub polling_delay_millis: u64,
pub client: Arc<SequencerClient>, pub client: Arc<SequencerClient>,

View File

@ -1,5 +1,5 @@
use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse}; use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse};
use nssa::{Account, Address, program::Program}; use nssa::{Account, AccountId, program::Program};
use nssa_core::{ use nssa_core::{
MembershipProof, NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey, MembershipProof, NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey,
program::InstructionData, program::InstructionData,
@ -15,7 +15,8 @@ impl WalletCore {
Program, Program,
impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, 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]; let mut instruction = [0; 23];
instruction[0] = 0x01; instruction[0] = 0x01;
instruction[1..17].copy_from_slice(&amount.to_le_bytes()); instruction[1..17].copy_from_slice(&amount.to_le_bytes());
@ -47,20 +48,24 @@ impl WalletCore {
pub async fn send_new_token_definition( pub async fn send_new_token_definition(
&self, &self,
definition_address: Address, definition_account_id: AccountId,
supply_address: Address, supply_account_id: AccountId,
name: [u8; 6], name: [u8; 6],
total_supply: u128, total_supply: u128,
) -> Result<SendTxResponse, ExecutionFailureKind> { ) -> Result<SendTxResponse, ExecutionFailureKind> {
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(); let program_id = nssa::program::Program::token().id();
// Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)] // Instruction must be: [0x00 || total_supply (little-endian 16 bytes) || name (6 bytes)]
let mut instruction = [0; 23]; let mut instruction = [0; 23];
instruction[1..17].copy_from_slice(&total_supply.to_le_bytes()); instruction[1..17].copy_from_slice(&total_supply.to_le_bytes());
instruction[17..].copy_from_slice(&name); instruction[17..].copy_from_slice(&name);
let message = let message = nssa::public_transaction::Message::try_new(
nssa::public_transaction::Message::try_new(program_id, addresses, vec![], instruction) program_id,
.unwrap(); account_ids,
vec![],
instruction,
)
.unwrap();
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]); 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( pub async fn send_new_token_definition_private_owned(
&self, &self,
definition_addr: Address, definition_account_id: AccountId,
supply_addr: Address, supply_account_id: AccountId,
name: [u8; 6], name: [u8; 6],
total_supply: u128, total_supply: u128,
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
@ -82,8 +87,8 @@ impl WalletCore {
// Kind of non-obvious naming // Kind of non-obvious naming
// Basically this funtion is called because authentication mask is [0, 2] // Basically this funtion is called because authentication mask is [0, 2]
self.shielded_two_accs_receiver_uninit( self.shielded_two_accs_receiver_uninit(
definition_addr, definition_account_id,
supply_addr, supply_account_id,
instruction_data, instruction_data,
tx_pre_check, tx_pre_check,
program, program,
@ -93,27 +98,32 @@ impl WalletCore {
pub async fn send_transfer_token_transaction( pub async fn send_transfer_token_transaction(
&self, &self,
sender_address: Address, sender_account_id: AccountId,
recipient_address: Address, recipient_account_id: AccountId,
amount: u128, amount: u128,
) -> Result<SendTxResponse, ExecutionFailureKind> { ) -> Result<SendTxResponse, ExecutionFailureKind> {
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(); 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]; let mut instruction = [0; 23];
instruction[0] = 0x01; instruction[0] = 0x01;
instruction[1..17].copy_from_slice(&amount.to_le_bytes()); 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); return Err(ExecutionFailureKind::SequencerError);
}; };
let message = let message = nssa::public_transaction::Message::try_new(
nssa::public_transaction::Message::try_new(program_id, addresses, nonces, instruction) program_id,
.unwrap(); account_ids,
nonces,
instruction,
)
.unwrap();
let Some(signing_key) = self let Some(signing_key) = self
.storage .storage
.user_data .user_data
.get_pub_account_signing_key(&sender_address) .get_pub_account_signing_key(&sender_account_id)
else { else {
return Err(ExecutionFailureKind::KeyNotFoundError); return Err(ExecutionFailureKind::KeyNotFoundError);
}; };
@ -127,8 +137,8 @@ impl WalletCore {
pub async fn send_transfer_token_transaction_private_owned_account_already_initialized( pub async fn send_transfer_token_transaction_private_owned_account_already_initialized(
&self, &self,
sender_address: Address, sender_account_id: AccountId,
recipient_address: Address, recipient_account_id: AccountId,
amount: u128, amount: u128,
recipient_proof: MembershipProof, recipient_proof: MembershipProof,
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
@ -136,8 +146,8 @@ impl WalletCore {
WalletCore::token_program_preparation_transfer(amount); WalletCore::token_program_preparation_transfer(amount);
self.private_tx_two_accs_all_init( self.private_tx_two_accs_all_init(
sender_address, sender_account_id,
recipient_address, recipient_account_id,
instruction_data, instruction_data,
tx_pre_check, tx_pre_check,
program, program,
@ -148,16 +158,16 @@ impl WalletCore {
pub async fn send_transfer_token_transaction_private_owned_account_not_initialized( pub async fn send_transfer_token_transaction_private_owned_account_not_initialized(
&self, &self,
sender_address: Address, sender_account_id: AccountId,
recipient_address: Address, recipient_account_id: AccountId,
amount: u128, amount: u128,
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
let (instruction_data, program, tx_pre_check) = let (instruction_data, program, tx_pre_check) =
WalletCore::token_program_preparation_transfer(amount); WalletCore::token_program_preparation_transfer(amount);
self.private_tx_two_accs_receiver_uninit( self.private_tx_two_accs_receiver_uninit(
sender_address, sender_account_id,
recipient_address, recipient_account_id,
instruction_data, instruction_data,
tx_pre_check, tx_pre_check,
program, program,
@ -167,7 +177,7 @@ impl WalletCore {
pub async fn send_transfer_token_transaction_private_foreign_account( pub async fn send_transfer_token_transaction_private_foreign_account(
&self, &self,
sender_address: Address, sender_account_id: AccountId,
recipient_npk: NullifierPublicKey, recipient_npk: NullifierPublicKey,
recipient_ipk: IncomingViewingPublicKey, recipient_ipk: IncomingViewingPublicKey,
amount: u128, amount: u128,
@ -176,7 +186,7 @@ impl WalletCore {
WalletCore::token_program_preparation_transfer(amount); WalletCore::token_program_preparation_transfer(amount);
self.private_tx_two_accs_receiver_outer( self.private_tx_two_accs_receiver_outer(
sender_address, sender_account_id,
recipient_npk, recipient_npk,
recipient_ipk, recipient_ipk,
instruction_data, instruction_data,
@ -188,16 +198,16 @@ impl WalletCore {
pub async fn send_transfer_token_transaction_deshielded( pub async fn send_transfer_token_transaction_deshielded(
&self, &self,
sender_address: Address, sender_account_id: AccountId,
recipient_address: Address, recipient_account_id: AccountId,
amount: u128, amount: u128,
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
let (instruction_data, program, tx_pre_check) = let (instruction_data, program, tx_pre_check) =
WalletCore::token_program_preparation_transfer(amount); WalletCore::token_program_preparation_transfer(amount);
self.deshielded_tx_two_accs( self.deshielded_tx_two_accs(
sender_address, sender_account_id,
recipient_address, recipient_account_id,
instruction_data, instruction_data,
tx_pre_check, tx_pre_check,
program, program,
@ -207,8 +217,8 @@ impl WalletCore {
pub async fn send_transfer_token_transaction_shielded_owned_account_already_initialized( pub async fn send_transfer_token_transaction_shielded_owned_account_already_initialized(
&self, &self,
sender_address: Address, sender_account_id: AccountId,
recipient_address: Address, recipient_account_id: AccountId,
amount: u128, amount: u128,
recipient_proof: MembershipProof, recipient_proof: MembershipProof,
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
@ -216,8 +226,8 @@ impl WalletCore {
WalletCore::token_program_preparation_transfer(amount); WalletCore::token_program_preparation_transfer(amount);
self.shielded_two_accs_all_init( self.shielded_two_accs_all_init(
sender_address, sender_account_id,
recipient_address, recipient_account_id,
instruction_data, instruction_data,
tx_pre_check, tx_pre_check,
program, program,
@ -228,16 +238,16 @@ impl WalletCore {
pub async fn send_transfer_token_transaction_shielded_owned_account_not_initialized( pub async fn send_transfer_token_transaction_shielded_owned_account_not_initialized(
&self, &self,
sender_address: Address, sender_account_id: AccountId,
recipient_address: Address, recipient_account_id: AccountId,
amount: u128, amount: u128,
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
let (instruction_data, program, tx_pre_check) = let (instruction_data, program, tx_pre_check) =
WalletCore::token_program_preparation_transfer(amount); WalletCore::token_program_preparation_transfer(amount);
self.shielded_two_accs_receiver_uninit( self.shielded_two_accs_receiver_uninit(
sender_address, sender_account_id,
recipient_address, recipient_account_id,
instruction_data, instruction_data,
tx_pre_check, tx_pre_check,
program, program,
@ -247,7 +257,7 @@ impl WalletCore {
pub async fn send_transfer_token_transaction_shielded_foreign_account( pub async fn send_transfer_token_transaction_shielded_foreign_account(
&self, &self,
sender_address: Address, sender_account_id: AccountId,
recipient_npk: NullifierPublicKey, recipient_npk: NullifierPublicKey,
recipient_ipk: IncomingViewingPublicKey, recipient_ipk: IncomingViewingPublicKey,
amount: u128, amount: u128,
@ -256,7 +266,7 @@ impl WalletCore {
WalletCore::token_program_preparation_transfer(amount); WalletCore::token_program_preparation_transfer(amount);
self.shielded_two_accs_receiver_outer( self.shielded_two_accs_receiver_outer(
sender_address, sender_account_id,
recipient_npk, recipient_npk,
recipient_ipk, recipient_ipk,
instruction_data, instruction_data,

View File

@ -1,13 +1,13 @@
use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse}; use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse};
use nssa::Address; use nssa::AccountId;
use crate::WalletCore; use crate::WalletCore;
impl WalletCore { impl WalletCore {
pub async fn send_deshielded_native_token_transfer( pub async fn send_deshielded_native_token_transfer(
&self, &self,
from: Address, from: AccountId,
to: Address, to: AccountId,
balance_to_move: u128, balance_to_move: u128,
) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 1]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [nssa_core::SharedSecretKey; 1]), ExecutionFailureKind> {
let (instruction_data, program, tx_pre_check) = let (instruction_data, program, tx_pre_check) =

View File

@ -1,5 +1,5 @@
use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse}; use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse};
use nssa::Address; use nssa::AccountId;
use nssa_core::{ use nssa_core::{
MembershipProof, NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey, MembershipProof, NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey,
}; };
@ -9,7 +9,7 @@ use crate::WalletCore;
impl WalletCore { impl WalletCore {
pub async fn send_private_native_token_transfer_outer_account( pub async fn send_private_native_token_transfer_outer_account(
&self, &self,
from: Address, from: AccountId,
to_npk: NullifierPublicKey, to_npk: NullifierPublicKey,
to_ipk: IncomingViewingPublicKey, to_ipk: IncomingViewingPublicKey,
balance_to_move: u128, balance_to_move: u128,
@ -30,8 +30,8 @@ impl WalletCore {
pub async fn send_private_native_token_transfer_owned_account_not_initialized( pub async fn send_private_native_token_transfer_owned_account_not_initialized(
&self, &self,
from: Address, from: AccountId,
to: Address, to: AccountId,
balance_to_move: u128, balance_to_move: u128,
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {
let (instruction_data, program, tx_pre_check) = 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( pub async fn send_private_native_token_transfer_owned_account_already_initialized(
&self, &self,
from: Address, from: AccountId,
to: Address, to: AccountId,
balance_to_move: u128, balance_to_move: u128,
to_proof: MembershipProof, to_proof: MembershipProof,
) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [SharedSecretKey; 2]), ExecutionFailureKind> {

View File

@ -1,6 +1,6 @@
use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse}; use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse};
use nssa::{ use nssa::{
Address, PublicTransaction, AccountId, PublicTransaction,
program::Program, program::Program,
public_transaction::{Message, WitnessSet}, public_transaction::{Message, WitnessSet},
}; };
@ -10,8 +10,8 @@ use crate::WalletCore;
impl WalletCore { impl WalletCore {
pub async fn send_public_native_token_transfer( pub async fn send_public_native_token_transfer(
&self, &self,
from: Address, from: AccountId,
to: Address, to: AccountId,
balance_to_move: u128, balance_to_move: u128,
) -> Result<SendTxResponse, ExecutionFailureKind> { ) -> Result<SendTxResponse, ExecutionFailureKind> {
let Ok(balance) = self.get_account_balance(from).await else { let Ok(balance) = self.get_account_balance(from).await else {
@ -23,9 +23,10 @@ impl WalletCore {
return Err(ExecutionFailureKind::SequencerError); return Err(ExecutionFailureKind::SequencerError);
}; };
let addresses = vec![from, to]; let account_ids = vec![from, to];
let program_id = Program::authenticated_transfer_program().id(); 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); 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( pub async fn register_account_under_authenticated_transfers_programs(
&self, &self,
from: Address, from: AccountId,
) -> Result<SendTxResponse, ExecutionFailureKind> { ) -> Result<SendTxResponse, ExecutionFailureKind> {
let Ok(nonces) = self.get_accounts_nonces(vec![from]).await else { let Ok(nonces) = self.get_accounts_nonces(vec![from]).await else {
return Err(ExecutionFailureKind::SequencerError); return Err(ExecutionFailureKind::SequencerError);
}; };
let instruction: u128 = 0; let instruction: u128 = 0;
let addresses = vec![from]; let account_ids = vec![from];
let program_id = Program::authenticated_transfer_program().id(); 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); let signing_key = self.storage.user_data.get_pub_account_signing_key(&from);

View File

@ -1,5 +1,5 @@
use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse}; use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse};
use nssa::Address; use nssa::AccountId;
use nssa_core::{ use nssa_core::{
MembershipProof, NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey, MembershipProof, NullifierPublicKey, SharedSecretKey, encryption::IncomingViewingPublicKey,
}; };
@ -9,8 +9,8 @@ use crate::WalletCore;
impl WalletCore { impl WalletCore {
pub async fn send_shielded_native_token_transfer_already_initialized( pub async fn send_shielded_native_token_transfer_already_initialized(
&self, &self,
from: Address, from: AccountId,
to: Address, to: AccountId,
balance_to_move: u128, balance_to_move: u128,
to_proof: MembershipProof, to_proof: MembershipProof,
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
@ -23,8 +23,8 @@ impl WalletCore {
pub async fn send_shielded_native_token_transfer_not_initialized( pub async fn send_shielded_native_token_transfer_not_initialized(
&self, &self,
from: Address, from: AccountId,
to: Address, to: AccountId,
balance_to_move: u128, balance_to_move: u128,
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
let (instruction_data, program, tx_pre_check) = let (instruction_data, program, tx_pre_check) =
@ -36,7 +36,7 @@ impl WalletCore {
pub async fn send_shielded_native_token_transfer_outer_account( pub async fn send_shielded_native_token_transfer_outer_account(
&self, &self,
from: Address, from: AccountId,
to_npk: NullifierPublicKey, to_npk: NullifierPublicKey,
to_ipk: IncomingViewingPublicKey, to_ipk: IncomingViewingPublicKey,
balance_to_move: u128, balance_to_move: u128,

View File

@ -1,7 +1,7 @@
use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse}; use common::{error::ExecutionFailureKind, sequencer_client::json::SendTxResponse};
use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder; use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder;
use nssa::{ use nssa::{
Account, Address, PrivacyPreservingTransaction, Account, AccountId, PrivacyPreservingTransaction,
privacy_preserving_transaction::{circuit, message::Message, witness_set::WitnessSet}, privacy_preserving_transaction::{circuit, message::Message, witness_set::WitnessSet},
program::Program, program::Program,
}; };
@ -23,12 +23,15 @@ pub(crate) struct AccountPreparedData {
impl WalletCore { impl WalletCore {
pub(crate) async fn private_acc_preparation( pub(crate) async fn private_acc_preparation(
&self, &self,
addr: Address, account_id: AccountId,
is_authorized: bool, is_authorized: bool,
needs_proof: bool, needs_proof: bool,
) -> Result<AccountPreparedData, ExecutionFailureKind> { ) -> Result<AccountPreparedData, ExecutionFailureKind> {
let Some((from_keys, from_acc)) = let Some((from_keys, from_acc)) = self
self.storage.user_data.get_private_account(&addr).cloned() .storage
.user_data
.get_private_account(&account_id)
.cloned()
else { else {
return Err(ExecutionFailureKind::KeyNotFoundError); return Err(ExecutionFailureKind::KeyNotFoundError);
}; };
@ -66,8 +69,8 @@ impl WalletCore {
pub(crate) async fn private_tx_two_accs_all_init( pub(crate) async fn private_tx_two_accs_all_init(
&self, &self,
from: Address, from: AccountId,
to: Address, to: AccountId,
instruction_data: InstructionData, instruction_data: InstructionData,
tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
program: Program, program: Program,
@ -144,8 +147,8 @@ impl WalletCore {
pub(crate) async fn private_tx_two_accs_receiver_uninit( pub(crate) async fn private_tx_two_accs_receiver_uninit(
&self, &self,
from: Address, from: AccountId,
to: Address, to: AccountId,
instruction_data: InstructionData, instruction_data: InstructionData,
tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
program: Program, program: Program,
@ -218,7 +221,7 @@ impl WalletCore {
pub(crate) async fn private_tx_two_accs_receiver_outer( pub(crate) async fn private_tx_two_accs_receiver_outer(
&self, &self,
from: Address, from: AccountId,
to_npk: NullifierPublicKey, to_npk: NullifierPublicKey,
to_ipk: IncomingViewingPublicKey, to_ipk: IncomingViewingPublicKey,
instruction_data: InstructionData, instruction_data: InstructionData,
@ -289,8 +292,8 @@ impl WalletCore {
pub(crate) async fn deshielded_tx_two_accs( pub(crate) async fn deshielded_tx_two_accs(
&self, &self,
from: Address, from: AccountId,
to: Address, to: AccountId,
instruction_data: InstructionData, instruction_data: InstructionData,
tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
program: Program, program: Program,
@ -349,8 +352,8 @@ impl WalletCore {
pub(crate) async fn shielded_two_accs_all_init( pub(crate) async fn shielded_two_accs_all_init(
&self, &self,
from: Address, from: AccountId,
to: Address, to: AccountId,
instruction_data: InstructionData, instruction_data: InstructionData,
tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
program: Program, program: Program,
@ -416,8 +419,8 @@ impl WalletCore {
pub(crate) async fn shielded_two_accs_receiver_uninit( pub(crate) async fn shielded_two_accs_receiver_uninit(
&self, &self,
from: Address, from: AccountId,
to: Address, to: AccountId,
instruction_data: InstructionData, instruction_data: InstructionData,
tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>, tx_pre_check: impl FnOnce(&Account, &Account) -> Result<(), ExecutionFailureKind>,
program: Program, program: Program,
@ -482,7 +485,7 @@ impl WalletCore {
pub(crate) async fn shielded_two_accs_receiver_outer( pub(crate) async fn shielded_two_accs_receiver_outer(
&self, &self,
from: Address, from: AccountId,
to_npk: NullifierPublicKey, to_npk: NullifierPublicKey,
to_ipk: IncomingViewingPublicKey, to_ipk: IncomingViewingPublicKey,
instruction_data: InstructionData, instruction_data: InstructionData,
@ -540,7 +543,7 @@ impl WalletCore {
pub async fn register_account_under_authenticated_transfers_programs_private( pub async fn register_account_under_authenticated_transfers_programs_private(
&self, &self,
from: Address, from: AccountId,
) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> { ) -> Result<(SendTxResponse, [SharedSecretKey; 1]), ExecutionFailureKind> {
let AccountPreparedData { let AccountPreparedData {
nsk: _, nsk: _,