Merge branch 'Pravdyvy/node-wallet-rewrite' into schouhy/implement-nssa-v0.1-public-state-tmp

This commit is contained in:
Sergio Chouhy 2025-08-09 06:36:13 -03:00
commit 20a7dad9a0
70 changed files with 782 additions and 11186 deletions

1
.gitignore vendored
View File

@ -6,3 +6,4 @@ data/
.idea/
.vscode/
rocksdb
Cargo.lock

6124
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,15 @@
[workspace]
resolver = "2"
members = [
"integration_tests",
"sequencer_runner",
"storage",
"accounts",
"utxo",
"vm",
"networking",
"consensus",
"sequencer_rpc",
"mempool",
"zkvm",
"wallet",
"sequencer_core",
"common",
"sc_core",
@ -72,7 +71,7 @@ version = "=4.1.0"
[workspace.dependencies.clap]
features = ["derive", "env"]
version = "3.1.6"
version = "4.5.42"
[workspace.dependencies.tokio-retry]
version = "0.3.0"

View File

@ -23,3 +23,6 @@ path = "../utxo"
[dependencies.common]
path = "../common"
[dependencies.nssa]
path = "../nssa"

View File

@ -4,33 +4,3 @@ use tiny_keccak::{Hasher, Keccak};
// TODO: Consider wrapping `AccountAddress` in a struct.
pub type AccountAddress = [u8; 32];
/// Returns the address associated with a public key
pub fn from_public_key(public_key: &SignaturePublicKey) -> AccountAddress {
let mut address = [0; 32];
let mut keccak_hasher = Keccak::v256();
keccak_hasher.update(&public_key.to_sec1_bytes());
keccak_hasher.finalize(&mut address);
address
}
#[cfg(test)]
mod tests {
use common::transaction::SignaturePrivateKey;
use super::*;
use crate::account_core::address;
#[test]
fn test_address_key_equal_keccak_pub_sign_key() {
let signing_key = SignaturePrivateKey::from_slice(&[1; 32]).unwrap();
let public_key = signing_key.verifying_key();
let mut expected_address = [0; 32];
let mut keccak_hasher = Keccak::v256();
keccak_hasher.update(&public_key.to_sec1_bytes());
keccak_hasher.finalize(&mut expected_address);
assert_eq!(expected_address, address::from_public_key(public_key));
}
}

View File

@ -117,14 +117,14 @@ impl AccountPublicMask {
impl Account {
pub fn new() -> Self {
let key_holder = AddressKeyHolder::new_os_random();
let public_key = *key_holder.get_pub_account_signing_key().verifying_key();
let address = address::from_public_key(&public_key);
let public_key = nssa::PublicKey::new(&key_holder.get_pub_account_signing_key());
let address = nssa::Address::from_public_key(&public_key);
let balance = 0;
let utxos = HashMap::new();
Self {
key_holder,
address,
address: *address.value(),
balance,
utxos,
}
@ -132,13 +132,13 @@ impl Account {
pub fn new_with_balance(balance: u64) -> Self {
let key_holder = AddressKeyHolder::new_os_random();
let public_key = *key_holder.get_pub_account_signing_key().verifying_key();
let address = address::from_public_key(&public_key);
let public_key = nssa::PublicKey::new(&key_holder.get_pub_account_signing_key());
let address = nssa::Address::from_public_key(&public_key);
let utxos = HashMap::new();
Self {
key_holder,
address,
address: *address.value(),
balance,
utxos,
}

View File

@ -3,12 +3,13 @@ use constants_types::{CipherText, Nonce};
use elliptic_curve::point::AffineCoordinates;
use k256::{ecdsa::SigningKey, AffinePoint, FieldBytes};
use log::info;
use rand::{rngs::OsRng, RngCore};
use rand::{rngs::OsRng, Rng, RngCore};
use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder};
use serde::{Deserialize, Serialize};
use crate::account_core::PublicKey;
pub type PublicAccountSigningKey = [u8; 32];
use nssa::{self, PrivateKey};
pub mod constants_types;
pub mod ephemeral_key_holder;
@ -19,7 +20,7 @@ pub mod secret_holders;
pub struct AddressKeyHolder {
top_secret_key_holder: TopSecretKeyHolder,
pub utxo_secret_key_holder: UTXOSecretKeyHolder,
pub_account_signing_key: PublicAccountSigningKey,
pub_account_signing_key: nssa::PrivateKey,
pub nullifer_public_key: PublicKey,
pub viewing_public_key: PublicKey,
}
@ -37,9 +38,8 @@ impl AddressKeyHolder {
let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key();
let pub_account_signing_key = {
let mut bytes = [0; 32];
OsRng.fill_bytes(&mut bytes);
bytes
let mut rng = OsRng;
nssa::PrivateKey::new(rng.gen())
};
Self {
@ -52,10 +52,8 @@ impl AddressKeyHolder {
}
/// Returns the signing key for public transaction signatures
pub fn get_pub_account_signing_key(&self) -> SigningKey {
let field_bytes = FieldBytes::from_slice(&self.pub_account_signing_key);
// TODO: remove unwrap
SigningKey::from_bytes(field_bytes).unwrap()
pub fn get_pub_account_signing_key(&self) -> &nssa::PrivateKey {
&self.pub_account_signing_key
}
pub fn calculate_shared_secret_receiver(
@ -319,10 +317,7 @@ mod tests {
fn test_get_public_account_signing_key() {
let address_key_holder = AddressKeyHolder::new_os_random();
let signing_key = address_key_holder.get_pub_account_signing_key();
assert_eq!(
signing_key.to_bytes().as_slice(),
address_key_holder.pub_account_signing_key
);
assert_eq!(signing_key, &address_key_holder.pub_account_signing_key);
}
#[test]
@ -336,18 +331,13 @@ mod tests {
let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key();
let pub_account_signing_key = {
let mut bytes = [0; 32];
OsRng.fill_bytes(&mut bytes);
bytes
let mut rng = OsRng;
nssa::PrivateKey::new(rng.gen())
};
//Address is a Keccak(verification_key)
let field_bytes = FieldBytes::from_slice(&pub_account_signing_key);
let signing_key = SigningKey::from_bytes(field_bytes).unwrap();
let public_key = nssa::PublicKey::new(&pub_account_signing_key);
let verifying_key = signing_key.verifying_key();
let address = address::from_public_key(verifying_key);
let address = nssa::Address::from_public_key(&public_key);
println!("======Prerequisites======");
println!();
@ -373,7 +363,7 @@ mod tests {
println!("======Public data======");
println!();
println!("Address{:?}", hex::encode(address));
println!("Address{:?}", hex::encode(address.value()));
println!(
"Nulifier public key {:?}",
hex::encode(serde_json::to_vec(&nullifer_public_key).unwrap())

View File

@ -6,4 +6,5 @@ source env.sh
cargo test --release
cd integration_tests
export NSSA_WALLET_HOME_DIR=$(pwd)/configs/debug/node/
cargo run $(pwd)/configs/debug all

View File

@ -10,6 +10,7 @@ serde_json.workspace = true
serde.workspace = true
reqwest.workspace = true
k256.workspace = true
rand.workspace = true
rs_merkle.workspace = true
sha2.workspace = true

View File

@ -27,19 +27,19 @@ pub struct HashableBlockData {
pub data: Data,
}
impl Block {
pub fn produce_block_from_hashable_data(hashable_data: HashableBlockData) -> Self {
let data = serde_json::to_vec(&hashable_data).unwrap();
impl From<HashableBlockData> for Block {
fn from(value: HashableBlockData) -> Self {
let data = serde_json::to_vec(&value).unwrap();
let hash = OwnHasher::hash(&data);
Self {
block_id: hashable_data.block_id,
prev_block_id: hashable_data.prev_block_id,
block_id: value.block_id,
prev_block_id: value.prev_block_id,
hash,
transactions: hashable_data.transactions,
data: hashable_data.data,
prev_block_hash: hashable_data.prev_block_hash,
transactions: value.transactions,
data: value.data,
prev_block_hash: value.prev_block_hash,
}
}
}

View File

@ -7,9 +7,13 @@ pub mod execution_input;
pub mod merkle_tree_public;
pub mod nullifier;
pub mod rpc_primitives;
pub mod sequencer_client;
pub mod transaction;
pub mod utxo_commitment;
//Module for tests utility functions
pub mod test_utils;
use rpc_primitives::errors::RpcError;
///Account id on blockchain

View File

@ -19,8 +19,6 @@ pub struct RegisterAccountRequest {
#[derive(Serialize, Deserialize, Debug)]
pub struct SendTxRequest {
pub transaction: nssa::PublicTransaction,
///UTXO Commitment Root, Pub Tx Root
pub tx_roots: [[u8; 32]; 2],
}
#[derive(Serialize, Deserialize, Debug)]

View File

@ -1,13 +1,12 @@
use common::transaction::Transaction;
use serde::{Deserialize, Serialize};
use crate::transaction::Transaction;
//Requests
#[derive(Serialize, Deserialize, Debug)]
pub struct SendTxRequest {
pub transaction: Transaction,
///UTXO Commitment Root, Pub Tx Root
pub tx_roots: [[u8; 32]; 2],
pub transaction: nssa::PublicTransaction,
}
//Responses

View File

@ -1,35 +1,32 @@
use accounts::account_core::Account;
use anyhow::Result;
use common::rpc_primitives::requests::{
use super::rpc_primitives::requests::{
GetAccountBalanceRequest, GetAccountBalanceResponse, GetBlockDataRequest, GetBlockDataResponse,
GetGenesisIdRequest, GetGenesisIdResponse, GetInitialTestnetAccountsRequest,
RegisterAccountRequest, RegisterAccountResponse,
};
use common::transaction::Transaction;
use common::{SequencerClientError, SequencerRpcError};
use anyhow::Result;
use json::{SendTxRequest, SendTxResponse, SequencerRpcRequest, SequencerRpcResponse};
use reqwest::Client;
use serde_json::Value;
use crate::config::NodeConfig;
use crate::sequencer_client::json::AccountInitialData;
use crate::transaction::Transaction;
use crate::{SequencerClientError, SequencerRpcError};
pub mod json;
#[derive(Clone)]
pub struct SequencerClient {
pub client: reqwest::Client,
pub config: NodeConfig,
pub sequencer_addr: String,
}
impl SequencerClient {
pub fn new(config: NodeConfig) -> Result<Self> {
pub fn new(sequencer_addr: String) -> Result<Self> {
Ok(Self {
client: Client::builder()
//Add more fiedls if needed
.timeout(std::time::Duration::from_secs(60))
.build()?,
config,
sequencer_addr,
})
}
@ -40,7 +37,7 @@ impl SequencerClient {
) -> Result<Value, SequencerClientError> {
let request = SequencerRpcRequest::from_payload_version_2_0(method.to_string(), payload);
let call_builder = self.client.post(&self.config.sequencer_addr);
let call_builder = self.client.post(&self.sequencer_addr);
let call_res = call_builder.json(&request).send().await?;
@ -56,6 +53,7 @@ impl SequencerClient {
}
}
///Get block data at `block_id` from sequencer
pub async fn get_block(
&self,
block_id: u64,
@ -71,6 +69,7 @@ impl SequencerClient {
Ok(resp_deser)
}
///Get account public balance for `address`. `address` must be a valid hex-string for 32 bytes.
pub async fn get_account_balance(
&self,
address: String,
@ -88,15 +87,12 @@ impl SequencerClient {
Ok(resp_deser)
}
///Send transaction to sequencer
pub async fn send_tx(
&self,
transaction: Transaction,
tx_roots: [[u8; 32]; 2],
transaction: nssa::PublicTransaction,
) -> Result<SendTxResponse, SequencerClientError> {
let tx_req = SendTxRequest {
transaction,
tx_roots,
};
let tx_req = SendTxRequest { transaction };
let req = serde_json::to_value(tx_req)?;
@ -107,25 +103,7 @@ impl SequencerClient {
Ok(resp_deser)
}
pub async fn register_account(
&self,
account: &Account,
) -> Result<RegisterAccountResponse, SequencerClientError> {
let acc_req = RegisterAccountRequest {
address: account.address,
};
let req = serde_json::to_value(acc_req)?;
let resp = self
.call_method_with_payload("register_account", req)
.await?;
let resp_deser = serde_json::from_value(resp)?;
Ok(resp_deser)
}
///Get genesis id from sequencer
pub async fn get_genesis_id(&self) -> Result<GetGenesisIdResponse, SequencerClientError> {
let genesis_req = GetGenesisIdRequest {};
@ -141,6 +119,7 @@ impl SequencerClient {
Ok(resp_deser)
}
///Get initial testnet accounts from sequencer
pub async fn get_initial_testnet_accounts(
&self,
) -> Result<Vec<AccountInitialData>, SequencerClientError> {

90
common/src/test_utils.rs Normal file
View File

@ -0,0 +1,90 @@
use k256::ecdsa::SigningKey;
use nssa;
use secp256k1_zkp::Tweak;
use crate::{
block::{Block, HashableBlockData},
execution_input::PublicNativeTokenSend,
transaction::{SignaturePrivateKey, Transaction, TransactionBody, TxKind},
};
//Dummy producers
///Produce dummy block with
///
/// `id` - block id, provide zero for genesis
///
/// `prev_hash` - hash of previous block, provide None for genesis
///
/// `transactions` - vector of `Transaction` objects
///
/// `additional_data` - vector with additional data
pub fn produce_dummy_block(
id: u64,
prev_hash: Option<[u8; 32]>,
transactions: Vec<nssa::PublicTransaction>,
additional_data: Vec<u8>,
) -> Block {
let block_data = HashableBlockData {
block_id: id,
prev_block_id: id.saturating_sub(1),
prev_block_hash: prev_hash.unwrap_or_default(),
transactions,
data: additional_data,
};
block_data.into()
}
pub fn produce_dummy_empty_transaction() -> nssa::PublicTransaction {
let program_id = nssa::AUTHENTICATED_TRANSFER_PROGRAM.id;
let addresses = vec![];
let nonces = vec![];
let instruction_data = 0;
let message =
nssa::public_transaction::Message::new(program_id, addresses, nonces, instruction_data);
let private_key = nssa::PrivateKey::new(1);
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[&private_key]);
nssa::PublicTransaction::new(message, witness_set)
}
// pub fn create_dummy_private_transaction_random_signer(
// nullifier_created_hashes: Vec<[u8; 32]>,
// utxo_commitments_spent_hashes: Vec<[u8; 32]>,
// utxo_commitments_created_hashes: Vec<[u8; 32]>,
// ) -> Transaction {
// let mut rng = rand::thread_rng();
//
// let body = TransactionBody {
// tx_kind: TxKind::Private,
// execution_input: vec![],
// execution_output: vec![],
// utxo_commitments_spent_hashes,
// utxo_commitments_created_hashes,
// nullifier_created_hashes,
// execution_proof_private: "dummy_proof".to_string(),
// encoded_data: vec![],
// ephemeral_pub_key: vec![10, 11, 12],
// commitment: vec![],
// tweak: Tweak::new(&mut rng),
// secret_r: [0; 32],
// sc_addr: "sc_addr".to_string(),
// };
// Transaction::new(body, SignaturePrivateKey::random(&mut rng))
// }
pub fn create_dummy_transaction_native_token_transfer(
from: [u8; 32],
nonce: u128,
to: [u8; 32],
balance_to_move: u128,
signing_key: nssa::PrivateKey,
) -> nssa::PublicTransaction {
let addresses = vec![nssa::Address::new(from), nssa::Address::new(to)];
let nonces = vec![nonce];
let program_id = nssa::AUTHENTICATED_TRANSFER_PROGRAM.id;
let message =
nssa::public_transaction::Message::new(program_id, addresses, nonces, balance_to_move);
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[&signing_key]);
nssa::PublicTransaction::new(message, witness_set)
}

View File

@ -58,10 +58,6 @@ pub struct TransactionBody {
pub secret_r: [u8; 32],
///Hex-encoded address of a smart contract account called
pub sc_addr: String,
///Recorded changes in state of smart contract
///
/// First value represents vector of changes, second is new length of a state
pub state_changes: (serde_json::Value, usize),
}
#[derive(Debug, Serialize, Deserialize)]
@ -325,7 +321,6 @@ mod tests {
tweak: Tweak::from_slice(&[7; SECRET_KEY_SIZE]).unwrap(),
secret_r: [8; 32],
sc_addr: "someAddress".to_string(),
state_changes: (serde_json::Value::Null, 10),
}
}

View File

@ -1,15 +0,0 @@
[package]
name = "consensus"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow.workspace = true
serde_json.workspace = true
env_logger.workspace = true
log.workspace = true
serde.workspace = true
tokio.workspace = true
[dependencies.networking]
path = "../networking"

View File

@ -1,22 +0,0 @@
use std::sync::Arc;
use networking::peer_manager::PeerManager;
use tokio::sync::Mutex;
#[derive(Debug)]
///Entrypoint to consensus.
/// Manages consensus protocol.
pub struct ConsensusManager {
pub peer_manager: Arc<Mutex<PeerManager>>,
}
impl ConsensusManager {
pub fn new(peer_manager: Arc<Mutex<PeerManager>>) -> Self {
Self { peer_manager }
}
//ToDo: change block from generic value into struct, when data block will be defined
pub fn vote(&self, _block: serde_json::Value) -> bool {
todo!()
}
}

View File

@ -30,14 +30,8 @@ path = "../sequencer_core"
[dependencies.sequencer_runner]
path = "../sequencer_runner"
[dependencies.node_rpc]
path = "../node_rpc"
[dependencies.node_core]
path = "../node_core"
[dependencies.node_runner]
path = "../node_runner"
[dependencies.wallet]
path = "../wallet"
[dependencies.common]
path = "../common"

View File

@ -1,253 +1,45 @@
{
"home": "./node",
"override_rust_log": null,
"sequencer_addr": "http://127.0.0.1:3040",
"seq_poll_timeout_secs": 10,
"port": 3041,
"gas_config": {
"gas_fee_per_byte_deploy": 100,
"gas_fee_per_input_buffer_runtime": 1000,
"gas_fee_per_byte_runtime": 10,
"gas_cost_runtime": 100,
"gas_cost_deploy": 1000,
"gas_limit_deploy": 30000000,
"gas_limit_runtime": 30000000
},
"shapshot_frequency_in_blocks": 10,
"initial_accounts": [
{
"address": [
13,
150,
223,
204,
65,
64,
25,
56,
12,
157,
222,
12,
211,
220,
229,
170,
201,
15,
181,
68,
59,
248,
113,
16,
135,
65,
174,
175,
222,
85,
42,
215
],
"balance": 10000,
"key_holder": {
"address": [
13,
150,
223,
204,
65,
64,
25,
56,
12,
157,
222,
12,
211,
220,
229,
170,
201,
15,
181,
68,
59,
248,
113,
16,
135,
65,
174,
175,
222,
85,
42,
215
],
"nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718",
"pub_account_signing_key": [
133,
143,
177,
187,
252,
66,
237,
236,
234,
252,
244,
138,
5,
151,
3,
99,
217,
231,
112,
217,
77,
211,
58,
218,
176,
68,
99,
53,
152,
228,
198,
190
],
"top_secret_key_holder": {
"secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4"
},
"utxo_secret_key_holder": {
"nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506",
"viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF"
},
"viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6"
},
"utxos": {}
"home": "./node",
"override_rust_log": null,
"sequencer_addr": "http://127.0.0.1:3040",
"seq_poll_timeout_secs": 10,
"initial_accounts": [
{
"address": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
"balance": 10000,
"key_holder": {
"address": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
"nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718",
"pub_account_signing_key": 1,
"top_secret_key_holder": {
"secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4"
},
{
"address": [
151,
72,
112,
233,
190,
141,
10,
192,
138,
168,
59,
63,
199,
167,
166,
134,
41,
29,
135,
50,
80,
138,
186,
152,
179,
96,
128,
243,
156,
44,
243,
100
],
"balance": 20000,
"key_holder": {
"address": [
151,
72,
112,
233,
190,
141,
10,
192,
138,
168,
59,
63,
199,
167,
166,
134,
41,
29,
135,
50,
80,
138,
186,
152,
179,
96,
128,
243,
156,
44,
243,
100
],
"nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271",
"pub_account_signing_key": [
54,
90,
62,
225,
71,
225,
228,
148,
143,
53,
210,
23,
137,
158,
171,
156,
48,
7,
139,
52,
117,
242,
214,
7,
99,
29,
122,
184,
59,
116,
144,
107
],
"top_secret_key_holder": {
"secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179"
},
"utxo_secret_key_holder": {
"nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122",
"viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7"
},
"viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99"
},
"utxos": {}
}
]
}
"utxo_secret_key_holder": {
"nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506",
"viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF"
},
"viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6"
},
"utxos": {}
},
{
"address": [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
"balance": 20000,
"key_holder": {
"address": [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
"nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271",
"pub_account_signing_key": 2,
"top_secret_key_holder": {
"secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179"
},
"utxo_secret_key_holder": {
"nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122",
"viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7"
},
"viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99"
},
"utxos": {}
}
]
}

View File

@ -8,12 +8,12 @@
"port": 3040,
"initial_accounts": [
{
"addr": "0d96dfcc414019380c9dde0cd3dce5aac90fb5443bf871108741aeafde552ad7",
"addr": "0101010101010101010101010101010101010101010101010101010101010101",
"balance": 10000
},
{
"addr": "974870e9be8d0ac08aa83b3fc7a7a686291d8732508aba98b36080f39c2cf364",
"addr": "0202020202020202020202020202020202020202020202020202020202020202",
"balance": 20000
}
]
}
}

View File

@ -1,15 +1,15 @@
use std::{path::PathBuf, sync::Arc, time::Duration};
use std::{path::PathBuf, time::Duration};
use actix_web::dev::ServerHandle;
use anyhow::Result;
use clap::Parser;
use common::rpc_primitives::RpcConfig;
use common::sequencer_client::SequencerClient;
use log::info;
use node_core::{NodeCore, config::NodeConfig};
use sequencer_core::config::SequencerConfig;
use sequencer_runner::startup_sequencer;
use tempfile::TempDir;
use tokio::{sync::Mutex, task::JoinHandle};
use tokio::task::JoinHandle;
use wallet::{Command, helperfunctions::fetch_config};
#[derive(Parser, Debug)]
#[clap(version)]
@ -20,92 +20,49 @@ struct Args {
test_name: String,
}
pub const ACC_SENDER: &str = "0d96dfcc414019380c9dde0cd3dce5aac90fb5443bf871108741aeafde552ad7";
pub const ACC_RECEIVER: &str = "974870e9be8d0ac08aa83b3fc7a7a686291d8732508aba98b36080f39c2cf364";
pub const ACC_SENDER: &str = "0101010101010101010101010101010101010101010101010101010101010101";
pub const ACC_RECEIVER: &str = "0202020202020202020202020202020202020202020202020202020202020202";
pub const TIME_TO_WAIT_FOR_BLOCK_SECONDS: u64 = 12;
#[allow(clippy::type_complexity)]
pub async fn pre_test(
home_dir: PathBuf,
) -> Result<(
ServerHandle,
JoinHandle<Result<()>>,
ServerHandle,
TempDir,
TempDir,
Arc<Mutex<NodeCore>>,
)> {
) -> Result<(ServerHandle, JoinHandle<Result<()>>, TempDir)> {
let home_dir_sequencer = home_dir.join("sequencer");
let home_dir_node = home_dir.join("node");
let mut sequencer_config =
sequencer_runner::config::from_file(home_dir_sequencer.join("sequencer_config.json"))
.unwrap();
let mut node_config =
node_runner::config::from_file(home_dir_node.join("node_config.json")).unwrap();
let (temp_dir_node, temp_dir_sequencer) =
replace_home_dir_with_temp_dir_in_configs(&mut node_config, &mut sequencer_config);
let temp_dir_sequencer = replace_home_dir_with_temp_dir_in_configs(&mut sequencer_config);
let (seq_http_server_handle, sequencer_loop_handle) =
startup_sequencer(sequencer_config).await?;
let node_port = node_config.port;
let node_core = NodeCore::start_from_config_update_chain(node_config.clone()).await?;
let wrapped_node_core = Arc::new(Mutex::new(node_core));
let http_server = node_rpc::new_http_server(
RpcConfig::with_port(node_port),
node_config.clone(),
wrapped_node_core.clone(),
)?;
info!("HTTP server started");
let node_http_server_handle = http_server.handle();
tokio::spawn(http_server);
Ok((
seq_http_server_handle,
sequencer_loop_handle,
node_http_server_handle,
temp_dir_node,
temp_dir_sequencer,
wrapped_node_core,
))
}
pub fn replace_home_dir_with_temp_dir_in_configs(
node_config: &mut NodeConfig,
sequencer_config: &mut SequencerConfig,
) -> (TempDir, TempDir) {
let temp_dir_node = tempfile::tempdir().unwrap();
) -> TempDir {
let temp_dir_sequencer = tempfile::tempdir().unwrap();
node_config.home = temp_dir_node.path().to_path_buf();
sequencer_config.home = temp_dir_sequencer.path().to_path_buf();
(temp_dir_node, temp_dir_sequencer)
temp_dir_sequencer
}
#[allow(clippy::type_complexity)]
pub async fn post_test(
residual: (
ServerHandle,
JoinHandle<Result<()>>,
ServerHandle,
TempDir,
TempDir,
Arc<Mutex<NodeCore>>,
),
) {
let (seq_http_server_handle, sequencer_loop_handle, node_http_server_handle, _, _, _) =
residual;
pub async fn post_test(residual: (ServerHandle, JoinHandle<Result<()>>, TempDir)) {
let (seq_http_server_handle, sequencer_loop_handle, _) = residual;
info!("Cleanup");
node_http_server_handle.stop(true).await;
sequencer_loop_handle.abort();
seq_http_server_handle.stop(true).await;
@ -113,28 +70,28 @@ pub async fn post_test(
//So they are dropped and tempdirs will be dropped too,
}
pub async fn test_success(wrapped_node_core: Arc<Mutex<NodeCore>>) {
let acc_sender = hex::decode(ACC_SENDER).unwrap().try_into().unwrap();
let acc_receiver = hex::decode(ACC_RECEIVER).unwrap().try_into().unwrap();
pub async fn test_success() {
let command = Command::SendNativeTokenTransfer {
from: ACC_SENDER.to_string(),
to: ACC_RECEIVER.to_string(),
amount: 100,
};
let guard = wrapped_node_core.lock().await;
let node_config = fetch_config().unwrap();
let _res = guard
.send_public_native_token_transfer(acc_sender, 0, acc_receiver, 100)
.await
.unwrap();
let seq_client = SequencerClient::new(node_config.sequencer_addr.clone()).unwrap();
wallet::execute_subcommand(command).await.unwrap();
info!("Waiting for next block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
info!("Checking correct balance move");
let acc_1_balance = guard
.sequencer_client
let acc_1_balance = seq_client
.get_account_balance(ACC_SENDER.to_string())
.await
.unwrap();
let acc_2_balance = guard
.sequencer_client
let acc_2_balance = seq_client
.get_account_balance(ACC_RECEIVER.to_string())
.await
.unwrap();
@ -148,30 +105,30 @@ pub async fn test_success(wrapped_node_core: Arc<Mutex<NodeCore>>) {
info!("Success!");
}
pub async fn test_success_move_to_another_account(wrapped_node_core: Arc<Mutex<NodeCore>>) {
let acc_sender = hex::decode(ACC_SENDER).unwrap().try_into().unwrap();
let acc_receiver_new_acc = [42; 32];
pub async fn test_success_move_to_another_account() {
let hex_acc_receiver_new_acc = hex::encode([42; 32]);
let hex_acc_receiver_new_acc = hex::encode(acc_receiver_new_acc);
let command = Command::SendNativeTokenTransfer {
from: ACC_SENDER.to_string(),
to: hex_acc_receiver_new_acc.clone(),
amount: 100,
};
let guard = wrapped_node_core.lock().await;
let node_config = fetch_config().unwrap();
let _res = guard
.send_public_native_token_transfer(acc_sender, 0, acc_receiver_new_acc, 100)
.await
.unwrap();
let seq_client = SequencerClient::new(node_config.sequencer_addr.clone()).unwrap();
wallet::execute_subcommand(command).await.unwrap();
info!("Waiting for next block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
info!("Checking correct balance move");
let acc_1_balance = guard
.sequencer_client
let acc_1_balance = seq_client
.get_account_balance(ACC_SENDER.to_string())
.await
.unwrap();
let acc_2_balance = guard
.sequencer_client
let acc_2_balance = seq_client
.get_account_balance(hex_acc_receiver_new_acc)
.await
.unwrap();
@ -185,28 +142,28 @@ pub async fn test_success_move_to_another_account(wrapped_node_core: Arc<Mutex<N
info!("Success!");
}
pub async fn test_failure(wrapped_node_core: Arc<Mutex<NodeCore>>) {
let acc_sender = hex::decode(ACC_SENDER).unwrap().try_into().unwrap();
let acc_receiver = hex::decode(ACC_RECEIVER).unwrap().try_into().unwrap();
pub async fn test_failure() {
let command = Command::SendNativeTokenTransfer {
from: ACC_SENDER.to_string(),
to: ACC_RECEIVER.to_string(),
amount: 1000000,
};
let guard = wrapped_node_core.lock().await;
let node_config = fetch_config().unwrap();
let _res = guard
.send_public_native_token_transfer(acc_sender, 0, acc_receiver, 100000)
.await
.unwrap();
let seq_client = SequencerClient::new(node_config.sequencer_addr.clone()).unwrap();
wallet::execute_subcommand(command).await.unwrap();
info!("Waiting for next block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
info!("Checking correct balance move");
let acc_1_balance = guard
.sequencer_client
let acc_1_balance = seq_client
.get_account_balance(ACC_SENDER.to_string())
.await
.unwrap();
let acc_2_balance = guard
.sequencer_client
let acc_2_balance = seq_client
.get_account_balance(ACC_RECEIVER.to_string())
.await
.unwrap();
@ -224,12 +181,10 @@ macro_rules! test_cleanup_wrap {
($home_dir:ident, $test_func:ident) => {{
let res = pre_test($home_dir.clone()).await.unwrap();
let wrapped_node_core = res.5.clone();
info!("Waiting for first block creation");
tokio::time::sleep(Duration::from_secs(TIME_TO_WAIT_FOR_BLOCK_SECONDS)).await;
$test_func(wrapped_node_core.clone()).await;
$test_func().await;
post_test(res).await;
}};

View File

@ -1,11 +0,0 @@
[package]
name = "networking"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow.workspace = true
serde_json.workspace = true
env_logger.workspace = true
log.workspace = true
serde.workspace = true

View File

@ -1,5 +0,0 @@
pub mod network_protocol;
pub mod peer;
pub mod peer_manager;
pub mod rate_limiter;
pub mod tcp;

View File

@ -1,19 +0,0 @@
#[derive(Debug)]
pub enum MessageKind {}
pub type PeerId = u64;
pub type PeerDistance = u32;
#[derive(Debug)]
pub struct PeerAddr {
pub id: PeerId,
//Probably will be socket address in the future
pub addr: String,
}
#[derive(Debug)]
///Structure, which contains all necessary fields for handshake
pub struct Handshake {}
#[derive(Debug)]
pub enum HandshakeFailedReason {}

View File

@ -1,18 +0,0 @@
use crate::{
network_protocol::{HandshakeFailedReason, PeerAddr},
tcp::Connection,
};
#[derive(Debug)]
/// Structure, which stores all of the peer interaction data.
/// Created at per-peer connection basis at `PeerManager`
pub struct Peer {
pub connection: Connection,
pub peer_addr: PeerAddr,
}
impl Peer {
pub fn handshake(&mut self) -> Result<(), HandshakeFailedReason> {
todo!();
}
}

View File

@ -1,20 +0,0 @@
use anyhow::Result;
use crate::{network_protocol::PeerId, peer::Peer};
#[derive(Debug)]
///Entrypoint to network module.
/// Manages connections with peers in network
pub struct PeerManager {
pub my_peer_id: PeerId,
}
impl PeerManager {
pub async fn start_peer_manager(_num_threads: u8, my_peer_id: PeerId) -> Result<Self> {
Ok(Self { my_peer_id })
}
pub async fn connect(&self, _peer_id: PeerId) -> Peer {
todo!()
}
}

View File

@ -1,16 +0,0 @@
use std::collections::HashMap;
use crate::network_protocol::MessageKind;
#[derive(Debug)]
/// Object responsible to manage the rate limits of all network messages
/// for a single connection/peer.
pub struct RateLimiter {
pub limits: HashMap<MessageKind, u64>,
}
impl RateLimiter {
pub fn is_allowed(&self, _message: MessageKind) -> bool {
todo!();
}
}

View File

@ -1,11 +0,0 @@
use crate::network_protocol::PeerAddr;
#[derive(Debug)]
///Structure, representing peer connection
pub struct Connection {}
#[derive(Debug)]
pub enum ConnectionType {
Inbound { conn: Connection },
Outbound { conn: Connection, peer: PeerAddr },
}

View File

@ -1,269 +0,0 @@
use std::collections::{HashMap, HashSet};
use std::path::Path;
use accounts::account_core::Account;
use anyhow::{anyhow, Result};
use common::block::Block;
use common::merkle_tree_public::merkle_tree::HashStorageMerkleTree;
use common::nullifier::UTXONullifier;
use common::transaction::Transaction;
use common::utxo_commitment::UTXOCommitment;
use log::error;
use storage::sc_db_utils::{DataBlob, DataBlobChangeVariant};
use storage::RocksDBIO;
use crate::chain_storage::AccMap;
pub struct NodeBlockStore {
dbio: RocksDBIO,
}
impl NodeBlockStore {
///Starting database at the start of new chain.
/// Creates files if necessary.
///
/// ATTENTION: Will overwrite genesis block.
pub fn open_db_with_genesis(location: &Path, genesis_block: Option<Block>) -> Result<Self> {
Ok(Self {
dbio: RocksDBIO::new(location, genesis_block)?,
})
}
///Reopening existing database
pub fn open_db_restart(location: &Path, genesis_block: Block) -> Result<Self> {
NodeBlockStore::db_destroy(location)?;
NodeBlockStore::open_db_with_genesis(location, Some(genesis_block))
}
///Reloading existing database
pub fn open_db_reload(location: &Path) -> Result<Self> {
NodeBlockStore::open_db_with_genesis(location, None)
}
///Destroying existing database
fn db_destroy(location: &Path) -> Result<()> {
RocksDBIO::destroy(location).map_err(|err| anyhow!("RocksDBIO error: {}", err))
}
pub fn get_block_at_id(&self, id: u64) -> Result<Block> {
Ok(self.dbio.get_block(id)?)
}
pub fn put_block_at_id(&self, block: Block) -> Result<()> {
Ok(self.dbio.put_block(block, false)?)
}
pub fn put_sc_sc_state(
&self,
sc_addr: &str,
length: usize,
modifications: Vec<DataBlobChangeVariant>,
) -> Result<()> {
Ok(self.dbio.put_sc_sc_state(sc_addr, length, modifications)?)
}
pub fn get_sc_sc_state(&self, sc_addr: &str) -> Result<Vec<DataBlob>> {
Ok(self.dbio.get_sc_sc_state(sc_addr)?)
}
pub fn get_snapshot_block_id(&self) -> Result<u64> {
Ok(self.dbio.get_snapshot_block_id()?)
}
pub fn get_snapshot_account(&self) -> Result<HashMap<[u8; 32], Account>> {
let temp: AccMap = serde_json::from_slice(&self.dbio.get_snapshot_account()?)?;
Ok(temp.into())
}
pub fn get_snapshot_commitment(&self) -> Result<HashStorageMerkleTree<UTXOCommitment>> {
Ok(serde_json::from_slice(
&self.dbio.get_snapshot_commitment()?,
)?)
}
pub fn get_snapshot_nullifier(&self) -> Result<HashSet<UTXONullifier>> {
Ok(serde_json::from_slice(
&self.dbio.get_snapshot_nullifier()?,
)?)
}
pub fn get_snapshot_transaction(&self) -> Result<HashStorageMerkleTree<Transaction>> {
Ok(serde_json::from_slice(
&self.dbio.get_snapshot_transaction()?,
)?)
}
pub fn put_snapshot_at_block_id(
&self,
id: u64,
accounts_ser: Vec<u8>,
comm_ser: Vec<u8>,
txs_ser: Vec<u8>,
nullifiers_ser: Vec<u8>,
) -> Result<()> {
//Error notification for writing into DB error
self.dbio
.put_snapshot_block_id_db(id)
.inspect_err(|err| error!("Failed to store snapshot block id with error {err:#?}"))?;
self.dbio
.put_snapshot_account_db(accounts_ser)
.inspect_err(|err| error!("Failed to store snapshot accounts with error {err:#?}"))?;
self.dbio
.put_snapshot_commitement_db(comm_ser)
.inspect_err(|err| {
error!("Failed to store snapshot commitments with error {err:#?}")
})?;
self.dbio
.put_snapshot_transaction_db(txs_ser)
.inspect_err(|err| {
error!("Failed to store snapshot transactions with error {err:#?}")
})?;
self.dbio
.put_snapshot_nullifier_db(nullifiers_ser)
.inspect_err(|err| error!("Failed to store snapshot nullifiers with error {err:#?}"))?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use common::block::Data;
use tempfile::tempdir;
fn create_genesis_block() -> Block {
Block {
block_id: 0,
prev_block_id: 0,
prev_block_hash: [0; 32],
hash: [1; 32],
transactions: vec![],
data: Data::default(),
}
}
fn create_sample_block(block_id: u64, prev_block_id: u64) -> Block {
Block {
block_id,
prev_block_id,
prev_block_hash: [0; 32],
hash: [1; 32],
transactions: vec![],
data: Data::default(),
}
}
#[test]
fn test_open_db_with_genesis() {
let temp_dir = tempdir().unwrap();
let path = temp_dir.path();
let genesis_block = create_genesis_block();
let node_store =
NodeBlockStore::open_db_with_genesis(path, Some(genesis_block.clone())).unwrap();
// Verify the genesis block is stored
let stored_block = node_store.get_block_at_id(0).unwrap();
assert_eq!(stored_block.block_id, genesis_block.block_id);
assert_eq!(stored_block.hash, genesis_block.hash);
}
#[test]
fn test_open_db_restart() {
let temp_dir = tempdir().unwrap();
let path = temp_dir.path();
let genesis_block = create_genesis_block();
{
let node_store_old =
NodeBlockStore::open_db_with_genesis(path, Some(genesis_block.clone())).unwrap();
let block = create_sample_block(1, 0);
node_store_old.put_block_at_id(block.clone()).unwrap();
}
// Check that the first block is still in the old database
{
let node_store_old = NodeBlockStore::open_db_reload(path).unwrap();
let result = node_store_old.get_block_at_id(1);
assert!(result.is_ok());
}
// Restart the database
let node_store = NodeBlockStore::open_db_restart(path, genesis_block).unwrap();
// The block should no longer be available since no first block is set on restart
let result = node_store.get_block_at_id(1);
assert!(result.is_err());
}
#[test]
fn test_open_db_reload() {
let temp_dir = tempdir().unwrap();
let path = temp_dir.path();
let genesis_block = create_genesis_block();
let _ = NodeBlockStore::open_db_with_genesis(path, Some(genesis_block)).unwrap();
// Reload the database
let node_store = NodeBlockStore::open_db_reload(path).unwrap();
// The genesis block should be available on reload
let result = node_store.get_block_at_id(0);
assert!(result.is_ok());
}
#[test]
fn test_put_and_get_block() {
let temp_dir = tempdir().unwrap();
let path = temp_dir.path();
let genesis_block = create_genesis_block();
let node_store = NodeBlockStore::open_db_with_genesis(path, Some(genesis_block)).unwrap();
let block = create_sample_block(1, 0);
node_store.put_block_at_id(block.clone()).unwrap();
let retrieved_block = node_store.get_block_at_id(1).unwrap();
assert_eq!(retrieved_block.block_id, block.block_id);
assert_eq!(retrieved_block.hash, block.hash);
}
#[test]
fn test_put_snapshot_at_block_id() {
let temp_dir = tempdir().unwrap();
let path = temp_dir.path();
let genesis_block = create_genesis_block();
let node_store = NodeBlockStore::open_db_with_genesis(path, Some(genesis_block)).unwrap();
let id = 3;
let accounts_ser = vec![1, 2, 3, 4];
let comm_ser = vec![5, 6, 7, 8];
let txs_ser = vec![9, 10, 11, 12];
let nullifiers_ser = vec![13, 14, 15, 16];
node_store
.put_snapshot_at_block_id(
id,
accounts_ser.clone(),
comm_ser.clone(),
txs_ser.clone(),
nullifiers_ser.clone(),
)
.unwrap();
assert_eq!(node_store.dbio.get_snapshot_block_id().unwrap(), id);
assert_eq!(
node_store.dbio.get_snapshot_account().unwrap(),
accounts_ser
);
assert_eq!(node_store.dbio.get_snapshot_commitment().unwrap(), comm_ser);
assert_eq!(node_store.dbio.get_snapshot_transaction().unwrap(), txs_ser);
assert_eq!(
node_store.dbio.get_snapshot_nullifier().unwrap(),
nullifiers_ser
);
}
}

View File

@ -1,632 +0,0 @@
use std::collections::{BTreeMap, HashMap, HashSet};
use accounts::account_core::{address::AccountAddress, Account};
use anyhow::Result;
use block_store::NodeBlockStore;
use common::{
block::Block,
execution_input::PublicNativeTokenSend,
merkle_tree_public::merkle_tree::{PublicTransactionMerkleTree, UTXOCommitmentsMerkleTree},
nullifier::UTXONullifier,
utxo_commitment::UTXOCommitment,
};
use k256::AffinePoint;
use log::{info, warn};
use sc_core::public_context::PublicSCContext;
use serde::{Deserialize, Serialize};
use utxo::utxo_core::UTXO;
use crate::{config::NodeConfig, ActionData};
pub mod accounts_store;
pub mod block_store;
#[derive(Deserialize, Serialize)]
pub struct AccMap {
pub acc_map: HashMap<String, Account>,
}
impl From<HashMap<[u8; 32], Account>> for AccMap {
fn from(value: HashMap<[u8; 32], Account>) -> Self {
AccMap {
acc_map: value
.into_iter()
.map(|(key, val)| (hex::encode(key), val))
.collect(),
}
}
}
impl From<AccMap> for HashMap<[u8; 32], Account> {
fn from(value: AccMap) -> Self {
value
.acc_map
.into_iter()
.map(|(key, val)| (hex::decode(key).unwrap().try_into().unwrap(), val))
.collect()
}
}
pub struct NodeChainStore {
pub acc_map: HashMap<AccountAddress, Account>,
pub block_store: NodeBlockStore,
pub nullifier_store: HashSet<UTXONullifier>,
pub utxo_commitments_store: UTXOCommitmentsMerkleTree,
pub pub_tx_store: PublicTransactionMerkleTree,
pub node_config: NodeConfig,
}
impl NodeChainStore {
pub fn new(config: NodeConfig, genesis_block: Block) -> Result<(Self, u64)> {
let mut acc_map = HashMap::new();
let mut nullifier_store = HashSet::new();
let mut utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]);
let mut pub_tx_store = PublicTransactionMerkleTree::new(vec![]);
let mut block_id = genesis_block.block_id;
//Sequencer should panic if unable to open db,
//as fixing this issue may require actions non-native to program scope
let block_store =
NodeBlockStore::open_db_with_genesis(&config.home.join("rocksdb"), Some(genesis_block))
.unwrap();
if let Ok(temp_block_id) = block_store.get_snapshot_block_id() {
utxo_commitments_store = block_store.get_snapshot_commitment()?;
nullifier_store = block_store.get_snapshot_nullifier()?;
acc_map = block_store.get_snapshot_account()?;
pub_tx_store = block_store.get_snapshot_transaction()?;
block_id = temp_block_id;
}
Ok((
Self {
acc_map,
block_store,
nullifier_store,
utxo_commitments_store,
pub_tx_store,
node_config: config,
},
block_id,
))
}
pub fn new_after_restart(config: NodeConfig, genesis_block: Block) -> Result<(Self, u64)> {
let mut acc_map = HashMap::new();
let mut nullifier_store = HashSet::new();
let mut utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]);
let mut pub_tx_store = PublicTransactionMerkleTree::new(vec![]);
let mut block_id = genesis_block.block_id;
//Sequencer should panic if unable to open db,
//as fixing this issue may require actions non-native to program scope
let block_store = NodeBlockStore::open_db_reload(&config.home.join("rocksdb")).unwrap();
if let Ok(temp_block_id) = block_store.get_snapshot_block_id() {
utxo_commitments_store = block_store.get_snapshot_commitment()?;
nullifier_store = block_store.get_snapshot_nullifier()?;
acc_map = block_store.get_snapshot_account()?;
pub_tx_store = block_store.get_snapshot_transaction()?;
block_id = temp_block_id;
}
Ok((
Self {
acc_map,
block_store,
nullifier_store,
utxo_commitments_store,
pub_tx_store,
node_config: config,
},
block_id,
))
}
pub fn dissect_insert_block(&mut self, block: Block) -> Result<()> {
let block_id = block.block_id;
for tx in &block.transactions {
if !tx.body().execution_input.is_empty() {
let public_action =
serde_json::from_slice::<ActionData>(&tx.body().execution_input);
if let Ok(public_action) = public_action {
match public_action {
ActionData::MintMoneyPublicTx(action) => {
let acc_mut = self.acc_map.get_mut(&action.acc);
if let Some(acc_mut) = acc_mut {
acc_mut.balance += action.amount as u64;
}
}
ActionData::SendMoneyDeshieldedTx(action) => {
for (balance, acc_addr) in action.receiver_data {
let acc_mut = self.acc_map.get_mut(&acc_addr);
if let Some(acc_mut) = acc_mut {
acc_mut.balance += balance as u64;
}
}
}
ActionData::SendMoneyShieldedTx(action) => {
let acc_mut = self.acc_map.get_mut(&action.acc_sender);
if let Some(acc_mut) = acc_mut {
acc_mut.balance =
acc_mut.balance.saturating_sub(action.amount as u64);
}
}
_ => {}
}
} else {
let native_transfer =
serde_json::from_slice::<PublicNativeTokenSend>(&tx.body().execution_input);
if let Ok(transfer) = native_transfer {
if let Some(acc_sender) = self.acc_map.get_mut(&transfer.from) {
//Can panic, we depend on sequencer maintaining chain consistency here
acc_sender.balance -= transfer.balance_to_move;
if let Some(acc_rec) = self.acc_map.get_mut(&transfer.to) {
acc_rec.balance += transfer.balance_to_move;
}
}
}
}
}
self.utxo_commitments_store.add_tx_multiple(
tx.body()
.utxo_commitments_created_hashes
.clone()
.into_iter()
.map(|hash| UTXOCommitment { hash })
.collect(),
);
for nullifier in tx.body().nullifier_created_hashes.iter() {
self.nullifier_store.insert(UTXONullifier {
utxo_hash: *nullifier,
});
}
if !tx.body().encoded_data.is_empty() {
let ephemeral_public_key_sender =
serde_json::from_slice::<AffinePoint>(&tx.body().ephemeral_pub_key)?;
for (ciphertext, nonce, tag) in tx.body().encoded_data.clone() {
let slice = nonce.as_slice();
let nonce =
accounts::key_management::constants_types::Nonce::clone_from_slice(slice);
for (acc_id, acc) in self.acc_map.iter_mut() {
if hex::decode(acc_id).unwrap()[0] == tag {
let decoded_data_curr_acc = acc.decrypt_data(
ephemeral_public_key_sender,
ciphertext.clone(),
nonce,
);
if let Ok(decoded_data_curr_acc) = decoded_data_curr_acc {
let decoded_utxo_try =
serde_json::from_slice::<UTXO>(&decoded_data_curr_acc);
if let Ok(utxo) = decoded_utxo_try {
if &utxo.owner == acc_id {
acc.utxos.insert(utxo.hash, utxo);
}
}
}
}
}
}
}
self.pub_tx_store.add_tx(tx);
}
self.block_store.put_block_at_id(block)?;
//Snapshot
if block_id.is_multiple_of(self.node_config.shapshot_frequency_in_blocks) {
//Serializing all important data structures
//If we fail serialization, it is not the reason to stop running
//Logging on warn level in this cases
let acc_map: AccMap = self.acc_map.clone().into();
if let Ok(accounts_ser) = serde_json::to_vec(&acc_map).inspect_err(|err| {
warn!("Failed to serialize accounts data {err:#?}");
}) {
if let Ok(comm_ser) =
serde_json::to_vec(&self.utxo_commitments_store).inspect_err(|err| {
warn!("Failed to serialize commitments {err:#?}");
})
{
if let Ok(txs_ser) = serde_json::to_vec(&self.pub_tx_store).inspect_err(|err| {
warn!("Failed to serialize transactions {err:#?}");
}) {
if let Ok(nullifiers_ser) = serde_json::to_vec(&self.nullifier_store)
.inspect_err(|err| {
warn!("Failed to serialize nullifiers {err:#?}");
})
{
let snapshot_trace = self.block_store.put_snapshot_at_block_id(
block_id,
accounts_ser,
comm_ser,
txs_ser,
nullifiers_ser,
);
info!(
"Snapshot executed at {block_id:?} with results {snapshot_trace:#?}"
);
}
}
}
}
}
Ok(())
}
pub fn produce_context(&self, caller: AccountAddress) -> PublicSCContext {
let mut account_masks = BTreeMap::new();
for (acc_addr, acc) in &self.acc_map {
account_masks.insert(*acc_addr, acc.make_account_public_mask());
}
PublicSCContext {
caller_address: caller,
caller_balance: self.acc_map.get(&caller).unwrap().balance,
account_masks,
comitment_store_root: self.utxo_commitments_store.get_root().unwrap_or([0; 32]),
pub_tx_store_root: self.pub_tx_store.get_root().unwrap_or([0; 32]),
nullifiers_set: self
.nullifier_store
.iter()
.map(|item| item.utxo_hash)
.collect(),
commitments_tree: self.utxo_commitments_store.clone(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::GasConfig;
use accounts::account_core::Account;
use common::block::{Block, Data};
use common::merkle_tree_public::TreeHashType;
use common::transaction::{SignaturePrivateKey, Transaction, TransactionBody, TxKind};
use secp256k1_zkp::Tweak;
use std::path::PathBuf;
use tempfile::tempdir;
fn create_initial_accounts() -> Vec<Account> {
let initial_acc1 = serde_json::from_str(r#"{
"address": [
244,
55,
238,
205,
74,
115,
179,
192,
65,
186,
166,
169,
221,
45,
6,
57,
200,
65,
195,
70,
118,
252,
206,
100,
215,
250,
72,
230,
19,
71,
217,
249
],
"balance": 100,
"key_holder": {
"nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718",
"pub_account_signing_key": [
244,
88,
134,
61,
35,
209,
229,
101,
85,
35,
140,
140,
192,
226,
83,
83,
190,
189,
110,
8,
89,
127,
147,
142,
157,
204,
51,
109,
189,
92,
144,
68
],
"top_secret_key_holder": {
"secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4"
},
"utxo_secret_key_holder": {
"nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506",
"viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF"
},
"viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6"
},
"utxos": {}
}"#).unwrap();
let initial_acc2 = serde_json::from_str(r#"{
"address": [
72,
169,
70,
237,
1,
96,
35,
157,
25,
15,
83,
18,
52,
206,
202,
63,
48,
59,
173,
76,
78,
7,
254,
229,
28,
45,
194,
79,
6,
89,
58,
85
],
"balance": 200,
"key_holder": {
"nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271",
"pub_account_signing_key": [
136,
105,
9,
53,
180,
145,
64,
5,
235,
174,
62,
211,
206,
116,
185,
24,
214,
62,
244,
64,
224,
59,
120,
150,
30,
249,
160,
46,
189,
254,
47,
244
],
"top_secret_key_holder": {
"secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179"
},
"utxo_secret_key_holder": {
"nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122",
"viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7"
},
"viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99"
},
"utxos": {}
}"#).unwrap();
let initial_accounts = vec![initial_acc1, initial_acc2];
initial_accounts
}
fn create_genesis_block() -> Block {
Block {
block_id: 0,
prev_block_id: 0,
prev_block_hash: [0; 32],
hash: [1; 32],
transactions: vec![],
data: Data::default(),
}
}
fn create_dummy_transaction(
nullifier_created_hashes: Vec<[u8; 32]>,
utxo_commitments_spent_hashes: Vec<[u8; 32]>,
utxo_commitments_created_hashes: Vec<[u8; 32]>,
) -> Transaction {
let mut rng = rand::thread_rng();
let body = TransactionBody {
tx_kind: TxKind::Private,
execution_input: vec![],
execution_output: vec![],
utxo_commitments_spent_hashes,
utxo_commitments_created_hashes,
nullifier_created_hashes,
execution_proof_private: "dummy_proof".to_string(),
encoded_data: vec![],
ephemeral_pub_key: vec![10, 11, 12],
commitment: vec![],
tweak: Tweak::new(&mut rng),
secret_r: [0; 32],
sc_addr: "sc_addr".to_string(),
state_changes: (serde_json::Value::Null, 0),
};
Transaction::new(body, SignaturePrivateKey::random(&mut rng))
}
fn create_sample_block(block_id: u64, prev_block_id: u64) -> Block {
Block {
block_id,
prev_block_id,
prev_block_hash: [0; 32],
hash: [1; 32],
transactions: vec![],
data: Data::default(),
}
}
fn create_sample_node_config(home: PathBuf) -> NodeConfig {
NodeConfig {
home,
override_rust_log: None,
sequencer_addr: "http://127.0.0.1".to_string(),
seq_poll_timeout_secs: 1,
port: 8000,
gas_config: create_sample_gas_config(),
shapshot_frequency_in_blocks: 1,
initial_accounts: create_initial_accounts(),
}
}
fn create_sample_gas_config() -> GasConfig {
GasConfig {
gas_fee_per_byte_deploy: 0,
gas_fee_per_input_buffer_runtime: 0,
gas_fee_per_byte_runtime: 0,
gas_cost_runtime: 0,
gas_cost_deploy: 0,
gas_limit_deploy: 0,
gas_limit_runtime: 0,
}
}
fn generate_dummy_utxo(address: TreeHashType, amount: u128) -> UTXO {
UTXO::new(address, vec![], amount, false)
}
#[test]
fn test_new_initializes_correctly() {
let temp_dir = tempdir().unwrap();
let path = temp_dir.path();
let config = create_sample_node_config(path.to_path_buf());
let genesis_block = create_genesis_block();
let (store, block_id) = NodeChainStore::new(config.clone(), genesis_block.clone()).unwrap();
assert_eq!(block_id, 0);
assert!(store.acc_map.is_empty());
assert!(store.nullifier_store.is_empty());
assert_eq!(
store.utxo_commitments_store.get_root().unwrap_or([0; 32]),
[0; 32]
);
}
#[test]
fn test_new_recovers_from_snapshot() {
let temp_dir = tempdir().unwrap();
let path = temp_dir.path().to_path_buf();
let config = create_sample_node_config(path);
let nullifier_secret_const =
"261d61d294ac4bdc24f91b6f490efa263757a4a95f65871cd4f16b2ea23c3b5d";
std::env::set_var("NULLIFIER_SECRET_CONST", nullifier_secret_const);
let viewing_secret_const =
"6117af750b30d7a296672ec3b3b25d3489beca3cfe5770fa39f275cec395d5ce";
std::env::set_var("VIEWING_SECRET_CONST", viewing_secret_const);
let genesis_block = create_genesis_block();
// Initialize once to create DB and store fake snapshot
{
let (mut store, _) =
NodeChainStore::new(config.clone(), genesis_block.clone()).unwrap();
// Insert state
let mut account = Account::new();
account
.add_new_utxo_outputs(vec![generate_dummy_utxo(account.address, 100)])
.unwrap();
store.acc_map.insert(account.address, account);
store.nullifier_store.insert(UTXONullifier {
utxo_hash: [2u8; 32],
});
store
.utxo_commitments_store
.add_tx_multiple(vec![UTXOCommitment { hash: [3u8; 32] }]);
store.pub_tx_store.add_tx(&create_dummy_transaction(
vec![[9; 32]],
vec![[7; 32]],
vec![[8; 32]],
));
// Put block snapshot to trigger snapshot recovery on next load
let dummy_block = create_sample_block(1, 0);
store.dissect_insert_block(dummy_block).unwrap();
}
// Now reload and verify snapshot is used
let (recovered_store, block_id) =
NodeChainStore::new_after_restart(config.clone(), genesis_block).unwrap();
assert_eq!(block_id, 1);
assert_eq!(recovered_store.acc_map.len(), 1);
assert!(recovered_store.utxo_commitments_store.get_root().is_some());
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,71 +0,0 @@
use anyhow::Result;
use log::info;
use crate::chain_storage::NodeChainStore;
///Addres of public fund transfer account, as no such binary exists for zkVM
pub const PUBLIC_DEPOSIT_ID: [u8; 32] = [0; 32];
///Setups public states of default smart conracts as empty
pub async fn setup_empty_sc_states(node: &NodeChainStore) -> Result<()> {
info!("Filling up public states of default smart contracts");
let empty_state = vec![];
let public_deposit_addr = hex::encode(PUBLIC_DEPOSIT_ID);
node.block_store.put_sc_sc_state(
&public_deposit_addr,
empty_state.len(),
empty_state.clone(),
)?;
info!("Public transfer state set");
let mint_utxo_addr_bytes: Vec<u8> = zkvm::test_methods::MINT_UTXO_ID
.iter()
.flat_map(|num| num.to_le_bytes())
.collect();
let mint_utxo_addr = hex::encode(mint_utxo_addr_bytes);
node.block_store
.put_sc_sc_state(&mint_utxo_addr, empty_state.len(), empty_state.clone())?;
info!("Mint UTXO state set");
let single_utxo_transfer_addr_bytes: Vec<u8> = zkvm::test_methods::SEND_UTXO_ID
.iter()
.flat_map(|num| num.to_le_bytes())
.collect();
let single_utxo_transfer_addr = hex::encode(single_utxo_transfer_addr_bytes);
node.block_store.put_sc_sc_state(
&single_utxo_transfer_addr,
empty_state.len(),
empty_state.clone(),
)?;
info!("Single UTXO transfer state set");
let mint_utxo_multiple_assets_addr_bytes: Vec<u8> =
zkvm::test_methods::MINT_UTXO_MULTIPLE_ASSETS_ID
.iter()
.flat_map(|num| num.to_le_bytes())
.collect();
let mint_utxo_multiple_assets_addr = hex::encode(mint_utxo_multiple_assets_addr_bytes);
node.block_store.put_sc_sc_state(
&mint_utxo_multiple_assets_addr,
empty_state.len(),
empty_state.clone(),
)?;
info!("Mint UTXO multiple assets state set");
let multiple_assets_utxo_transfer_addr_bytes: Vec<u8> =
zkvm::test_methods::SEND_UTXO_MULTIPLE_ASSETS_ID
.iter()
.flat_map(|num| num.to_le_bytes())
.collect();
let multiple_assets_utxo_transfer_addr = hex::encode(multiple_assets_utxo_transfer_addr_bytes);
node.block_store.put_sc_sc_state(
&multiple_assets_utxo_transfer_addr,
empty_state.len(),
empty_state.clone(),
)?;
info!("Multiple_assets UTXO transfer state set");
Ok(())
}

View File

@ -1,45 +0,0 @@
[package]
name = "node_rpc"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow.workspace = true
serde_json.workspace = true
env_logger.workspace = true
log.workspace = true
serde.workspace = true
actix.workspace = true
actix-cors.workspace = true
futures.workspace = true
tokio.workspace = true
hex.workspace = true
actix-web.workspace = true
[dependencies.accounts]
path = "../accounts"
[dependencies.consensus]
path = "../consensus"
[dependencies.networking]
path = "../networking"
[dependencies.storage]
path = "../storage"
[dependencies.utxo]
path = "../utxo"
[dependencies.vm]
path = "../vm"
[dependencies.zkvm]
path = "../zkvm"
[dependencies.node_core]
path = "../node_core"
[dependencies.common]
path = "../common"

View File

@ -1,45 +0,0 @@
pub mod net_utils;
pub mod process;
pub mod types;
use std::sync::Arc;
use common::rpc_primitives::{
errors::{RpcError, RpcErrorKind},
RpcPollingConfig,
};
use node_core::{config::NodeConfig, NodeCore};
use serde::Serialize;
use serde_json::Value;
pub use net_utils::*;
use tokio::sync::Mutex;
use self::types::err_rpc::RpcErr;
//ToDo: Add necessary fields
pub struct JsonHandler {
pub polling_config: RpcPollingConfig,
pub node_core_config: NodeConfig,
pub node_chain_store: Arc<Mutex<NodeCore>>,
}
fn respond<T: Serialize>(val: T) -> Result<Value, RpcErr> {
Ok(serde_json::to_value(val)?)
}
pub fn rpc_error_responce_inverter(err: RpcError) -> RpcError {
let mut content: Option<Value> = None;
if err.error_struct.is_some() {
content = match err.error_struct.clone().unwrap() {
RpcErrorKind::HandlerError(val) | RpcErrorKind::InternalError(val) => Some(val),
RpcErrorKind::RequestValidationError(vall) => Some(serde_json::to_value(vall).unwrap()),
};
}
RpcError {
error_struct: None,
code: err.code,
message: err.message,
data: content,
}
}

View File

@ -1,76 +0,0 @@
use std::io;
use std::sync::Arc;
use actix_cors::Cors;
use actix_web::{http, middleware, web, App, Error as HttpError, HttpResponse, HttpServer};
use futures::Future;
use futures::FutureExt;
use log::info;
use common::rpc_primitives::message::Message;
use common::rpc_primitives::RpcConfig;
use node_core::config::NodeConfig;
use node_core::NodeCore;
use tokio::sync::Mutex;
use super::JsonHandler;
pub const SHUTDOWN_TIMEOUT_SECS: u64 = 10;
fn rpc_handler(
message: web::Json<Message>,
handler: web::Data<JsonHandler>,
) -> impl Future<Output = Result<HttpResponse, HttpError>> {
let response = async move {
let message = handler.process(message.0).await?;
Ok(HttpResponse::Ok().json(&message))
};
response.boxed()
}
fn get_cors(cors_allowed_origins: &[String]) -> Cors {
let mut cors = Cors::permissive();
if cors_allowed_origins != ["*".to_string()] {
for origin in cors_allowed_origins {
cors = cors.allowed_origin(origin);
}
}
cors.allowed_methods(vec!["GET", "POST"])
.allowed_headers(vec![http::header::AUTHORIZATION, http::header::ACCEPT])
.allowed_header(http::header::CONTENT_TYPE)
.max_age(3600)
}
#[allow(clippy::too_many_arguments)]
pub fn new_http_server(
config: RpcConfig,
node_config: NodeConfig,
node_chain_store: Arc<Mutex<NodeCore>>,
) -> io::Result<actix_web::dev::Server> {
let RpcConfig {
addr,
cors_allowed_origins,
polling_config,
limits_config,
} = config;
info!(target:"network", "Starting http server at {addr}");
let handler = web::Data::new(JsonHandler {
polling_config,
node_core_config: node_config,
node_chain_store,
});
// HTTP server
Ok(HttpServer::new(move || {
App::new()
.wrap(get_cors(&cors_allowed_origins))
.app_data(handler.clone())
.app_data(web::JsonConfig::default().limit(limits_config.json_payload_max_size))
.wrap(middleware::Logger::default())
.service(web::resource("/").route(web::post().to(rpc_handler)))
})
.bind(addr)?
.shutdown_timeout(SHUTDOWN_TIMEOUT_SECS)
.disable_signals()
.run())
}

View File

@ -1,755 +0,0 @@
use std::sync::atomic::Ordering;
use actix_web::Error as HttpError;
use node_core::generate_commitments_helper;
use serde_json::Value;
use common::rpc_primitives::{
errors::RpcError,
message::{Message, Request},
parser::RpcRequest,
};
use common::transaction::ActionData;
use common::rpc_primitives::requests::{
GetBlockDataRequest, GetBlockDataResponse, GetLastBlockRequest, GetLastBlockResponse,
};
use crate::types::{
err_rpc::cast_common_execution_error_into_rpc_error,
rpc_structs::{
CreateAccountRequest, CreateAccountResponse, ExecuteScenarioMultipleSendRequest,
ExecuteScenarioMultipleSendResponse, ExecuteScenarioSplitRequest,
ExecuteScenarioSplitResponse, ExecuteSubscenarioRequest, ExecuteSubscenarioResponse,
ShowAccountPublicBalanceRequest, ShowAccountPublicBalanceResponse, ShowAccountUTXORequest,
ShowAccountUTXOResponse, ShowTransactionRequest, ShowTransactionResponse,
UTXOShortEssentialStruct, WriteMintPrivateUTXOMultipleAssetsRequest,
WriteMintPrivateUTXOMultipleAssetsResponse, WriteMintPrivateUTXORequest,
WriteMintPrivateUTXOResponse, WriteSendDeshieldedBalanceRequest,
WriteSendDeshieldedUTXOResponse, WriteSendPrivateUTXORequest, WriteSendPrivateUTXOResponse,
WriteSendShieldedUTXORequest, WriteSendShieldedUTXOResponse, WriteSendSplitUTXOResponse,
WriteSplitUTXORequest,
},
};
pub const CREATE_ACCOUNT: &str = "create_account";
pub const EXECUTE_SUBSCENARIO: &str = "execute_subscenario";
pub const GET_BLOCK: &str = "get_block";
pub const GET_LAST_BLOCK: &str = "get_last_block";
pub const EXECUTE_SCENARIO_SPLIT: &str = "execute_scenario_split";
pub const EXECUTE_SCENARIO_MULTIPLE_SEND: &str = "execute_scenario_multiple_send";
pub const SHOW_ACCOUNT_PUBLIC_BALANCE: &str = "show_account_public_balance";
pub const SHOW_ACCOUNT_UTXO: &str = "show_account_utxo";
pub const SHOW_TRANSACTION: &str = "show_transaction";
pub const WRITE_MINT_UTXO: &str = "write_mint_utxo";
pub const WRITE_MINT_UTXO_MULTIPLE_ASSETS: &str = "write_mint_utxo_multiple_assets";
pub const WRITE_SEND_UTXO_PRIVATE: &str = "write_send_utxo_private";
pub const WRITE_SEND_UTXO_SHIELDED: &str = "write_send_utxo_shielded";
pub const WRITE_SEND_UTXO_DESHIELDED: &str = "write_send_utxo_deshielded";
pub const WRITE_SPLIT_UTXO: &str = "write_split_utxo";
pub const SUCCESS: &str = "success";
pub const ACCOUNT_NOT_FOUND: &str = "Account not found";
pub const TRANSACTION_NOT_FOUND: &str = "Transaction not found";
use super::{respond, types::err_rpc::RpcErr, JsonHandler};
impl JsonHandler {
pub async fn process(&self, message: Message) -> Result<Message, HttpError> {
let id = message.id();
if let Message::Request(request) = message {
let message_inner = self
.process_request_internal(request)
.await
.map_err(|e| e.0);
Ok(Message::response(id, message_inner))
} else {
Ok(Message::error(RpcError::parse_error(
"JSON RPC Request format was expected".to_owned(),
)))
}
}
async fn process_request_execute_subscenario(&self, request: Request) -> Result<Value, RpcErr> {
let req = ExecuteSubscenarioRequest::parse(Some(request.params))?;
{
let mut store = self.node_chain_store.lock().await;
match req.scenario_id {
1 => store
.subscenario_1()
.await
.map_err(cast_common_execution_error_into_rpc_error)?,
2 => store
.subscenario_2()
.await
.map_err(cast_common_execution_error_into_rpc_error)?,
3 => store
.subscenario_3()
.await
.map_err(cast_common_execution_error_into_rpc_error)?,
_ => return Err(RpcErr(RpcError::invalid_params("Scenario id not found"))),
}
}
let helperstruct = ExecuteSubscenarioResponse {
scenario_result: SUCCESS.to_string(),
};
respond(helperstruct)
}
async fn process_request_execute_scenario_split(
&self,
request: Request,
) -> Result<Value, RpcErr> {
let req = ExecuteScenarioSplitRequest::parse(Some(request.params))?;
{
let mut store = self.node_chain_store.lock().await;
store
.scenario_1(req.visibility_list, req.publication_index)
.await
.map_err(cast_common_execution_error_into_rpc_error)?;
}
let helperstruct = ExecuteScenarioSplitResponse {
scenario_result: SUCCESS.to_string(),
};
respond(helperstruct)
}
async fn process_request_execute_scenario_multiple_send(
&self,
request: Request,
) -> Result<Value, RpcErr> {
let req = ExecuteScenarioMultipleSendRequest::parse(Some(request.params))?;
{
let mut store = self.node_chain_store.lock().await;
store
.scenario_2(req.number_of_assets, req.number_to_send)
.await
.map_err(cast_common_execution_error_into_rpc_error)?;
}
let helperstruct = ExecuteScenarioMultipleSendResponse {
scenario_result: SUCCESS.to_string(),
};
respond(helperstruct)
}
async fn process_create_account(&self, request: Request) -> Result<Value, RpcErr> {
let _req = CreateAccountRequest::parse(Some(request.params))?;
let acc_addr = {
let mut guard = self.node_chain_store.lock().await;
guard.create_new_account().await
};
let helperstruct = CreateAccountResponse {
status: hex::encode(acc_addr),
};
respond(helperstruct)
}
async fn process_get_block_data(&self, request: Request) -> Result<Value, RpcErr> {
let req = GetBlockDataRequest::parse(Some(request.params))?;
let block = {
let guard = self.node_chain_store.lock().await;
{
let read_guard = guard.storage.read().await;
read_guard.block_store.get_block_at_id(req.block_id)?
}
};
let helperstruct = GetBlockDataResponse { block };
respond(helperstruct)
}
async fn process_get_last_block(&self, request: Request) -> Result<Value, RpcErr> {
let _req = GetLastBlockRequest::parse(Some(request.params))?;
let last_block = {
let guard = self.node_chain_store.lock().await;
guard.curr_height.load(Ordering::Relaxed)
};
let helperstruct = GetLastBlockResponse { last_block };
respond(helperstruct)
}
async fn process_show_account_public_balance(&self, request: Request) -> Result<Value, RpcErr> {
let req = ShowAccountPublicBalanceRequest::parse(Some(request.params))?;
let acc_addr_hex_dec = hex::decode(req.account_addr.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode account address from hex string".to_string())
})?;
let acc_addr: [u8; 32] = acc_addr_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address from bytes".to_string())
})?;
let balance = {
let cover_guard = self.node_chain_store.lock().await;
{
let under_guard = cover_guard.storage.read().await;
let acc = under_guard
.acc_map
.get(&acc_addr)
.ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?;
acc.balance
}
};
let helperstruct = ShowAccountPublicBalanceResponse {
addr: req.account_addr,
balance,
};
respond(helperstruct)
}
async fn process_show_account_utxo_request(&self, request: Request) -> Result<Value, RpcErr> {
let req = ShowAccountUTXORequest::parse(Some(request.params))?;
let acc_addr_hex_dec = hex::decode(req.account_addr.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode account address from hex string".to_string())
})?;
let acc_addr: [u8; 32] = acc_addr_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address from bytes".to_string())
})?;
let utxo_hash_hex_dec = hex::decode(req.utxo_hash.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode hash from hex string".to_string())
})?;
let utxo_hash: [u8; 32] = utxo_hash_hex_dec
.try_into()
.map_err(|_| RpcError::parse_error("Failed to parse hash from bytes".to_string()))?;
let (asset, amount) = {
let cover_guard = self.node_chain_store.lock().await;
{
let mut under_guard = cover_guard.storage.write().await;
let acc = under_guard
.acc_map
.get_mut(&acc_addr)
.ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?;
let utxo = acc
.utxos
.get(&utxo_hash)
.ok_or(RpcError::new_internal_error(
None,
"UTXO does not exist in the tree",
))?;
(utxo.asset.clone(), utxo.amount)
}
};
let helperstruct = ShowAccountUTXOResponse {
hash: req.utxo_hash,
asset,
amount,
};
respond(helperstruct)
}
async fn process_show_transaction(&self, request: Request) -> Result<Value, RpcErr> {
let req = ShowTransactionRequest::parse(Some(request.params))?;
let tx_hash_hex_dec = hex::decode(req.tx_hash.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode hash from hex string".to_string())
})?;
let tx_hash: [u8; 32] = tx_hash_hex_dec
.try_into()
.map_err(|_| RpcError::parse_error("Failed to parse hash from bytes".to_string()))?;
let helperstruct = {
let cover_guard = self.node_chain_store.lock().await;
{
let under_guard = cover_guard.storage.read().await;
let tx = under_guard
.pub_tx_store
.get_tx(tx_hash)
.ok_or(RpcError::new_internal_error(None, TRANSACTION_NOT_FOUND))?;
ShowTransactionResponse {
hash: req.tx_hash,
tx_kind: tx.body().tx_kind,
public_input: if let Ok(action) =
serde_json::from_slice::<ActionData>(&tx.body().execution_input)
{
action.into_hexed_print()
} else {
"".to_string()
},
public_output: if let Ok(action) =
serde_json::from_slice::<ActionData>(&tx.body().execution_output)
{
action.into_hexed_print()
} else {
"".to_string()
},
utxo_commitments_created_hashes: tx
.body()
.utxo_commitments_created_hashes
.iter()
.map(hex::encode)
.collect::<Vec<_>>(),
utxo_commitments_spent_hashes: tx
.body()
.utxo_commitments_spent_hashes
.iter()
.map(hex::encode)
.collect::<Vec<_>>(),
utxo_nullifiers_created_hashes: tx
.body()
.nullifier_created_hashes
.iter()
.map(hex::encode)
.collect::<Vec<_>>(),
encoded_data: tx
.body()
.encoded_data
.iter()
.map(|val| (hex::encode(val.0.clone()), hex::encode(val.1.clone())))
.collect::<Vec<_>>(),
ephemeral_pub_key: hex::encode(tx.body().ephemeral_pub_key.clone()),
}
}
};
respond(helperstruct)
}
pub async fn process_write_mint_utxo(&self, request: Request) -> Result<Value, RpcErr> {
let req = WriteMintPrivateUTXORequest::parse(Some(request.params))?;
let acc_addr_hex_dec = hex::decode(req.account_addr.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode account address from hex string".to_string())
})?;
let acc_addr: [u8; 32] = acc_addr_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address from bytes".to_string())
})?;
let (utxo, commitment_hash) = {
let mut cover_guard = self.node_chain_store.lock().await;
cover_guard
.operate_account_mint_private(acc_addr, req.amount as u128)
.await
.map_err(cast_common_execution_error_into_rpc_error)?
};
let helperstruct = WriteMintPrivateUTXOResponse {
status: SUCCESS.to_string(),
utxo: UTXOShortEssentialStruct {
hash: hex::encode(utxo.hash),
commitment_hash: hex::encode(commitment_hash),
asset: utxo.asset,
},
};
respond(helperstruct)
}
pub async fn process_write_mint_utxo_multiple_assets(
&self,
request: Request,
) -> Result<Value, RpcErr> {
let req = WriteMintPrivateUTXOMultipleAssetsRequest::parse(Some(request.params))?;
let acc_addr_hex_dec = hex::decode(req.account_addr.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode account address from hex string".to_string())
})?;
let acc_addr: [u8; 32] = acc_addr_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address from bytes".to_string())
})?;
let (utxos, commitment_hashes) = {
let mut cover_guard = self.node_chain_store.lock().await;
cover_guard
.operate_account_mint_multiple_assets_private(
acc_addr,
req.amount as u128,
req.num_of_assets,
)
.await
.map_err(cast_common_execution_error_into_rpc_error)?
};
let helperstruct = WriteMintPrivateUTXOMultipleAssetsResponse {
status: SUCCESS.to_string(),
utxos: utxos
.into_iter()
.zip(commitment_hashes)
.map(|(utxo, comm_hash)| UTXOShortEssentialStruct {
hash: hex::encode(utxo.hash),
commitment_hash: hex::encode(comm_hash),
asset: utxo.asset,
})
.collect(),
};
respond(helperstruct)
}
pub async fn process_write_send_private_utxo(&self, request: Request) -> Result<Value, RpcErr> {
let req = WriteSendPrivateUTXORequest::parse(Some(request.params))?;
let acc_addr_hex_dec_sender =
hex::decode(req.account_addr_sender.clone()).map_err(|_| {
RpcError::parse_error(
"Failed to decode account address from hex string".to_string(),
)
})?;
let acc_addr_sender: [u8; 32] = acc_addr_hex_dec_sender.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address from bytes".to_string())
})?;
let acc_addr_hex_dec = hex::decode(req.account_addr_receiver.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode account address from hex string".to_string())
})?;
let acc_addr: [u8; 32] = acc_addr_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address from bytes".to_string())
})?;
let utxo_hash_hex_dec = hex::decode(req.utxo_hash.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode utxo hash from hex string".to_string())
})?;
let utxo_hash: [u8; 32] = utxo_hash_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse utxo hash from bytes".to_string())
})?;
let comm_hash_hex_dec = hex::decode(req.utxo_commitment.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode commitment hash from hex string".to_string())
})?;
let comm_hash: [u8; 32] = comm_hash_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse commitment hash from bytes".to_string())
})?;
let new_utxo_rec = {
let mut cover_guard = self.node_chain_store.lock().await;
let utxo_to_send = {
let mut under_guard = cover_guard.storage.write().await;
let acc = under_guard
.acc_map
.get_mut(&acc_addr_sender)
.ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?;
acc.utxos
.get(&utxo_hash)
.ok_or(RpcError::new_internal_error(
None,
"UTXO does not exist in tree",
))?
.clone()
};
cover_guard
.operate_account_send_private_one_receiver(acc_addr, utxo_to_send, comm_hash)
.await
.map_err(cast_common_execution_error_into_rpc_error)?
};
let helperstruct = WriteSendPrivateUTXOResponse {
status: SUCCESS.to_string(),
utxo_result: UTXOShortEssentialStruct {
hash: hex::encode(new_utxo_rec.hash),
asset: new_utxo_rec.asset.clone(),
commitment_hash: hex::encode(generate_commitments_helper(&[new_utxo_rec])[0]),
},
};
respond(helperstruct)
}
pub async fn process_write_send_shielded_utxo(
&self,
request: Request,
) -> Result<Value, RpcErr> {
let req = WriteSendShieldedUTXORequest::parse(Some(request.params))?;
let acc_addr_hex_dec_sender =
hex::decode(req.account_addr_sender.clone()).map_err(|_| {
RpcError::parse_error(
"Failed to decode account address sender from hex string".to_string(),
)
})?;
let acc_addr_sender: [u8; 32] = acc_addr_hex_dec_sender.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address sender from bytes".to_string())
})?;
let acc_addr_hex_dec_rec =
hex::decode(req.account_addr_receiver.clone()).map_err(|_| {
RpcError::parse_error(
"Failed to decode account address receiver from hex string".to_string(),
)
})?;
let acc_addr_rec: [u8; 32] = acc_addr_hex_dec_rec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address receiver from bytes".to_string())
})?;
let new_utxo_rec = {
let mut cover_guard = self.node_chain_store.lock().await;
cover_guard
.operate_account_send_shielded_one_receiver(
acc_addr_sender,
acc_addr_rec,
req.amount as u128,
)
.await
.map_err(cast_common_execution_error_into_rpc_error)?
};
let helperstruct = WriteSendShieldedUTXOResponse {
status: SUCCESS.to_string(),
utxo_result: UTXOShortEssentialStruct {
hash: hex::encode(new_utxo_rec.hash),
asset: new_utxo_rec.asset.clone(),
commitment_hash: hex::encode(generate_commitments_helper(&[new_utxo_rec])[0]),
},
};
respond(helperstruct)
}
pub async fn process_write_send_deshielded_utxo(
&self,
request: Request,
) -> Result<Value, RpcErr> {
let req = WriteSendDeshieldedBalanceRequest::parse(Some(request.params))?;
let acc_addr_hex_dec_sender =
hex::decode(req.account_addr_sender.clone()).map_err(|_| {
RpcError::parse_error(
"Failed to decode account address from hex string".to_string(),
)
})?;
let acc_addr_sender: [u8; 32] = acc_addr_hex_dec_sender.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address from bytes".to_string())
})?;
let acc_addr_hex_dec = hex::decode(req.account_addr_receiver.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode account address from hex string".to_string())
})?;
let acc_addr: [u8; 32] = acc_addr_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address from bytes".to_string())
})?;
let utxo_hash_hex_dec = hex::decode(req.utxo_hash.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode utxo hash from hex string".to_string())
})?;
let utxo_hash: [u8; 32] = utxo_hash_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse utxo hash from bytes".to_string())
})?;
let comm_hash_hex_dec = hex::decode(req.utxo_commitment.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode commitment hash from hex string".to_string())
})?;
let comm_hash: [u8; 32] = comm_hash_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse commitment hash from bytes".to_string())
})?;
{
let mut cover_guard = self.node_chain_store.lock().await;
let utxo_to_send = {
let mut under_guard = cover_guard.storage.write().await;
let acc = under_guard
.acc_map
.get_mut(&acc_addr_sender)
.ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?;
acc.utxos
.get(&utxo_hash)
.ok_or(RpcError::new_internal_error(
None,
"UTXO does not exist in tree",
))?
.clone()
};
cover_guard
.operate_account_send_deshielded_one_receiver(acc_addr, utxo_to_send, comm_hash)
.await
.map_err(cast_common_execution_error_into_rpc_error)?
};
let helperstruct = WriteSendDeshieldedUTXOResponse {
status: SUCCESS.to_string(),
};
respond(helperstruct)
}
pub async fn process_write_send_split_utxo(&self, request: Request) -> Result<Value, RpcErr> {
let req = WriteSplitUTXORequest::parse(Some(request.params))?;
let acc_addr_hex_dec_sender =
hex::decode(req.account_addr_sender.clone()).map_err(|_| {
RpcError::parse_error(
"Failed to decode account address from hex string".to_string(),
)
})?;
let acc_addr_sender: [u8; 32] = acc_addr_hex_dec_sender.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse account address from bytes".to_string())
})?;
let acc_addresses = {
let mut res_addrs = vec![];
for item in req.account_addr_receivers {
let hex_dec_item = hex::decode(item).map_err(|_| {
RpcError::parse_error(
"Failed to decode account address from hex string".to_string(),
)
})?;
let dec_item = hex_dec_item.try_into().map_err(|_| {
RpcError::parse_error(
"Failed to decode account address from hex string".to_string(),
)
})?;
res_addrs.push(dec_item);
}
res_addrs.try_into().unwrap()
};
let utxo_hash_hex_dec = hex::decode(req.utxo_hash.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode utxo hash from hex string".to_string())
})?;
let utxo_hash: [u8; 32] = utxo_hash_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse utxo hash from bytes".to_string())
})?;
let comm_hash_hex_dec = hex::decode(req.utxo_commitment.clone()).map_err(|_| {
RpcError::parse_error("Failed to decode commitment hash from hex string".to_string())
})?;
let comm_hash: [u8; 32] = comm_hash_hex_dec.try_into().map_err(|_| {
RpcError::parse_error("Failed to parse commitment hash from bytes".to_string())
})?;
let (new_utxos, commitment_hashes) = {
let mut cover_guard = self.node_chain_store.lock().await;
let utxo_to_send = {
let mut under_guard = cover_guard.storage.write().await;
let acc = under_guard
.acc_map
.get_mut(&acc_addr_sender)
.ok_or(RpcError::new_internal_error(None, ACCOUNT_NOT_FOUND))?;
acc.utxos
.get(&utxo_hash)
.ok_or(RpcError::new_internal_error(
None,
"UTXO does not exist in tree",
))?
.clone()
};
cover_guard
.operate_account_send_split_utxo(
acc_addresses,
utxo_to_send,
comm_hash,
req.visibility_list,
)
.await
.map_err(cast_common_execution_error_into_rpc_error)?
};
let helperstruct = WriteSendSplitUTXOResponse {
status: SUCCESS.to_string(),
utxo_results: new_utxos
.into_iter()
.zip(commitment_hashes)
.map(|(utxo, comm_hash)| UTXOShortEssentialStruct {
hash: hex::encode(utxo.hash),
commitment_hash: hex::encode(comm_hash),
asset: utxo.asset,
})
.collect(),
};
respond(helperstruct)
}
pub async fn process_request_internal(&self, request: Request) -> Result<Value, RpcErr> {
match request.method.as_ref() {
//Todo : Add handling of more JSON RPC methods
CREATE_ACCOUNT => self.process_create_account(request).await,
EXECUTE_SUBSCENARIO => self.process_request_execute_subscenario(request).await,
GET_BLOCK => self.process_get_block_data(request).await,
GET_LAST_BLOCK => self.process_get_last_block(request).await,
EXECUTE_SCENARIO_SPLIT => self.process_request_execute_scenario_split(request).await,
EXECUTE_SCENARIO_MULTIPLE_SEND => {
self.process_request_execute_scenario_multiple_send(request)
.await
}
SHOW_ACCOUNT_PUBLIC_BALANCE => self.process_show_account_public_balance(request).await,
SHOW_ACCOUNT_UTXO => self.process_show_account_utxo_request(request).await,
SHOW_TRANSACTION => self.process_show_transaction(request).await,
WRITE_MINT_UTXO => self.process_write_mint_utxo(request).await,
WRITE_MINT_UTXO_MULTIPLE_ASSETS => {
self.process_write_mint_utxo_multiple_assets(request).await
}
WRITE_SEND_UTXO_PRIVATE => self.process_write_send_private_utxo(request).await,
WRITE_SEND_UTXO_SHIELDED => self.process_write_send_shielded_utxo(request).await,
WRITE_SEND_UTXO_DESHIELDED => self.process_write_send_deshielded_utxo(request).await,
WRITE_SPLIT_UTXO => self.process_write_send_split_utxo(request).await,
_ => Err(RpcErr(RpcError::method_not_found(request.method))),
}
}
}

View File

@ -1,85 +0,0 @@
use common::{ExecutionFailureKind, SequencerClientError};
use log::debug;
use common::rpc_primitives::errors::{RpcError, RpcParseError};
pub struct RpcErr(pub RpcError);
pub type RpcErrInternal = anyhow::Error;
pub trait RpcErrKind: 'static {
fn into_rpc_err(self) -> RpcError;
}
impl<T: RpcErrKind> From<T> for RpcErr {
fn from(e: T) -> Self {
Self(e.into_rpc_err())
}
}
macro_rules! standard_rpc_err_kind {
($type_name:path) => {
impl RpcErrKind for $type_name {
fn into_rpc_err(self) -> RpcError {
self.into()
}
}
};
}
standard_rpc_err_kind!(RpcError);
standard_rpc_err_kind!(RpcParseError);
impl RpcErrKind for serde_json::Error {
fn into_rpc_err(self) -> RpcError {
RpcError::serialization_error(&self.to_string())
}
}
impl RpcErrKind for RpcErrInternal {
fn into_rpc_err(self) -> RpcError {
RpcError::new_internal_error(None, &format!("{self:#?}"))
}
}
#[allow(clippy::needless_pass_by_value)]
pub fn from_rpc_err_into_anyhow_err(rpc_err: RpcError) -> anyhow::Error {
debug!("Rpc error cast to anyhow error : err {rpc_err:?}");
anyhow::anyhow!(format!("{rpc_err:#?}"))
}
pub fn cast_seq_client_error_into_rpc_error(seq_cli_err: SequencerClientError) -> RpcError {
let error_string = seq_cli_err.to_string();
match seq_cli_err {
SequencerClientError::SerdeError(_) => RpcError::serialization_error(&error_string),
SequencerClientError::HTTPError(_) => RpcError::new_internal_error(None, &error_string),
SequencerClientError::InternalError(err) => RpcError::new_internal_error(
err.error.data,
&serde_json::to_string(&err.error.error_struct).unwrap_or(String::default()),
),
}
}
pub fn cast_common_execution_error_into_rpc_error(comm_exec_err: ExecutionFailureKind) -> RpcError {
let error_string = comm_exec_err.to_string();
match comm_exec_err {
ExecutionFailureKind::BuilderError(_) => RpcError::new_internal_error(None, &error_string),
ExecutionFailureKind::WriteError(_) => RpcError::new_internal_error(None, &error_string),
ExecutionFailureKind::DBError(_) => RpcError::new_internal_error(None, &error_string),
ExecutionFailureKind::DecodeError(_) => RpcError::new_internal_error(None, &error_string),
ExecutionFailureKind::ProveError(_) => RpcError::new_internal_error(None, &error_string),
ExecutionFailureKind::AmountMismatchError => {
RpcError::new_internal_error(None, &error_string)
}
ExecutionFailureKind::InsufficientGasError => {
RpcError::new_internal_error(None, &error_string)
}
ExecutionFailureKind::InsufficientFundsError => {
RpcError::new_internal_error(None, &error_string)
}
ExecutionFailureKind::SequencerClientError(seq_cli_err) => {
cast_seq_client_error_into_rpc_error(seq_cli_err)
}
}
}

View File

@ -1,2 +0,0 @@
pub mod err_rpc;
pub mod rpc_structs;

View File

@ -1,206 +0,0 @@
use common::parse_request;
use common::rpc_primitives::errors::RpcParseError;
use common::rpc_primitives::parser::parse_params;
use common::rpc_primitives::parser::RpcRequest;
use common::transaction::TxKind;
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Serialize, Deserialize, Debug)]
pub struct ExecuteSubscenarioRequest {
pub scenario_id: u64,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ExecuteScenarioSplitRequest {
pub visibility_list: [bool; 3],
pub publication_index: usize,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ExecuteScenarioMultipleSendRequest {
pub number_of_assets: usize,
pub number_to_send: usize,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ShowAccountPublicBalanceRequest {
pub account_addr: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ShowAccountUTXORequest {
pub account_addr: String,
pub utxo_hash: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ShowTransactionRequest {
pub tx_hash: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct WriteDepositPublicBalanceRequest {
pub account_addr: String,
pub amount: u64,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct WriteMintPrivateUTXORequest {
pub account_addr: String,
pub amount: u64,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct WriteMintPrivateUTXOMultipleAssetsRequest {
pub account_addr: String,
pub num_of_assets: usize,
pub amount: u64,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct WriteSendPrivateUTXORequest {
pub account_addr_sender: String,
pub account_addr_receiver: String,
pub utxo_hash: String,
pub utxo_commitment: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct WriteSendShieldedUTXORequest {
pub account_addr_sender: String,
pub account_addr_receiver: String,
pub amount: u64,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct WriteSendDeshieldedBalanceRequest {
pub account_addr_sender: String,
pub account_addr_receiver: String,
pub utxo_hash: String,
pub utxo_commitment: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct WriteSplitUTXORequest {
pub account_addr_sender: String,
pub account_addr_receivers: [String; 3],
pub visibility_list: [bool; 3],
pub utxo_hash: String,
pub utxo_commitment: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct CreateAccountRequest {}
// parse_request!(GetGenesisIdRequest);
parse_request!(ExecuteSubscenarioRequest);
parse_request!(ExecuteScenarioSplitRequest);
parse_request!(ExecuteScenarioMultipleSendRequest);
// parse_request!(GetLastBlockRequest);
parse_request!(ShowAccountPublicBalanceRequest);
parse_request!(ShowAccountUTXORequest);
parse_request!(ShowTransactionRequest);
parse_request!(WriteDepositPublicBalanceRequest);
parse_request!(WriteMintPrivateUTXORequest);
parse_request!(WriteMintPrivateUTXOMultipleAssetsRequest);
parse_request!(WriteSendPrivateUTXORequest);
parse_request!(WriteSendShieldedUTXORequest);
parse_request!(WriteSendDeshieldedBalanceRequest);
parse_request!(WriteSplitUTXORequest);
parse_request!(CreateAccountRequest);
#[derive(Serialize, Deserialize, Debug)]
pub struct ExecuteSubscenarioResponse {
pub scenario_result: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ExecuteScenarioSplitResponse {
pub scenario_result: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ExecuteScenarioMultipleSendResponse {
pub scenario_result: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ShowAccountPublicBalanceResponse {
pub addr: String,
pub balance: u64,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ShowAccountUTXOResponse {
pub hash: String,
pub asset: Vec<u8>,
pub amount: u128,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ShowTransactionResponse {
pub hash: String,
pub tx_kind: TxKind,
pub public_input: String,
pub public_output: String,
pub utxo_commitments_created_hashes: Vec<String>,
pub utxo_commitments_spent_hashes: Vec<String>,
pub utxo_nullifiers_created_hashes: Vec<String>,
pub encoded_data: Vec<(String, String)>,
pub ephemeral_pub_key: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct WriteDepositPublicBalanceResponse {
pub status: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct UTXOShortEssentialStruct {
pub hash: String,
pub commitment_hash: String,
pub asset: Vec<u8>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct WriteMintPrivateUTXOResponse {
pub status: String,
pub utxo: UTXOShortEssentialStruct,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct WriteMintPrivateUTXOMultipleAssetsResponse {
pub status: String,
pub utxos: Vec<UTXOShortEssentialStruct>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct WriteSendPrivateUTXOResponse {
pub status: String,
pub utxo_result: UTXOShortEssentialStruct,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct WriteSendShieldedUTXOResponse {
pub status: String,
pub utxo_result: UTXOShortEssentialStruct,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct WriteSendDeshieldedUTXOResponse {
pub status: String,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct WriteSendSplitUTXOResponse {
pub status: String,
pub utxo_results: Vec<UTXOShortEssentialStruct>,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct CreateAccountResponse {
pub status: String,
}

View File

@ -1,50 +0,0 @@
[package]
name = "node_runner"
version = "0.1.0"
edition = "2021"
[dependencies]
hex.workspace = true
anyhow.workspace = true
serde_json.workspace = true
env_logger.workspace = true
log.workspace = true
serde.workspace = true
actix.workspace = true
actix-web.workspace = true
tokio.workspace = true
[dependencies.clap]
features = ["derive", "env"]
workspace = true
[dependencies.accounts]
path = "../accounts"
[dependencies.consensus]
path = "../consensus"
[dependencies.networking]
path = "../networking"
[dependencies.storage]
path = "../storage"
[dependencies.utxo]
path = "../utxo"
[dependencies.vm]
path = "../vm"
[dependencies.zkvm]
path = "../zkvm"
[dependencies.node_rpc]
path = "../node_rpc"
[dependencies.node_core]
path = "../node_core"
[dependencies.common]
path = "../common"

View File

@ -1,253 +0,0 @@
{
"home": ".",
"override_rust_log": null,
"sequencer_addr": "http://127.0.0.1:3040",
"seq_poll_timeout_secs": 10,
"port": 3041,
"gas_config": {
"gas_fee_per_byte_deploy": 100,
"gas_fee_per_input_buffer_runtime": 1000,
"gas_fee_per_byte_runtime": 10,
"gas_cost_runtime": 100,
"gas_cost_deploy": 1000,
"gas_limit_deploy": 30000000,
"gas_limit_runtime": 30000000
},
"shapshot_frequency_in_blocks": 10,
"initial_accounts": [
{
"address": [
13,
150,
223,
204,
65,
64,
25,
56,
12,
157,
222,
12,
211,
220,
229,
170,
201,
15,
181,
68,
59,
248,
113,
16,
135,
65,
174,
175,
222,
85,
42,
215
],
"balance": 10000,
"key_holder": {
"address": [
13,
150,
223,
204,
65,
64,
25,
56,
12,
157,
222,
12,
211,
220,
229,
170,
201,
15,
181,
68,
59,
248,
113,
16,
135,
65,
174,
175,
222,
85,
42,
215
],
"nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718",
"pub_account_signing_key": [
133,
143,
177,
187,
252,
66,
237,
236,
234,
252,
244,
138,
5,
151,
3,
99,
217,
231,
112,
217,
77,
211,
58,
218,
176,
68,
99,
53,
152,
228,
198,
190
],
"top_secret_key_holder": {
"secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4"
},
"utxo_secret_key_holder": {
"nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506",
"viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF"
},
"viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6"
},
"utxos": {}
},
{
"address": [
151,
72,
112,
233,
190,
141,
10,
192,
138,
168,
59,
63,
199,
167,
166,
134,
41,
29,
135,
50,
80,
138,
186,
152,
179,
96,
128,
243,
156,
44,
243,
100
],
"balance": 20000,
"key_holder": {
"address": [
151,
72,
112,
233,
190,
141,
10,
192,
138,
168,
59,
63,
199,
167,
166,
134,
41,
29,
135,
50,
80,
138,
186,
152,
179,
96,
128,
243,
156,
44,
243,
100
],
"nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271",
"pub_account_signing_key": [
54,
90,
62,
225,
71,
225,
228,
148,
143,
53,
210,
23,
137,
158,
171,
156,
48,
7,
139,
52,
117,
242,
214,
7,
99,
29,
122,
184,
59,
116,
144,
107
],
"top_secret_key_holder": {
"secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179"
},
"utxo_secret_key_holder": {
"nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122",
"viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7"
},
"viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99"
},
"utxos": {}
}
]
}

View File

@ -1,14 +0,0 @@
use std::path::PathBuf;
use anyhow::Result;
use node_core::config::NodeConfig;
use std::fs::File;
use std::io::BufReader;
pub fn from_file(config_home: PathBuf) -> Result<NodeConfig> {
let file = File::open(config_home)?;
let reader = BufReader::new(file);
Ok(serde_json::from_reader(reader)?)
}

View File

@ -1,56 +0,0 @@
use std::{path::PathBuf, sync::Arc};
use anyhow::Result;
use clap::Parser;
use common::rpc_primitives::RpcConfig;
use consensus::ConsensusManager;
use log::info;
use networking::peer_manager::PeerManager;
use node_core::NodeCore;
use node_rpc::new_http_server;
use tokio::sync::Mutex;
pub mod config;
#[derive(Parser, Debug)]
#[clap(version)]
struct Args {
/// Path to configs
home_dir: PathBuf,
}
pub async fn main_runner() -> Result<()> {
env_logger::init();
let args = Args::parse();
let Args { home_dir } = args;
let app_config = config::from_file(home_dir.join("node_config.json"))?;
let port = app_config.port;
let node_core = NodeCore::start_from_config_update_chain(app_config.clone()).await?;
let wrapped_node_core = Arc::new(Mutex::new(node_core));
let http_server = new_http_server(
RpcConfig::with_port(port),
app_config.clone(),
wrapped_node_core.clone(),
)?;
info!("HTTP server started");
let _http_server_handle = http_server.handle();
tokio::spawn(http_server);
let peer_manager = PeerManager::start_peer_manager(4, 0).await?;
info!("Peer manager mock started");
let peer_manager_shared = Arc::new(Mutex::new(peer_manager));
let _consensus_manager = ConsensusManager::new(peer_manager_shared.clone());
info!("Consensus manger mock started");
#[allow(clippy::empty_loop)]
loop {
//ToDo: Insert activity into main loop
}
}

View File

@ -1,16 +0,0 @@
use anyhow::Result;
use node_runner::main_runner;
pub const NUM_THREADS: usize = 4;
fn main() -> Result<()> {
actix::System::with_tokio_rt(|| {
tokio::runtime::Builder::new_multi_thread()
.worker_threads(NUM_THREADS)
.enable_all()
.build()
.unwrap()
})
.block_on(main_runner())
}

View File

@ -1,4 +1,3 @@
fn main() {
risc0_build::embed_methods();
}

View File

@ -12,8 +12,12 @@ impl Address {
Self { value }
}
pub(crate) fn from_public_key(public_key: &PublicKey) -> Self {
pub fn from_public_key(public_key: &PublicKey) -> Self {
// TODO: implement
Address::new([public_key.0; 32])
}
pub fn value(&self) -> &[u8; 32] {
&self.value
}
}

View File

@ -14,6 +14,7 @@ pub use address::Address;
pub use nssa_core::program::Program;
pub use public_transaction::PublicTransaction;
pub use signature::PrivateKey;
pub use signature::PublicKey;
pub use state::V01State;
pub const AUTHENTICATED_TRANSFER_PROGRAM: Program = Program {

View File

@ -3,7 +3,7 @@ use nssa_core::{
program::ProgramId,
};
use serde::{Deserialize, Serialize};
use sha2::{digest::FixedOutput, Digest};
use sha2::{Digest, digest::FixedOutput};
use crate::{
address::Address,
@ -46,11 +46,11 @@ pub struct WitnessSet {
}
impl WitnessSet {
pub fn for_message(message: &Message, private_keys: &[PrivateKey]) -> Self {
pub fn for_message(message: &Message, private_keys: &[&PrivateKey]) -> Self {
let message_bytes = message.to_bytes();
let signatures_and_public_keys = private_keys
.iter()
.map(|key| (Signature::new(key, &message_bytes), PublicKey::new(key)))
.map(|&key| (Signature::new(key, &message_bytes), PublicKey::new(key)))
.collect();
Self {
signatures_and_public_keys,

View File

@ -6,6 +6,8 @@ use crate::{address::Address, public_transaction::Message};
pub(crate) struct Signature;
// TODO: Dummy impl. Replace by actual private key.
// TODO: Remove Debug, Clone, Serialize, Deserialize, PartialEq and Eq for security reasons
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct PrivateKey(pub(crate) u8);
impl PrivateKey {
@ -16,10 +18,10 @@ impl PrivateKey {
// TODO: Dummy impl. Replace by actual public key.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub(crate) struct PublicKey(pub(crate) u8);
pub struct PublicKey(pub(crate) u8);
impl PublicKey {
pub(crate) fn new(key: &PrivateKey) -> Self {
pub fn new(key: &PrivateKey) -> Self {
// TODO: implement
Self(key.0)
}

View File

@ -158,7 +158,7 @@ mod tests {
let nonces = vec![nonce];
let program_id = AUTHENTICATED_TRANSFER_PROGRAM.id;
let message = public_transaction::Message::new(program_id, addresses, nonces, balance);
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)
}

View File

@ -19,7 +19,7 @@ light-poseidon.workspace = true
ark-bn254.workspace = true
ark-ff.workspace = true
risc0-zkvm = { git = "https://github.com/risc0/risc0.git", branch = "release-2.3" }
risc0-zkvm = "2.3.1"
[dependencies.accounts]
path = "../accounts"

View File

@ -14,7 +14,6 @@ pub fn create_public_transaction_payload(
tweak: Tweak,
secret_r: [u8; 32],
sc_addr: String,
state_changes: (serde_json::Value, usize),
) -> TransactionBody {
TransactionBody {
tx_kind: TxKind::Public,
@ -30,7 +29,6 @@ pub fn create_public_transaction_payload(
tweak,
secret_r,
sc_addr,
state_changes,
}
}

View File

@ -3,7 +3,7 @@ use std::fmt::Display;
use accounts::account_core::address::{self, AccountAddress};
use anyhow::Result;
use common::{
block::{Block, HashableBlockData},
block::HashableBlockData,
execution_input::PublicNativeTokenSend,
merkle_tree_public::TreeHashType,
nullifier::UTXONullifier,
@ -129,7 +129,7 @@ impl SequencerCore {
prev_block_hash,
};
let block = Block::produce_block_from_hashable_data(hashable_data);
let block = hashable_data.into();
self.store.block_store.put_block_at_id(block)?;
@ -144,11 +144,7 @@ mod tests {
use crate::config::AccountInitialData;
use super::*;
use common::transaction::{SignaturePrivateKey, Transaction, TransactionBody, TxKind};
use k256::{ecdsa::SigningKey, FieldBytes};
use nssa::Program;
use secp256k1_zkp::Tweak;
fn setup_sequencer_config_variable_initial_accounts(
initial_accounts: Vec<AccountInitialData>,
@ -196,35 +192,35 @@ mod tests {
setup_sequencer_config_variable_initial_accounts(initial_accounts)
}
fn create_dummy_transaction() -> nssa::PublicTransaction {
let program_id = nssa::AUTHENTICATED_TRANSFER_PROGRAM.id;
let addresses = vec![];
let nonces = vec![];
let instruction_data = 0;
let message =
nssa::public_transaction::Message::new(program_id, addresses, nonces, instruction_data);
let private_key = nssa::PrivateKey::new(1);
let witness_set =
nssa::public_transaction::WitnessSet::for_message(&message, &[private_key]);
nssa::PublicTransaction::new(message, witness_set)
}
fn create_dummy_transaction_native_token_transfer(
from: [u8; 32],
nonce: u128,
to: [u8; 32],
balance_to_move: u128,
signing_key: nssa::PrivateKey,
) -> nssa::PublicTransaction {
let addresses = vec![nssa::Address::new(from), nssa::Address::new(to)];
let nonces = vec![nonce];
let program_id = nssa::AUTHENTICATED_TRANSFER_PROGRAM.id;
let message =
nssa::public_transaction::Message::new(program_id, addresses, nonces, balance_to_move);
let witness_set =
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
nssa::PublicTransaction::new(message, witness_set)
}
// fn create_dummy_transaction() -> nssa::PublicTransaction {
// let program_id = nssa::AUTHENTICATED_TRANSFER_PROGRAM.id;
// let addresses = vec![];
// let nonces = vec![];
// let instruction_data = 0;
// let message =
// nssa::public_transaction::Message::new(program_id, addresses, nonces, instruction_data);
// let private_key = nssa::PrivateKey::new(1);
// let witness_set =
// nssa::public_transaction::WitnessSet::for_message(&message, &[&private_key]);
// nssa::PublicTransaction::new(message, witness_set)
// }
//
// fn create_dummy_transaction_native_token_transfer(
// from: [u8; 32],
// nonce: u128,
// to: [u8; 32],
// balance_to_move: u128,
// signing_key: nssa::PrivateKey,
// ) -> nssa::PublicTransaction {
// let addresses = vec![nssa::Address::new(from), nssa::Address::new(to)];
// let nonces = vec![nonce];
// let program_id = nssa::AUTHENTICATED_TRANSFER_PROGRAM.id;
// let message =
// nssa::public_transaction::Message::new(program_id, addresses, nonces, balance_to_move);
// let witness_set =
// nssa::public_transaction::WitnessSet::for_message(&message, &[&signing_key]);
// nssa::PublicTransaction::new(message, witness_set)
// }
fn create_signing_key_for_account1() -> nssa::PrivateKey {
// let pub_sign_key_acc1 = [
@ -249,7 +245,7 @@ mod tests {
}
fn common_setup(sequencer: &mut SequencerCore) {
let tx = create_dummy_transaction();
let tx = common::test_utils::produce_dummy_empty_transaction();
sequencer.mempool.push_item(tx);
sequencer
@ -353,7 +349,7 @@ mod tests {
common_setup(&mut sequencer);
let tx = create_dummy_transaction();
let tx = common::test_utils::produce_dummy_empty_transaction();
// let tx_roots = sequencer.get_tree_roots();
let result = sequencer.transaction_pre_check(tx);
@ -378,7 +374,9 @@ mod tests {
let sign_key1 = create_signing_key_for_account1();
let tx = create_dummy_transaction_native_token_transfer(acc1, 0, acc2, 10, sign_key1);
let tx = common::test_utils::create_dummy_transaction_native_token_transfer(
acc1, 0, acc2, 10, sign_key1,
);
let result = sequencer.transaction_pre_check(tx);
assert!(result.is_ok());
@ -402,7 +400,9 @@ mod tests {
let sign_key2 = create_signing_key_for_account2();
let tx = create_dummy_transaction_native_token_transfer(acc1, 0, acc2, 10, sign_key2);
let tx = common::test_utils::create_dummy_transaction_native_token_transfer(
acc1, 0, acc2, 10, sign_key2,
);
// let tx_roots = sequencer.get_tree_roots();
let tx = sequencer.transaction_pre_check(tx).unwrap();
@ -429,7 +429,9 @@ mod tests {
let sign_key1 = create_signing_key_for_account1();
let tx = create_dummy_transaction_native_token_transfer(acc1, 0, acc2, 10000000, sign_key1);
let tx = common::test_utils::create_dummy_transaction_native_token_transfer(
acc1, 0, acc2, 10000000, sign_key1,
);
// let tx_roots = sequencer.get_tree_roots();
let result = sequencer.transaction_pre_check(tx);
@ -464,7 +466,9 @@ mod tests {
let sign_key1 = create_signing_key_for_account1();
let tx = create_dummy_transaction_native_token_transfer(acc1, 0, acc2, 100, sign_key1);
let tx = common::test_utils::create_dummy_transaction_native_token_transfer(
acc1, 0, acc2, 100, sign_key1,
);
sequencer.execute_check_transaction_on_state(tx).unwrap();
@ -493,7 +497,7 @@ mod tests {
common_setup(&mut sequencer);
let tx = create_dummy_transaction();
let tx = common::test_utils::produce_dummy_empty_transaction();
// let tx_roots = sequencer.get_tree_roots();
// Fill the mempool
@ -514,8 +518,7 @@ mod tests {
common_setup(&mut sequencer);
let tx = create_dummy_transaction();
// let tx_roots = sequencer.get_tree_roots();
let tx = common::test_utils::produce_dummy_empty_transaction();
let result = sequencer.push_tx_into_mempool_pre_check(tx);
assert!(result.is_ok());
@ -528,7 +531,7 @@ mod tests {
let mut sequencer = SequencerCore::start_from_config(config);
let genesis_height = sequencer.chain_height;
let tx = create_dummy_transaction();
let tx = common::test_utils::produce_dummy_empty_transaction();
sequencer.mempool.push_item(tx);
let block_id = sequencer.produce_new_block_with_mempool_transactions();
@ -554,7 +557,9 @@ mod tests {
let sign_key1 = create_signing_key_for_account1();
let tx = create_dummy_transaction_native_token_transfer(acc1, 0, acc2, 100, sign_key1);
let tx = common::test_utils::create_dummy_transaction_native_token_transfer(
acc1, 0, acc2, 100, sign_key1,
);
let tx_original = tx.clone();
let tx_replay = tx.clone();
@ -594,7 +599,9 @@ mod tests {
let sign_key1 = create_signing_key_for_account1();
let tx = create_dummy_transaction_native_token_transfer(acc1, 0, acc2, 100, sign_key1);
let tx = common::test_utils::create_dummy_transaction_native_token_transfer(
acc1, 0, acc2, 100, sign_key1,
);
// The transaction should be included the first time
sequencer.mempool.push_item(tx.clone());

View File

@ -76,34 +76,33 @@ fn block_to_transactions_map(block: &Block) -> HashMap<TreeHashType, u64> {
#[cfg(test)]
mod tests {
use super::*;
use common::transaction::{SignaturePrivateKey, TransactionBody};
use nssa::Program;
use tempfile::tempdir;
fn create_dummy_block_with_transaction(block_id: u64) -> (Block, nssa::PublicTransaction) {
let program_id = nssa::AUTHENTICATED_TRANSFER_PROGRAM.id;
let addresses = vec![];
let nonces = vec![];
let instruction_data = 0;
let message =
nssa::public_transaction::Message::new(program_id, addresses, nonces, instruction_data);
let private_key = nssa::PrivateKey::new(1);
let witness_set =
nssa::public_transaction::WitnessSet::for_message(&message, &[private_key]);
let tx = nssa::PublicTransaction::new(message, witness_set);
(
Block {
block_id,
prev_block_id: block_id - 1,
prev_block_hash: [0; 32],
hash: [1; 32],
transactions: vec![tx.clone()],
data: vec![],
},
tx,
)
}
//
// fn create_dummy_block_with_transaction(block_id: u64) -> (Block, nssa::PublicTransaction) {
// let program_id = nssa::AUTHENTICATED_TRANSFER_PROGRAM.id;
// let addresses = vec![];
// let nonces = vec![];
// let instruction_data = 0;
// let message =
// nssa::public_transaction::Message::new(program_id, addresses, nonces, instruction_data);
// let private_key = nssa::PrivateKey::new(1);
// let witness_set =
// nssa::public_transaction::WitnessSet::for_message(&message, &[private_key]);
// let tx = nssa::PublicTransaction::new(message, witness_set);
// (
// Block {
// block_id,
// prev_block_id: block_id - 1,
// prev_block_hash: [0; 32],
// hash: [1; 32],
// transactions: vec![tx.clone()],
// data: vec![],
// },
// tx,
// )
// }
//
#[test]
fn test_get_transaction_by_hash() {
let temp_dir = tempdir().unwrap();
@ -119,7 +118,10 @@ mod tests {
// Start an empty node store
let mut node_store =
SequecerBlockStore::open_db_with_genesis(path, Some(genesis_block)).unwrap();
let (block, tx) = create_dummy_block_with_transaction(1);
let tx = common::test_utils::produce_dummy_empty_transaction();
let block = common::test_utils::produce_dummy_block(1, None, vec![tx.clone()], vec![]);
// Try retrieve a tx that's not in the chain yet.
let retrieved_tx = node_store.get_transaction_by_hash(tx.hash());
assert_eq!(None, retrieved_tx);

View File

@ -3,12 +3,12 @@ use std::{collections::HashSet, path::Path};
use accounts::account_core::address::AccountAddress;
use block_store::SequecerBlockStore;
use common::{
block::{Block, HashableBlockData},
block::HashableBlockData,
merkle_tree_public::merkle_tree::{PublicTransactionMerkleTree, UTXOCommitmentsMerkleTree},
nullifier::UTXONullifier,
};
use rand::{rngs::OsRng, RngCore};
use nssa;
use rand::{rngs::OsRng, RngCore};
use crate::config::AccountInitialData;
@ -57,7 +57,7 @@ impl SequecerChainStore {
prev_block_hash,
};
let genesis_block = Block::produce_block_from_hashable_data(hashable_data);
let genesis_block = hashable_data.into();
//Sequencer should panic if unable to open db,
//as fixing this issue may require actions non-native to program scope
@ -67,9 +67,6 @@ impl SequecerChainStore {
)
.unwrap();
Self {
state,
block_store,
}
Self { state, block_store }
}
}

View File

@ -24,12 +24,6 @@ path = "../mempool"
[dependencies.accounts]
path = "../accounts"
[dependencies.consensus]
path = "../consensus"
[dependencies.networking]
path = "../networking"
[dependencies.sequencer_core]
path = "../sequencer_core"

View File

@ -275,7 +275,7 @@ mod tests {
let message =
nssa::public_transaction::Message::new(program_id, addresses, nonces, balance_to_move);
let witness_set =
nssa::public_transaction::WitnessSet::for_message(&message, &[signing_key]);
nssa::public_transaction::WitnessSet::for_message(&message, &[&signing_key]);
let tx = nssa::PublicTransaction::new(message, witness_set);
sequencer_core

View File

@ -22,12 +22,6 @@ workspace = true
[dependencies.mempool]
path = "../mempool"
[dependencies.consensus]
path = "../consensus"
[dependencies.networking]
path = "../networking"
[dependencies.sequencer_rpc]
path = "../sequencer_rpc"

View File

@ -1,11 +0,0 @@
[package]
name = "vm"
version = "0.1.0"
edition = "2021"
[dependencies]
anyhow.workspace = true
serde_json.workspace = true
env_logger.workspace = true
log.workspace = true
serde.workspace = true

View File

@ -1 +0,0 @@
//ToDo: Add vm module

View File

@ -1,5 +1,5 @@
[package]
name = "node_core"
name = "wallet"
version = "0.1.0"
edition = "2021"
@ -18,9 +18,10 @@ reqwest.workspace = true
thiserror.workspace = true
tokio.workspace = true
tempfile.workspace = true
risc0-zkvm = { git = "https://github.com/risc0/risc0.git", branch = "release-2.3" }
risc0-zkvm = "2.3.1"
hex.workspace = true
actix-rt.workspace = true
clap.workspace = true
[dependencies.sc_core]
path = "../sc_core"
@ -28,15 +29,15 @@ path = "../sc_core"
[dependencies.accounts]
path = "../accounts"
[dependencies.storage]
path = "../storage"
[dependencies.utxo]
path = "../utxo"
[dependencies.zkvm]
path = "../zkvm"
[dependencies.nssa]
path = "../nssa"
[dependencies.common]
path = "../common"

View File

@ -0,0 +1,164 @@
use std::collections::{BTreeMap, HashMap, HashSet};
use accounts::account_core::{address::AccountAddress, Account};
use anyhow::Result;
use common::{
merkle_tree_public::merkle_tree::{PublicTransactionMerkleTree, UTXOCommitmentsMerkleTree},
nullifier::UTXONullifier,
};
use sc_core::public_context::PublicSCContext;
use serde::{Deserialize, Serialize};
use crate::config::NodeConfig;
pub mod accounts_store;
#[derive(Deserialize, Serialize)]
pub struct AccMap {
pub acc_map: HashMap<String, Account>,
}
impl From<HashMap<[u8; 32], Account>> for AccMap {
fn from(value: HashMap<[u8; 32], Account>) -> Self {
AccMap {
acc_map: value
.into_iter()
.map(|(key, val)| (hex::encode(key), val))
.collect(),
}
}
}
impl From<AccMap> for HashMap<[u8; 32], Account> {
fn from(value: AccMap) -> Self {
value
.acc_map
.into_iter()
.map(|(key, val)| (hex::decode(key).unwrap().try_into().unwrap(), val))
.collect()
}
}
pub struct NodeChainStore {
pub acc_map: HashMap<AccountAddress, Account>,
pub nullifier_store: HashSet<UTXONullifier>,
pub utxo_commitments_store: UTXOCommitmentsMerkleTree,
pub pub_tx_store: PublicTransactionMerkleTree,
pub node_config: NodeConfig,
}
impl NodeChainStore {
pub fn new(config: NodeConfig) -> Result<Self> {
let acc_map = HashMap::new();
let nullifier_store = HashSet::new();
let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]);
let pub_tx_store = PublicTransactionMerkleTree::new(vec![]);
Ok(Self {
acc_map,
nullifier_store,
utxo_commitments_store,
pub_tx_store,
node_config: config,
})
}
pub fn produce_context(&self, caller: AccountAddress) -> PublicSCContext {
let mut account_masks = BTreeMap::new();
for (acc_addr, acc) in &self.acc_map {
account_masks.insert(*acc_addr, acc.make_account_public_mask());
}
PublicSCContext {
caller_address: caller,
caller_balance: self.acc_map.get(&caller).unwrap().balance,
account_masks,
comitment_store_root: self.utxo_commitments_store.get_root().unwrap_or([0; 32]),
pub_tx_store_root: self.pub_tx_store.get_root().unwrap_or([0; 32]),
nullifiers_set: self
.nullifier_store
.iter()
.map(|item| item.utxo_hash)
.collect(),
commitments_tree: self.utxo_commitments_store.clone(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use accounts::account_core::Account;
use std::path::PathBuf;
use tempfile::tempdir;
fn create_initial_accounts() -> Vec<Account> {
let initial_acc1 = serde_json::from_str(r#"{
"address": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
"balance": 100,
"key_holder": {
"nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718",
"pub_account_signing_key": 1,
"top_secret_key_holder": {
"secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4"
},
"utxo_secret_key_holder": {
"nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506",
"viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF"
},
"viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6"
},
"utxos": {}
}"#).unwrap();
let initial_acc2 = serde_json::from_str(r#"{
"address": [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
"balance": 200,
"key_holder": {
"nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271",
"pub_account_signing_key": 2,
"top_secret_key_holder": {
"secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179"
},
"utxo_secret_key_holder": {
"nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122",
"viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7"
},
"viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99"
},
"utxos": {}
}"#).unwrap();
let initial_accounts = vec![initial_acc1, initial_acc2];
initial_accounts
}
fn create_sample_node_config(home: PathBuf) -> NodeConfig {
NodeConfig {
home,
override_rust_log: None,
sequencer_addr: "http://127.0.0.1".to_string(),
seq_poll_timeout_secs: 1,
initial_accounts: create_initial_accounts(),
}
}
#[test]
fn test_new_initializes_correctly() {
let temp_dir = tempdir().unwrap();
let path = temp_dir.path();
let config = create_sample_node_config(path.to_path_buf());
let store = NodeChainStore::new(config.clone()).unwrap();
assert!(store.acc_map.is_empty());
assert!(store.nullifier_store.is_empty());
assert_eq!(
store.utxo_commitments_store.get_root().unwrap_or([0; 32]),
[0; 32]
);
}
}

View File

@ -46,12 +46,6 @@ pub struct NodeConfig {
pub sequencer_addr: String,
///Sequencer polling duration for new blocks in seconds
pub seq_poll_timeout_secs: u64,
///Port to listen
pub port: u16,
///Gas config
pub gas_config: GasConfig,
///Frequency of snapshots
pub shapshot_frequency_in_blocks: u64,
///Initial accounts for wallet
pub initial_accounts: Vec<Account>,
}

View File

@ -0,0 +1,43 @@
use std::{fs::File, io::BufReader, path::PathBuf, str::FromStr};
use anyhow::{anyhow, Result};
use crate::{config::NodeConfig, HOME_DIR_ENV_VAR};
pub fn vec_u8_to_vec_u64(bytes: Vec<u8>) -> Vec<u64> {
// Pad with zeros to make sure it's a multiple of 8
let mut padded = bytes.clone();
while !padded.len().is_multiple_of(8) {
padded.push(0);
}
padded
.chunks(8)
.map(|chunk| {
let mut array = [0u8; 8];
array.copy_from_slice(chunk);
u64::from_le_bytes(array)
})
.collect()
}
///Get home dir for wallet. Env var `NSSA_WALLET_HOME_DIR` must be set before execution to succeed.
pub fn get_home() -> Result<PathBuf> {
Ok(PathBuf::from_str(&std::env::var(HOME_DIR_ENV_VAR)?)?)
}
///Fetch config from `NSSA_WALLET_HOME_DIR`
pub fn fetch_config() -> Result<NodeConfig> {
let config_home = get_home()?;
let file = File::open(config_home.join("node_config.json"))?;
let reader = BufReader::new(file);
Ok(serde_json::from_reader(reader)?)
}
//ToDo: Replace with structures conversion in future
pub fn produce_account_addr_from_hex(hex_str: String) -> Result<[u8; 32]> {
hex::decode(hex_str)?
.try_into()
.map_err(|_| anyhow!("Failed conversion to 32 bytes"))
}

162
wallet/src/lib.rs Normal file
View File

@ -0,0 +1,162 @@
use std::sync::Arc;
use common::{
execution_input::PublicNativeTokenSend,
sequencer_client::{json::SendTxResponse, SequencerClient},
transaction::Transaction,
ExecutionFailureKind,
};
use accounts::account_core::{address::AccountAddress, Account};
use anyhow::Result;
use chain_storage::NodeChainStore;
use common::transaction::TransactionBody;
use config::NodeConfig;
use log::info;
use sc_core::proofs_circuits::pedersen_commitment_vec;
use tokio::sync::RwLock;
use clap::{Parser, Subcommand};
use nssa;
use crate::helperfunctions::{fetch_config, produce_account_addr_from_hex};
pub const HOME_DIR_ENV_VAR: &str = "NSSA_WALLET_HOME_DIR";
pub const BLOCK_GEN_DELAY_SECS: u64 = 20;
pub mod chain_storage;
pub mod config;
pub mod helperfunctions;
pub mod requests_structs;
pub struct NodeCore {
pub storage: Arc<RwLock<NodeChainStore>>,
pub node_config: NodeConfig,
pub sequencer_client: Arc<SequencerClient>,
}
impl NodeCore {
pub async fn start_from_config_update_chain(config: NodeConfig) -> Result<Self> {
let client = Arc::new(SequencerClient::new(config.sequencer_addr.clone())?);
let mut storage = NodeChainStore::new(config.clone())?;
for acc in config.clone().initial_accounts {
storage.acc_map.insert(acc.address, acc);
}
let wrapped_storage = Arc::new(RwLock::new(storage));
Ok(Self {
storage: wrapped_storage,
node_config: config.clone(),
sequencer_client: client.clone(),
})
}
pub async fn get_roots(&self) -> [[u8; 32]; 2] {
let storage = self.storage.read().await;
[
storage.utxo_commitments_store.get_root().unwrap_or([0; 32]),
storage.pub_tx_store.get_root().unwrap_or([0; 32]),
]
}
pub async fn create_new_account(&mut self) -> AccountAddress {
let account = Account::new();
account.log();
let addr = account.address;
{
let mut write_guard = self.storage.write().await;
write_guard.acc_map.insert(account.address, account);
}
addr
}
pub async fn send_public_native_token_transfer(
&self,
from: AccountAddress,
nonce: u128,
to: AccountAddress,
balance_to_move: u128,
) -> Result<SendTxResponse, ExecutionFailureKind> {
{
let read_guard = self.storage.read().await;
let account = read_guard.acc_map.get(&from);
if let Some(account) = account {
let addresses = vec![nssa::Address::new(from), nssa::Address::new(to)];
let nonces = vec![nonce];
let program_id = nssa::AUTHENTICATED_TRANSFER_PROGRAM.id;
let message = nssa::public_transaction::Message::new(
program_id,
addresses,
nonces,
balance_to_move,
);
let signing_key = account.key_holder.get_pub_account_signing_key();
let witness_set =
nssa::public_transaction::WitnessSet::for_message(&message, &[&signing_key]);
let tx = nssa::PublicTransaction::new(message, witness_set);
Ok(self.sequencer_client.send_tx(tx).await?)
} else {
Err(ExecutionFailureKind::AmountMismatchError)
}
}
}
}
///Represents CLI command for a wallet
#[derive(Subcommand, Debug, Clone)]
#[clap(about)]
pub enum Command {
SendNativeTokenTransfer {
///from - valid 32 byte hex string
#[arg(long)]
from: String,
///to - valid 32 byte hex string
#[arg(long)]
to: String,
///amount - amount of balance to move
#[arg(long)]
amount: u128,
},
}
///To execute commands, env var NSSA_WALLET_HOME_DIR must be set into directory with config
#[derive(Parser, Debug)]
#[clap(version, about)]
pub struct Args {
/// Wallet command
#[command(subcommand)]
pub command: Command,
}
pub async fn execute_subcommand(command: Command) -> Result<()> {
match command {
Command::SendNativeTokenTransfer { from, to, amount } => {
let node_config = fetch_config()?;
let from = produce_account_addr_from_hex(from)?;
let to = produce_account_addr_from_hex(to)?;
let wallet_core = NodeCore::start_from_config_update_chain(node_config).await?;
//ToDo: Nonce management
let res = wallet_core
.send_public_native_token_transfer(from, 0, to, amount)
.await?;
info!("Results of tx send is {res:#?}");
}
}
Ok(())
}

24
wallet/src/main.rs Normal file
View File

@ -0,0 +1,24 @@
use anyhow::Result;
use clap::Parser;
use tokio::runtime::Builder;
use wallet::{execute_subcommand, Args};
pub const NUM_THREADS: usize = 2;
fn main() -> Result<()> {
let runtime = Builder::new_multi_thread()
.worker_threads(NUM_THREADS)
.enable_all()
.build()
.unwrap();
let args = Args::parse();
env_logger::init();
runtime.block_on(async move {
execute_subcommand(args.command).await.unwrap();
});
Ok(())
}

View File

@ -0,0 +1,33 @@
use accounts::account_core::address::AccountAddress;
use serde::{Deserialize, Serialize};
use utxo::utxo_core::UTXO;
#[derive(Debug, Serialize, Deserialize)]
pub struct MintMoneyPublicTx {
pub acc: AccountAddress,
pub amount: u128,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SendMoneyShieldedTx {
pub acc_sender: AccountAddress,
pub amount: u128,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct SendMoneyDeshieldedTx {
pub receiver_data: Vec<(u128, AccountAddress)>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct UTXOPublication {
pub utxos: Vec<UTXO>,
}
#[derive(Debug, Serialize, Deserialize)]
pub enum ActionData {
MintMoneyPublicTx(MintMoneyPublicTx),
SendMoneyShieldedTx(SendMoneyShieldedTx),
SendMoneyDeshieldedTx(SendMoneyDeshieldedTx),
UTXOPublication(UTXOPublication),
}

View File

@ -12,7 +12,7 @@ serde.workspace = true
thiserror.workspace = true
rand.workspace = true
risc0-zkvm = { git = "https://github.com/risc0/risc0.git", branch = "release-2.3" }
risc0-zkvm = "2.3.1"
test-methods = { path = "test_methods" }
[dependencies.accounts]