adapt sequencer to use nssa

This commit is contained in:
Sergio Chouhy 2025-08-07 15:19:06 -03:00
parent ae9963aec3
commit ec909a1625
20 changed files with 320 additions and 767 deletions

294
Cargo.lock generated
View File

@ -147,7 +147,6 @@ version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24eda4e2a6e042aa4e55ac438a2ae052d3b5da0ecf83d7411e1a368946925208"
dependencies = [
"actix-macros",
"futures-core",
"tokio",
]
@ -627,17 +626,6 @@ dependencies = [
"critical-section",
]
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi 0.1.19",
"libc",
"winapi",
]
[[package]]
name = "auto_ops"
version = "0.3.0"
@ -972,45 +960,6 @@ dependencies = [
"libloading",
]
[[package]]
name = "clap"
version = "3.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
dependencies = [
"atty",
"bitflags 1.3.2",
"clap_derive",
"clap_lex",
"indexmap 1.9.3",
"once_cell",
"strsim 0.10.0",
"termcolor",
"textwrap",
]
[[package]]
name = "clap_derive"
version = "3.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008"
dependencies = [
"heck 0.4.1",
"proc-macro-error",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "clap_lex"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "cobs"
version = "0.3.0"
@ -1029,6 +978,7 @@ dependencies = [
"hex",
"k256",
"log",
"nssa",
"reqwest 0.11.27",
"risc0-zkvm 2.3.1 (git+https://github.com/risc0/risc0.git?branch=release-2.3)",
"rs_merkle",
@ -1262,7 +1212,7 @@ dependencies = [
"ident_case",
"proc-macro2",
"quote",
"strsim 0.11.1",
"strsim",
"syn 2.0.104",
]
@ -1952,13 +1902,19 @@ dependencies = [
"futures-sink",
"futures-util",
"http 0.2.12",
"indexmap 2.10.0",
"indexmap",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]]
name = "half"
version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403"
[[package]]
name = "hash32"
version = "0.2.1"
@ -2030,15 +1986,6 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "hermit-abi"
version = "0.5.2"
@ -2365,16 +2312,6 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ee796ad498c8d9a1d68e477df8f754ed784ef875de1414ebdaf169f70a6a784"
[[package]]
name = "indexmap"
version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
]
[[package]]
name = "indexmap"
version = "2.10.0"
@ -2394,32 +2331,6 @@ dependencies = [
"generic-array",
]
[[package]]
name = "integration_tests"
version = "0.1.0"
dependencies = [
"accounts",
"actix",
"actix-web",
"anyhow",
"clap",
"common",
"env_logger",
"hex",
"log",
"node_core",
"node_rpc",
"node_runner",
"sequencer_core",
"sequencer_rpc",
"sequencer_runner",
"serde",
"serde_json",
"tempfile",
"tokio",
"toml 0.7.8",
]
[[package]]
name = "inventory"
version = "0.3.20"
@ -2462,7 +2373,7 @@ version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9"
dependencies = [
"hermit-abi 0.5.2",
"hermit-abi",
"libc",
"windows-sys 0.59.0",
]
@ -2973,88 +2884,6 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5b0c77c1b780822bc749a33e39aeb2c07584ab93332303babeabb645298a76e"
[[package]]
name = "node_core"
version = "0.1.0"
dependencies = [
"accounts",
"actix-rt",
"anyhow",
"bincode",
"common",
"elliptic-curve",
"env_logger",
"hex",
"k256",
"log",
"rand 0.8.5",
"reqwest 0.11.27",
"risc0-zkvm 2.3.1 (git+https://github.com/risc0/risc0.git?branch=release-2.3)",
"sc_core",
"secp256k1-zkp",
"serde",
"serde_json",
"sha2",
"storage",
"tempfile",
"thiserror 1.0.69",
"tokio",
"utxo",
"zkvm",
]
[[package]]
name = "node_rpc"
version = "0.1.0"
dependencies = [
"accounts",
"actix",
"actix-cors",
"actix-web",
"anyhow",
"common",
"consensus",
"env_logger",
"futures",
"hex",
"log",
"networking",
"node_core",
"serde",
"serde_json",
"storage",
"tokio",
"utxo",
"vm",
"zkvm",
]
[[package]]
name = "node_runner"
version = "0.1.0"
dependencies = [
"accounts",
"actix",
"actix-web",
"anyhow",
"clap",
"common",
"consensus",
"env_logger",
"hex",
"log",
"networking",
"node_core",
"node_rpc",
"serde",
"serde_json",
"storage",
"tokio",
"utxo",
"vm",
"zkvm",
]
[[package]]
name = "nom"
version = "7.1.3"
@ -3072,6 +2901,9 @@ dependencies = [
"nssa-core",
"program-methods",
"risc0-zkvm 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde",
"serde_cbor",
"sha2",
]
[[package]]
@ -3248,12 +3080,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "os_str_bytes"
version = "6.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
[[package]]
name = "parking_lot"
version = "0.12.4"
@ -3412,7 +3238,7 @@ version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35"
dependencies = [
"toml_edit 0.22.27",
"toml_edit",
]
[[package]]
@ -4510,7 +4336,7 @@ dependencies = [
"strum",
"tempfile",
"thiserror 2.0.12",
"toml 0.8.23",
"toml",
"yaml-rust2",
]
@ -4524,7 +4350,7 @@ dependencies = [
"strum",
"tempfile",
"thiserror 2.0.12",
"toml 0.8.23",
"toml",
"yaml-rust2",
]
@ -4672,6 +4498,7 @@ dependencies = [
"k256",
"log",
"mempool",
"nssa",
"rand 0.8.5",
"secp256k1-zkp",
"serde",
@ -4698,6 +4525,7 @@ dependencies = [
"log",
"mempool",
"networking",
"nssa",
"sequencer_core",
"serde",
"serde_json",
@ -4706,28 +4534,6 @@ dependencies = [
"tokio",
]
[[package]]
name = "sequencer_runner"
version = "0.1.0"
dependencies = [
"actix",
"actix-web",
"anyhow",
"clap",
"common",
"consensus",
"env_logger",
"log",
"mempool",
"networking",
"sequencer_core",
"sequencer_rpc",
"serde",
"serde_json",
"tokio",
"toml 0.7.8",
]
[[package]]
name = "serde"
version = "1.0.219"
@ -4737,6 +4543,16 @@ dependencies = [
"serde_derive",
]
[[package]]
name = "serde_cbor"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
dependencies = [
"half",
"serde",
]
[[package]]
name = "serde_derive"
version = "1.0.219"
@ -4953,12 +4769,6 @@ dependencies = [
"thiserror 1.0.69",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "strsim"
version = "0.11.1"
@ -5097,12 +4907,6 @@ dependencies = [
"risc0-build 2.3.1 (git+https://github.com/risc0/risc0.git?branch=release-2.3)",
]
[[package]]
name = "textwrap"
version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057"
[[package]]
name = "thiserror"
version = "1.0.69"
@ -5260,18 +5064,6 @@ dependencies = [
"tokio",
]
[[package]]
name = "toml"
version = "0.7.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit 0.19.15",
]
[[package]]
name = "toml"
version = "0.8.23"
@ -5281,7 +5073,7 @@ dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit 0.22.27",
"toml_edit",
]
[[package]]
@ -5293,31 +5085,18 @@ dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [
"indexmap 2.10.0",
"serde",
"serde_spanned",
"toml_datetime",
"winnow 0.5.40",
]
[[package]]
name = "toml_edit"
version = "0.22.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
dependencies = [
"indexmap 2.10.0",
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"toml_write",
"winnow 0.7.12",
"winnow",
]
[[package]]
@ -5974,15 +5753,6 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
[[package]]
name = "winnow"
version = "0.5.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
dependencies = [
"memchr",
]
[[package]]
name = "winnow"
version = "0.7.12"
@ -6175,7 +5945,7 @@ dependencies = [
"crossbeam-utils",
"displaydoc",
"flate2",
"indexmap 2.10.0",
"indexmap",
"memchr",
"thiserror 2.0.12",
"zopfli",

View File

@ -1,23 +1,19 @@
[workspace]
resolver = "2"
members = [
"node_runner",
"sequencer_runner",
# "sequencer_runner",
"storage",
"accounts",
"utxo",
"vm",
"networking",
"consensus",
"node_rpc",
"sequencer_rpc",
"mempool",
"zkvm",
"node_core",
"sequencer_core",
"common",
"sc_core",
"integration_tests",
"nssa",
]

View File

@ -21,3 +21,6 @@ hex.workspace = true
[dependencies.secp256k1-zkp]
workspace = true
features = ["std", "rand-std", "rand", "serde", "global-context"]
[dependencies.nssa]
path = "../nssa"

View File

@ -2,6 +2,7 @@ use rs_merkle::Hasher;
use serde::{Deserialize, Serialize};
use crate::{merkle_tree_public::hasher::OwnHasher, transaction::Transaction};
use nssa;
pub type BlockHash = [u8; 32];
pub type Data = Vec<u8>;
@ -13,7 +14,7 @@ pub struct Block {
pub prev_block_id: BlockId,
pub prev_block_hash: BlockHash,
pub hash: BlockHash,
pub transactions: Vec<Transaction>,
pub transactions: Vec<nssa::PublicTransaction>,
pub data: Data,
}
@ -22,7 +23,7 @@ pub struct HashableBlockData {
pub block_id: BlockId,
pub prev_block_id: BlockId,
pub prev_block_hash: BlockHash,
pub transactions: Vec<Transaction>,
pub transactions: Vec<nssa::PublicTransaction>,
pub data: Data,
}

View File

@ -18,7 +18,7 @@ pub struct RegisterAccountRequest {
#[derive(Serialize, Deserialize, Debug)]
pub struct SendTxRequest {
pub transaction: Transaction,
pub transaction: nssa::PublicTransaction,
///UTXO Commitment Root, Pub Tx Root
pub tx_roots: [[u8; 32]; 2],
}
@ -89,10 +89,10 @@ pub struct GetLastBlockResponse {
#[derive(Serialize, Deserialize, Debug)]
pub struct GetAccountBalanceResponse {
pub balance: u64,
pub balance: u128,
}
#[derive(Serialize, Deserialize, Debug)]
pub struct GetTransactionByHashResponse {
pub transaction: Option<Transaction>,
pub transaction: Option<nssa::PublicTransaction>,
}

View File

@ -7,3 +7,6 @@ edition = "2024"
risc0-zkvm = "2.2"
nssa-core = {path="core"}
program-methods = { path = "program_methods" }
serde = "1.0.219"
serde_cbor = "0.11.2"
sha2 = "0.10.9"

View File

@ -11,7 +11,7 @@ pub type Nonce = u128;
type Data = Vec<u8>;
/// Account to be used both in public and private contexts
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Account {
pub program_owner: ProgramId,
pub balance: u128,

View File

@ -1,12 +1,14 @@
use serde::{Deserialize, Serialize};
use crate::signature::PublicKey;
#[derive(Clone, Hash, PartialEq, Eq)]
pub(crate) struct Address {
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub struct Address {
pub(crate) value: [u8; 32],
}
impl Address {
pub(crate) fn new(value: [u8; 32]) -> Self {
pub fn new(value: [u8; 32]) -> Self {
Self { value }
}

View File

@ -1,16 +1,22 @@
use nssa_core::{
account::{Account, AccountWithMetadata},
program::{Program, ProgramId},
program::ProgramId,
};
use program_methods::{AUTHENTICATED_TRANSFER_ELF, AUTHENTICATED_TRANSFER_ID};
use risc0_zkvm::{ExecutorEnv, ExecutorEnvBuilder, default_executor};
mod address;
mod public_transaction;
pub mod public_transaction;
mod signature;
pub mod state;
mod state;
struct AuthenticatedTransferProgram;
pub use address::Address;
pub use nssa_core::program::Program;
pub use public_transaction::PublicTransaction;
pub use signature::PrivateKey;
pub use state::V01State;
pub struct AuthenticatedTransferProgram;
impl Program for AuthenticatedTransferProgram {
const PROGRAM_ID: ProgramId = AUTHENTICATED_TRANSFER_ID;
const PROGRAM_ELF: &[u8] = AUTHENTICATED_TRANSFER_ELF;

View File

@ -2,13 +2,16 @@ use nssa_core::{
account::{Account, Nonce},
program::ProgramId,
};
use serde::{Deserialize, Serialize};
use sha2::{digest::FixedOutput, Digest};
use crate::{
address::Address,
signature::{PrivateKey, PublicKey, Signature},
};
pub(crate) struct Message {
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Message {
pub(crate) program_id: ProgramId,
pub(crate) addresses: Vec<Address>,
pub(crate) nonces: Vec<Nonce>,
@ -17,7 +20,7 @@ pub(crate) struct Message {
}
impl Message {
pub(crate) fn new(
pub fn new(
program_id: ProgramId,
addresses: Vec<Address>,
nonces: Vec<Nonce>,
@ -37,12 +40,13 @@ impl Message {
}
}
pub(crate) struct WitnessSet {
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct WitnessSet {
pub(crate) signatures_and_public_keys: Vec<(Signature, PublicKey)>,
}
impl WitnessSet {
pub(crate) 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()
@ -54,17 +58,18 @@ impl WitnessSet {
}
}
pub(crate) struct PublicTransaction {
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct PublicTransaction {
message: Message,
witness_set: WitnessSet,
}
impl PublicTransaction {
pub(crate) fn message(&self) -> &Message {
pub fn message(&self) -> &Message {
&self.message
}
pub(crate) fn witness_set(&self) -> &WitnessSet {
pub fn witness_set(&self) -> &WitnessSet {
&self.witness_set
}
@ -76,10 +81,17 @@ impl PublicTransaction {
.collect()
}
pub(crate) fn new(message: Message, witness_set: WitnessSet) -> Self {
pub fn new(message: Message, witness_set: WitnessSet) -> Self {
Self {
message,
witness_set,
}
}
pub fn hash(&self) -> [u8; 32] {
let bytes = serde_cbor::to_vec(&self).unwrap();
let mut hasher = sha2::Sha256::new();
hasher.update(&bytes);
hasher.finalize_fixed().try_into().unwrap()
}
}

View File

@ -1,10 +1,21 @@
use serde::{Deserialize, Serialize};
use crate::{address::Address, public_transaction::Message};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub(crate) struct Signature;
// TODO: Dummy impl. Replace by actual private key.
pub(crate) struct PrivateKey(pub(crate) u8);
pub struct PrivateKey(pub(crate) u8);
impl PrivateKey {
pub fn new(dummy_value: u8) -> Self {
Self(dummy_value)
}
}
// TODO: Dummy impl. Replace by actual public key.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub(crate) struct PublicKey(pub(crate) u8);
impl PublicKey {

View File

@ -8,12 +8,28 @@ use nssa_core::{
};
use std::collections::{HashMap, HashSet};
struct V01State {
pub struct V01State {
public_state: HashMap<Address, Account>,
}
impl V01State {
fn transition_from_public_transaction(&mut self, tx: PublicTransaction) -> Result<(), ()> {
pub fn new_with_genesis_accounts(initial_data: &[([u8; 32], u128)]) -> Self {
// TODO:: remove this assert?
let public_state = initial_data
.to_owned()
.into_iter()
.map(|(address_value, balance)| {
let mut account = Account::default();
account.balance = balance;
account.program_owner = AuthenticatedTransferProgram::PROGRAM_ID;
let address = Address::new(address_value);
(address, account)
})
.collect();
Self { public_state }
}
pub fn transition_from_public_transaction(&mut self, tx: &PublicTransaction) -> Result<(), ()> {
let state_diff = self
.execute_and_verify_public_transaction(&tx)
.map_err(|_| ())?;
@ -36,7 +52,7 @@ impl V01State {
.or_insert_with(Account::default)
}
fn get_account_by_address(&self, address: &Address) -> Account {
pub fn get_account_by_address(&self, address: &Address) -> Account {
self.public_state
.get(address)
.cloned()
@ -123,26 +139,6 @@ mod tests {
use super::*;
use crate::{public_transaction, signature::PrivateKey};
fn genesis_state_for_tests(balances: &[u128], addresses: &[Address]) -> V01State {
assert_eq!(balances.len(), addresses.len());
let accounts: Vec<Account> = balances
.iter()
.map(|balance| {
let mut account = Account::default();
account.balance = *balance;
account.program_owner = AuthenticatedTransferProgram::PROGRAM_ID;
account
})
.collect();
let public_state = addresses
.to_owned()
.into_iter()
.zip(accounts.into_iter())
.collect();
V01State { public_state }
}
fn transfer_transaction_for_tests(
from: Address,
from_key: PrivateKey,
@ -160,23 +156,22 @@ mod tests {
#[test]
fn test_1() {
let addresses = [Address::new([1; 32])];
let balances = [100];
let mut genesis_state = genesis_state_for_tests(&balances, &addresses);
let from = addresses[0].clone();
let initial_data = [([1; 32], 100)];
let mut genesis_state = V01State::new_with_genesis_accounts(&initial_data);
let from = Address::new(initial_data[0].0.clone());
let from_key = PrivateKey(1);
let to = Address::new([2; 32]);
let balance_to_move = 5;
let tx =
transfer_transaction_for_tests(from.clone(), from_key, 0, to.clone(), balance_to_move);
let _ = genesis_state.transition_from_public_transaction(tx);
let _ = genesis_state.transition_from_public_transaction(&tx);
assert_eq!(
genesis_state.get_account_by_address(&to).balance,
balance_to_move
);
assert_eq!(
genesis_state.get_account_by_address(&from).balance,
balances[0] - balance_to_move
initial_data[0].1 - balance_to_move
);
assert_eq!(genesis_state.get_account_by_address(&from).nonce, 1);
assert_eq!(genesis_state.get_account_by_address(&to).nonce, 0);
@ -184,20 +179,20 @@ mod tests {
#[test]
fn test_2() {
let addresses = [Address::new([1; 32]), Address::new([99; 32])];
let balances = [100, 200];
let mut genesis_state = genesis_state_for_tests(&balances, &addresses);
let from = addresses[1].clone();
let initial_data = [([1; 32], 100), ([99; 32], 200)];
let mut genesis_state = V01State::new_with_genesis_accounts(&initial_data);
let from = Address::new(initial_data[1].0.clone());
let from_key = PrivateKey(99);
let to = addresses[0].clone();
let to = Address::new(initial_data[0].0.clone());
let balance_to_move = 8;
let to_previous_balance = genesis_state.get_account_by_address(&to).balance;
let tx = transfer_transaction_for_tests(from.clone(), from_key, 0, to.clone(), balance_to_move);
let _ = genesis_state.transition_from_public_transaction(tx);
let tx =
transfer_transaction_for_tests(from.clone(), from_key, 0, to.clone(), balance_to_move);
let _ = genesis_state.transition_from_public_transaction(&tx);
assert_eq!(genesis_state.get_account_by_address(&to).balance, 108);
assert_eq!(
genesis_state.get_account_by_address(&from).balance,
balances[1] - balance_to_move
initial_data[1].1 - balance_to_move
);
assert_eq!(genesis_state.get_account_by_address(&from).nonce, 1);
assert_eq!(genesis_state.get_account_by_address(&to).nonce, 0);

View File

@ -28,6 +28,9 @@ path = "../accounts"
[dependencies.common]
path = "../common"
[dependencies.nssa]
path = "../nssa"
[dependencies.secp256k1-zkp]
workspace = true
features = ["std", "rand-std", "rand", "serde", "global-context"]

View File

@ -6,7 +6,7 @@ use std::path::PathBuf;
pub struct AccountInitialData {
///Hex encoded `AccountAddress`
pub addr: String,
pub balance: u64,
pub balance: u128,
}
#[derive(Clone, Serialize, Deserialize)]

View File

@ -34,7 +34,7 @@ pub enum TransactionMalformationErrorKind {
TxHashAlreadyPresentInTree { tx: TreeHashType },
NullifierAlreadyPresentInTree { tx: TreeHashType },
UTXOCommitmentAlreadyPresentInTree { tx: TreeHashType },
MempoolFullForRound { tx: TreeHashType },
MempoolFullForRound,
ChainStateFurtherThanTransactionState { tx: TreeHashType },
FailedToInsert { tx: TreeHashType, details: String },
InvalidSignature,
@ -67,146 +67,36 @@ impl SequencerCore {
}
}
pub fn get_tree_roots(&self) -> [[u8; 32]; 2] {
[
self.store
.utxo_commitments_store
.get_root()
.unwrap_or([0; 32]),
self.store.pub_tx_store.get_root().unwrap_or([0; 32]),
]
}
// pub fn get_tree_roots(&self) -> [[u8; 32]; 2] {
// [
// self.store
// .utxo_commitments_store
// .get_root()
// .unwrap_or([0; 32]),
// self.store.pub_tx_store.get_root().unwrap_or([0; 32]),
// ]
// }
pub fn transaction_pre_check(
&mut self,
tx: Transaction,
tx_roots: [[u8; 32]; 2],
) -> Result<AuthenticatedTransaction, TransactionMalformationErrorKind> {
let tx = tx
.into_authenticated()
.map_err(|_| TransactionMalformationErrorKind::InvalidSignature)?;
let TransactionBody {
tx_kind,
ref execution_input,
ref execution_output,
ref utxo_commitments_created_hashes,
ref nullifier_created_hashes,
..
} = tx.transaction().body();
let tx_hash = *tx.hash();
let mempool_size = self.mempool.len();
if mempool_size >= self.sequencer_config.max_num_tx_in_block {
return Err(TransactionMalformationErrorKind::MempoolFullForRound { tx: tx_hash });
}
let curr_sequencer_roots = self.get_tree_roots();
if tx_roots != curr_sequencer_roots {
return Err(
TransactionMalformationErrorKind::ChainStateFurtherThanTransactionState {
tx: tx_hash,
},
);
}
//Sanity check
match tx_kind {
TxKind::Public => {
if !utxo_commitments_created_hashes.is_empty()
|| !nullifier_created_hashes.is_empty()
{
//Public transactions can not make private operations.
return Err(
TransactionMalformationErrorKind::PublicTransactionChangedPrivateData {
tx: tx_hash,
},
);
}
}
TxKind::Private => {
if !execution_input.is_empty() || !execution_output.is_empty() {
//Not entirely necessary, but useful simplification for a future.
//This way only shielded and deshielded transactions can be used for interaction
//between public and private state.
return Err(
TransactionMalformationErrorKind::PrivateTransactionChangedPublicData {
tx: tx_hash,
},
);
}
}
_ => {}
};
//Native transfers checks
if let Ok(native_transfer_action) =
serde_json::from_slice::<PublicNativeTokenSend>(execution_input)
{
let signer_address = address::from_public_key(&tx.transaction().public_key);
//Correct sender check
if native_transfer_action.from != signer_address {
return Err(TransactionMalformationErrorKind::IncorrectSender);
}
}
//Tree checks
let tx_tree_check = self.store.pub_tx_store.get_tx(tx_hash).is_some();
let nullifier_tree_check = nullifier_created_hashes.iter().any(|nullifier_hash| {
self.store.nullifier_store.contains(&UTXONullifier {
utxo_hash: *nullifier_hash,
})
});
let utxo_commitments_check =
utxo_commitments_created_hashes
.iter()
.any(|utxo_commitment_hash| {
self.store
.utxo_commitments_store
.get_tx(*utxo_commitment_hash)
.is_some()
});
if tx_tree_check {
return Err(
TransactionMalformationErrorKind::TxHashAlreadyPresentInTree { tx: *tx.hash() },
);
}
if nullifier_tree_check {
return Err(
TransactionMalformationErrorKind::NullifierAlreadyPresentInTree { tx: *tx.hash() },
);
}
if utxo_commitments_check {
return Err(
TransactionMalformationErrorKind::UTXOCommitmentAlreadyPresentInTree {
tx: *tx.hash(),
},
);
}
tx: nssa::PublicTransaction,
// tx_roots: [[u8; 32]; 2],
) -> Result<nssa::PublicTransaction, TransactionMalformationErrorKind> {
// TODO: Stateless checks here
Ok(tx)
}
pub fn push_tx_into_mempool_pre_check(
&mut self,
transaction: Transaction,
tx_roots: [[u8; 32]; 2],
transaction: nssa::PublicTransaction,
// _tx_roots: [[u8; 32]; 2],
) -> Result<(), TransactionMalformationErrorKind> {
let mempool_size = self.mempool.len();
if mempool_size >= self.sequencer_config.max_num_tx_in_block {
return Err(TransactionMalformationErrorKind::MempoolFullForRound {
tx: transaction.body().hash(),
});
return Err(TransactionMalformationErrorKind::MempoolFullForRound);
}
let authenticated_tx = self.transaction_pre_check(transaction, tx_roots)?;
let authenticated_tx = self.transaction_pre_check(transaction)?;
self.mempool.push_item(authenticated_tx.into());
@ -215,77 +105,15 @@ impl SequencerCore {
fn execute_check_transaction_on_state(
&mut self,
mempool_tx: &MempoolTransaction,
) -> Result<(), TransactionMalformationErrorKind> {
let TransactionBody {
ref utxo_commitments_created_hashes,
ref nullifier_created_hashes,
execution_input,
..
} = mempool_tx.auth_tx.transaction().body();
mempool_tx: MempoolTransaction,
) -> Result<nssa::PublicTransaction, ()> {
let tx = mempool_tx.auth_tx;
let tx_hash = *mempool_tx.auth_tx.hash();
self.store.state.transition_from_public_transaction(&tx)?;
//Balance move
if let Ok(native_transfer_action) =
serde_json::from_slice::<PublicNativeTokenSend>(execution_input)
{
// Nonce check
let signer_addres =
address::from_public_key(&mempool_tx.auth_tx.transaction().public_key);
if self.store.acc_store.get_account_nonce(&signer_addres)
!= native_transfer_action.nonce
{
return Err(TransactionMalformationErrorKind::NonceMismatch { tx: tx_hash });
}
// self.store.pub_tx_store.add_tx(mempool_tx.auth_tx);
let from_balance = self
.store
.acc_store
.get_account_balance(&native_transfer_action.from);
let to_balance = self
.store
.acc_store
.get_account_balance(&native_transfer_action.to);
//Balance check
if from_balance < native_transfer_action.balance_to_move {
return Err(TransactionMalformationErrorKind::BalanceMismatch { tx: tx_hash });
}
self.store.acc_store.set_account_balance(
&native_transfer_action.from,
from_balance - native_transfer_action.balance_to_move,
);
self.store.acc_store.set_account_balance(
&native_transfer_action.to,
to_balance + native_transfer_action.balance_to_move,
);
self.store.acc_store.increase_nonce(&signer_addres);
}
for utxo_comm in utxo_commitments_created_hashes {
self.store
.utxo_commitments_store
.add_tx(&UTXOCommitment { hash: *utxo_comm });
}
for nullifier in nullifier_created_hashes.iter() {
self.store.nullifier_store.insert(UTXONullifier {
utxo_hash: *nullifier,
});
}
self.store
.pub_tx_store
.add_tx(mempool_tx.auth_tx.transaction());
Ok(())
}
pub fn register_account(&mut self, account_addr: AccountAddress) {
self.store.acc_store.register_account(account_addr);
Ok(tx)
}
///Produces new block from transactions in mempool
@ -298,13 +126,7 @@ impl SequencerCore {
let valid_transactions = transactions
.into_iter()
.filter_map(|mempool_tx| {
if self.execute_check_transaction_on_state(&mempool_tx).is_ok() {
Some(mempool_tx.auth_tx.into_transaction())
} else {
None
}
})
.filter_map(|mempool_tx| self.execute_check_transaction_on_state(mempool_tx).ok())
.collect();
let prev_block_hash = self
@ -340,6 +162,7 @@ mod tests {
use common::transaction::{SignaturePrivateKey, Transaction, TransactionBody, TxKind};
use k256::{ecdsa::SigningKey, FieldBytes};
use mempool_transaction::MempoolTransaction;
use nssa::Program;
use secp256k1_zkp::Tweak;
fn setup_sequencer_config_variable_initial_accounts(
@ -362,13 +185,15 @@ mod tests {
fn setup_sequencer_config() -> SequencerConfig {
let acc1_addr = vec![
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,
// 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,
1; 32
];
let acc2_addr = vec![
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,
// 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,
2; 32
];
let initial_acc1 = AccountInitialData {
@ -386,92 +211,61 @@ mod tests {
setup_sequencer_config_variable_initial_accounts(initial_accounts)
}
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_dummy_transaction() -> nssa::PublicTransaction {
let program_id = nssa::AuthenticatedTransferProgram::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: u64,
nonce: u128,
to: [u8; 32],
balance_to_move: u64,
signing_key: SigningKey,
) -> Transaction {
let mut rng = rand::thread_rng();
let native_token_transfer = PublicNativeTokenSend {
from,
nonce,
to,
balance_to_move,
};
let body = TransactionBody {
tx_kind: TxKind::Public,
execution_input: serde_json::to_vec(&native_token_transfer).unwrap(),
execution_output: vec![],
utxo_commitments_spent_hashes: vec![],
utxo_commitments_created_hashes: vec![],
nullifier_created_hashes: vec![],
execution_proof_private: "".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, signing_key)
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::AuthenticatedTransferProgram::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() -> SigningKey {
let pub_sign_key_acc1 = [
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,
];
let field_bytes = FieldBytes::from_slice(&pub_sign_key_acc1);
SigningKey::from_bytes(field_bytes).unwrap()
fn create_signing_key_for_account1() -> nssa::PrivateKey {
// let pub_sign_key_acc1 = [
// 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,
// ];
//
// let field_bytes = FieldBytes::from_slice(&pub_sign_key_acc1);
// SigningKey::from_bytes(field_bytes).unwrap()
nssa::PrivateKey::new(1)
}
fn create_signing_key_for_account2() -> SigningKey {
let pub_sign_key_acc2 = [
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,
];
let field_bytes = FieldBytes::from_slice(&pub_sign_key_acc2);
SigningKey::from_bytes(field_bytes).unwrap()
fn create_signing_key_for_account2() -> nssa::PrivateKey {
// let pub_sign_key_acc2 = [
// 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,
// ];
//
// let field_bytes = FieldBytes::from_slice(&pub_sign_key_acc2);
// SigningKey::from_bytes(field_bytes).unwrap()
nssa::PrivateKey::new(2)
}
fn common_setup(sequencer: &mut SequencerCore) {
let tx = create_dummy_transaction(vec![[9; 32]], vec![[7; 32]], vec![[8; 32]]);
let mempool_tx = MempoolTransaction {
auth_tx: tx.into_authenticated().unwrap(),
};
let tx = create_dummy_transaction();
let mempool_tx = MempoolTransaction { auth_tx: tx };
sequencer.mempool.push_item(mempool_tx);
sequencer
@ -497,16 +291,16 @@ mod tests {
.try_into()
.unwrap();
assert!(sequencer.store.acc_store.contains_account(&acc1_addr));
assert!(sequencer.store.acc_store.contains_account(&acc2_addr));
let balance_acc_1 = sequencer.store.state.get_account_by_address(&nssa::Address::new(acc1_addr)).balance;
let balance_acc_2 = sequencer.store.state.get_account_by_address(&nssa::Address::new(acc2_addr)).balance;
assert_eq!(
10000,
sequencer.store.acc_store.get_account_balance(&acc1_addr)
balance_acc_1
);
assert_eq!(
20000,
sequencer.store.acc_store.get_account_balance(&acc2_addr)
balance_acc_2
);
}
@ -548,32 +342,16 @@ mod tests {
.try_into()
.unwrap();
assert!(sequencer.store.acc_store.contains_account(&acc1_addr));
assert!(sequencer.store.acc_store.contains_account(&acc2_addr));
assert_eq!(sequencer.store.acc_store.len(), intial_accounts_len);
assert_eq!(
10000,
sequencer.store.acc_store.get_account_balance(&acc1_addr)
sequencer.store.state.get_account_by_address(&nssa::Address::new(acc1_addr)).balance
);
assert_eq!(
20000,
sequencer.store.acc_store.get_account_balance(&acc2_addr)
sequencer.store.state.get_account_by_address(&nssa::Address::new(acc2_addr)).balance
);
}
#[test]
fn test_get_tree_roots() {
let config = setup_sequencer_config();
let mut sequencer = SequencerCore::start_from_config(config);
common_setup(&mut sequencer);
let roots = sequencer.get_tree_roots();
assert_eq!(roots.len(), 2); // Should return two roots
}
#[test]
fn test_transaction_pre_check_pass() {
let config = setup_sequencer_config();
@ -581,9 +359,9 @@ mod tests {
common_setup(&mut sequencer);
let tx = create_dummy_transaction(vec![[91; 32]], vec![[71; 32]], vec![[81; 32]]);
let tx_roots = sequencer.get_tree_roots();
let result = sequencer.transaction_pre_check(tx, tx_roots);
let tx = create_dummy_transaction();
// let tx_roots = sequencer.get_tree_roots();
let result = sequencer.transaction_pre_check(tx);
assert!(result.is_ok());
}
@ -607,8 +385,7 @@ 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_roots = sequencer.get_tree_roots();
let result = sequencer.transaction_pre_check(tx, tx_roots);
let result = sequencer.transaction_pre_check(tx);
assert!(result.is_ok());
}
@ -632,13 +409,13 @@ 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_roots = sequencer.get_tree_roots();
let result = sequencer.transaction_pre_check(tx, tx_roots);
// let tx_roots = sequencer.get_tree_roots();
let tx = sequencer.transaction_pre_check(tx).unwrap();
assert_eq!(
result.err().unwrap(),
TransactionMalformationErrorKind::IncorrectSender
);
let result =
sequencer.execute_check_transaction_on_state(MempoolTransaction { auth_tx: tx });
assert_eq!(result.err().unwrap(), ());
}
#[test]
@ -660,16 +437,19 @@ 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_roots = sequencer.get_tree_roots();
let result = sequencer.transaction_pre_check(tx, tx_roots);
// let tx_roots = sequencer.get_tree_roots();
let result = sequencer.transaction_pre_check(tx);
//Passed pre-check
assert!(result.is_ok());
let result = sequencer.execute_check_transaction_on_state(&result.unwrap().into());
let result = sequencer.execute_check_transaction_on_state(MempoolTransaction {
auth_tx: result.unwrap(),
});
let is_failed_at_balance_mismatch = matches!(
result.err().unwrap(),
TransactionMalformationErrorKind::BalanceMismatch { tx: _ }
// TransactionMalformationErrorKind::BalanceMismatch { tx: _ }
()
);
assert!(is_failed_at_balance_mismatch);
@ -696,11 +476,11 @@ mod tests {
let tx = create_dummy_transaction_native_token_transfer(acc1, 0, acc2, 100, sign_key1);
sequencer
.execute_check_transaction_on_state(&tx.into_authenticated().unwrap().into())
.execute_check_transaction_on_state(MempoolTransaction { auth_tx: tx })
.unwrap();
let bal_from = sequencer.store.acc_store.get_account_balance(&acc1);
let bal_to = sequencer.store.acc_store.get_account_balance(&acc2);
let bal_from = sequencer.store.state.get_account_by_address(&nssa::Address::new(acc1)).balance;
let bal_to = sequencer.store.state.get_account_by_address(&nssa::Address::new(acc2)).balance;
assert_eq!(bal_from, 9900);
assert_eq!(bal_to, 20100);
@ -716,16 +496,16 @@ mod tests {
common_setup(&mut sequencer);
let tx = create_dummy_transaction(vec![[92; 32]], vec![[72; 32]], vec![[82; 32]]);
let tx_roots = sequencer.get_tree_roots();
let tx = create_dummy_transaction();
// let tx_roots = sequencer.get_tree_roots();
// Fill the mempool
let dummy_tx = MempoolTransaction {
auth_tx: tx.clone().into_authenticated().unwrap(),
auth_tx: tx.clone(),
};
sequencer.mempool.push_item(dummy_tx);
let result = sequencer.push_tx_into_mempool_pre_check(tx, tx_roots);
let result = sequencer.push_tx_into_mempool_pre_check(tx);
assert!(matches!(
result,
@ -740,10 +520,10 @@ mod tests {
common_setup(&mut sequencer);
let tx = create_dummy_transaction(vec![[93; 32]], vec![[73; 32]], vec![[83; 32]]);
let tx_roots = sequencer.get_tree_roots();
let tx = create_dummy_transaction();
// let tx_roots = sequencer.get_tree_roots();
let result = sequencer.push_tx_into_mempool_pre_check(tx, tx_roots);
let result = sequencer.push_tx_into_mempool_pre_check(tx);
assert!(result.is_ok());
assert_eq!(sequencer.mempool.len(), 1);
}
@ -754,10 +534,8 @@ mod tests {
let mut sequencer = SequencerCore::start_from_config(config);
let genesis_height = sequencer.chain_height;
let tx = create_dummy_transaction(vec![[94; 32]], vec![[7; 32]], vec![[8; 32]]);
let tx_mempool = MempoolTransaction {
auth_tx: tx.into_authenticated().unwrap(),
};
let tx = create_dummy_transaction();
let tx_mempool = MempoolTransaction { auth_tx: tx };
sequencer.mempool.push_item(tx_mempool);
let block_id = sequencer.produce_new_block_with_mempool_transactions();
@ -786,10 +564,10 @@ mod tests {
let tx = create_dummy_transaction_native_token_transfer(acc1, 0, acc2, 100, sign_key1);
let tx_mempool_original = MempoolTransaction {
auth_tx: tx.clone().into_authenticated().unwrap(),
auth_tx: tx.clone(),
};
let tx_mempool_replay = MempoolTransaction {
auth_tx: tx.clone().into_authenticated().unwrap(),
auth_tx: tx.clone(),
};
// Pushing two copies of the same tx to the mempool
@ -832,7 +610,7 @@ mod tests {
// The transaction should be included the first time
let tx_mempool_original = MempoolTransaction {
auth_tx: tx.clone().into_authenticated().unwrap(),
auth_tx: tx.clone(),
};
sequencer.mempool.push_item(tx_mempool_original);
let current_height = sequencer
@ -846,9 +624,7 @@ mod tests {
assert_eq!(block.transactions, vec![tx.clone()]);
// Add same transaction should fail
let tx_mempool_replay = MempoolTransaction {
auth_tx: tx.into_authenticated().unwrap(),
};
let tx_mempool_replay = MempoolTransaction { auth_tx: tx };
sequencer.mempool.push_item(tx_mempool_replay);
let current_height = sequencer
.produce_new_block_with_mempool_transactions()

View File

@ -2,11 +2,11 @@ use common::{merkle_tree_public::TreeHashType, transaction::AuthenticatedTransac
use mempool::mempoolitem::MemPoolItem;
pub struct MempoolTransaction {
pub auth_tx: AuthenticatedTransaction,
pub auth_tx: nssa::PublicTransaction,
}
impl From<AuthenticatedTransaction> for MempoolTransaction {
fn from(auth_tx: AuthenticatedTransaction) -> Self {
impl From<nssa::PublicTransaction> for MempoolTransaction {
fn from(auth_tx: nssa::PublicTransaction) -> Self {
Self { auth_tx }
}
}
@ -15,6 +15,6 @@ impl MemPoolItem for MempoolTransaction {
type Identifier = TreeHashType;
fn identifier(&self) -> Self::Identifier {
*self.auth_tx.hash()
self.auth_tx.hash()
}
}

View File

@ -51,12 +51,12 @@ impl SequecerBlockStore {
}
/// Returns the transaction corresponding to the given hash, if it exists in the blockchain.
pub fn get_transaction_by_hash(&self, hash: TreeHashType) -> Option<Transaction> {
pub fn get_transaction_by_hash(&self, hash: TreeHashType) -> Option<nssa::PublicTransaction> {
let block_id = self.tx_hash_to_block_map.get(&hash);
let block = block_id.map(|&id| self.get_block_at_id(id));
if let Some(Ok(block)) = block {
for transaction in block.transactions.into_iter() {
if transaction.body().hash() == hash {
if transaction.hash() == hash {
return Some(transaction);
}
}
@ -69,7 +69,7 @@ fn block_to_transactions_map(block: &Block) -> HashMap<TreeHashType, u64> {
block
.transactions
.iter()
.map(|transaction| (transaction.body().hash(), block.block_id))
.map(|transaction| (transaction.hash(), block.block_id))
.collect()
}
@ -77,26 +77,18 @@ fn block_to_transactions_map(block: &Block) -> HashMap<TreeHashType, u64> {
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, Transaction) {
let body = TransactionBody {
tx_kind: common::transaction::TxKind::Public,
execution_input: Default::default(),
execution_output: Default::default(),
utxo_commitments_spent_hashes: Default::default(),
utxo_commitments_created_hashes: Default::default(),
nullifier_created_hashes: Default::default(),
execution_proof_private: Default::default(),
encoded_data: Default::default(),
ephemeral_pub_key: Default::default(),
commitment: Default::default(),
tweak: Default::default(),
secret_r: Default::default(),
sc_addr: Default::default(),
state_changes: Default::default(),
};
let tx = Transaction::new(body, SignaturePrivateKey::from_slice(&[1; 32]).unwrap());
fn create_dummy_block_with_transaction(block_id: u64) -> (Block, nssa::PublicTransaction) {
let program_id = nssa::AuthenticatedTransferProgram::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,
@ -127,12 +119,12 @@ mod tests {
SequecerBlockStore::open_db_with_genesis(path, Some(genesis_block)).unwrap();
let (block, tx) = create_dummy_block_with_transaction(1);
// Try retrieve a tx that's not in the chain yet.
let retrieved_tx = node_store.get_transaction_by_hash(tx.body().hash());
let retrieved_tx = node_store.get_transaction_by_hash(tx.hash());
assert_eq!(None, retrieved_tx);
// Add the block with the transaction
node_store.put_block_at_id(block).unwrap();
// Try again
let retrieved_tx = node_store.get_transaction_by_hash(tx.body().hash());
let retrieved_tx = node_store.get_transaction_by_hash(tx.hash());
assert_eq!(Some(tx), retrieved_tx);
}
}

View File

@ -1,5 +1,6 @@
use std::{collections::HashSet, path::Path};
use accounts::account_core::address::AccountAddress;
use accounts_store::SequencerAccountsStore;
use block_store::SequecerBlockStore;
use common::{
@ -8,6 +9,7 @@ use common::{
nullifier::UTXONullifier,
};
use rand::{rngs::OsRng, RngCore};
use nssa;
use crate::config::AccountInitialData;
@ -15,11 +17,11 @@ pub mod accounts_store;
pub mod block_store;
pub struct SequecerChainStore {
pub acc_store: SequencerAccountsStore,
pub state: nssa::V01State,
pub block_store: SequecerBlockStore,
pub nullifier_store: HashSet<UTXONullifier>,
pub utxo_commitments_store: UTXOCommitmentsMerkleTree,
pub pub_tx_store: PublicTransactionMerkleTree,
// pub pub_tx_store: PublicTransactionMerkleTree,
}
impl SequecerChainStore {
@ -29,7 +31,7 @@ impl SequecerChainStore {
is_genesis_random: bool,
initial_accounts: &[AccountInitialData],
) -> Self {
let init_accs: Vec<_> = initial_accounts
let init_accs: Vec<(AccountAddress, u128)> = initial_accounts
.iter()
.map(|acc_data| {
(
@ -42,10 +44,10 @@ impl SequecerChainStore {
})
.collect();
let acc_store = SequencerAccountsStore::new(&init_accs);
let state = nssa::V01State::new_with_genesis_accounts(&init_accs);
let nullifier_store = HashSet::new();
let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]);
let pub_tx_store = PublicTransactionMerkleTree::new(vec![]);
// let pub_tx_store = PublicTransactionMerkleTree::new(vec![]);
let mut data = [0; 32];
let mut prev_block_hash = [0; 32];
@ -74,11 +76,11 @@ impl SequecerChainStore {
.unwrap();
Self {
acc_store,
state,
block_store,
nullifier_store,
utxo_commitments_store,
pub_tx_store,
// pub_tx_store,
}
}
}

View File

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

View File

@ -1,4 +1,5 @@
use actix_web::Error as HttpError;
use nssa;
use sequencer_core::config::AccountInitialData;
use serde_json::Value;
@ -24,7 +25,6 @@ use common::rpc_primitives::requests::{
use super::{respond, types::err_rpc::RpcErr, JsonHandler};
pub const HELLO: &str = "hello";
pub const REGISTER_ACCOUNT: &str = "register_account";
pub const SEND_TX: &str = "send_tx";
pub const GET_BLOCK: &str = "get_block";
pub const GET_GENESIS: &str = "get_genesis";
@ -66,29 +66,13 @@ impl JsonHandler {
respond(helperstruct)
}
async fn process_register_account_request(&self, request: Request) -> Result<Value, RpcErr> {
let acc_req = RegisterAccountRequest::parse(Some(request.params))?;
{
let mut acc_store = self.sequencer_state.lock().await;
acc_store.register_account(acc_req.address);
}
let helperstruct = RegisterAccountResponse {
status: SUCCESS.to_string(),
};
respond(helperstruct)
}
async fn process_send_tx(&self, request: Request) -> Result<Value, RpcErr> {
let send_tx_req = SendTxRequest::parse(Some(request.params))?;
{
let mut state = self.sequencer_state.lock().await;
state.push_tx_into_mempool_pre_check(send_tx_req.transaction, send_tx_req.tx_roots)?;
state.push_tx_into_mempool_pre_check(send_tx_req.transaction)?;
}
let helperstruct = SendTxResponse {
@ -164,13 +148,16 @@ impl JsonHandler {
let get_account_req = GetAccountBalanceRequest::parse(Some(request.params))?;
let address_bytes = hex::decode(get_account_req.address)
.map_err(|_| RpcError::invalid_params("invalid hex".to_string()))?;
let address = address_bytes
.try_into()
.map_err(|_| RpcError::invalid_params("invalid length".to_string()))?;
let address = nssa::Address::new(
address_bytes
.try_into()
.map_err(|_| RpcError::invalid_params("invalid length".to_string()))?,
);
let balance = {
let state = self.sequencer_state.lock().await;
state.store.acc_store.get_account_balance(&address)
let account = state.store.state.get_account_by_address(&address);
account.balance
};
let helperstruct = GetAccountBalanceResponse { balance };
@ -199,7 +186,6 @@ impl JsonHandler {
pub async fn process_request_internal(&self, request: Request) -> Result<Value, RpcErr> {
match request.method.as_ref() {
HELLO => self.process_temp_hello(request).await,
REGISTER_ACCOUNT => self.process_register_account_request(request).await,
SEND_TX => self.process_send_tx(request).await,
GET_BLOCK => self.process_get_block_data(request).await,
GET_GENESIS => self.process_get_genesis(request).await,
@ -221,6 +207,7 @@ mod tests {
rpc_primitives::RpcPollingConfig,
transaction::{SignaturePrivateKey, Transaction, TransactionBody},
};
use nssa::Program;
use sequencer_core::{
config::{AccountInitialData, SequencerConfig},
SequencerCore,
@ -233,13 +220,15 @@ mod tests {
let tempdir = tempdir().unwrap();
let home = tempdir.path().to_path_buf();
let acc1_addr = vec![
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,
// 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,
1; 32
];
let acc2_addr = vec![
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,
// 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,
2; 32
];
let initial_acc1 = AccountInitialData {
@ -268,32 +257,25 @@ mod tests {
fn json_handler_for_tests() -> (JsonHandler, Vec<AccountInitialData>) {
let config = sequencer_config_for_tests();
let mut sequencer_core = SequencerCore::start_from_config(config);
let initial_accounts = sequencer_core.sequencer_config.initial_accounts.clone();
let tx_body = TransactionBody {
tx_kind: common::transaction::TxKind::Shielded,
execution_input: Default::default(),
execution_output: Default::default(),
utxo_commitments_spent_hashes: Default::default(),
utxo_commitments_created_hashes: Default::default(),
nullifier_created_hashes: Default::default(),
execution_proof_private: Default::default(),
encoded_data: Default::default(),
ephemeral_pub_key: Default::default(),
commitment: Default::default(),
tweak: Default::default(),
secret_r: Default::default(),
sc_addr: Default::default(),
state_changes: Default::default(),
};
let tx = Transaction::new(tx_body, SignaturePrivateKey::from_slice(&[1; 32]).unwrap());
let from = nssa::Address::new([1; 32]);
let signing_key = nssa::PrivateKey::new(1);
let to = nssa::Address::new([2; 32]);
let balance_to_move = 10;
let addresses = vec![from, to];
let nonces = vec![0];
let program_id = nssa::AuthenticatedTransferProgram::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]);
let tx = nssa::PublicTransaction::new(message, witness_set);
sequencer_core.push_tx_into_mempool_pre_check(tx).unwrap();
sequencer_core
.push_tx_into_mempool_pre_check(tx, [[0; 32]; 2])
.unwrap();
sequencer_core
.produce_new_block_with_mempool_transactions()
.unwrap();
@ -414,7 +396,7 @@ mod tests {
"id": 1,
"jsonrpc": "2.0",
"result": {
"balance": 10000
"balance": 10000 - 10
}
});
@ -499,7 +481,7 @@ mod tests {
let request = serde_json::json!({
"jsonrpc": "2.0",
"method": "get_transaction_by_hash",
"params": { "hash": "a5210ef33912a448cfe6eda43878c144df81f7bdf51d19b5ddf97be11806a6ed"},
"params": { "hash": "e5f0c9b4b7732a2f4946b8e7a5f7c641b004559b1a13b1ccc600f29477725240"},
"id": 1
});
@ -508,24 +490,20 @@ mod tests {
"jsonrpc": "2.0",
"result": {
"transaction": {
"body": {
"commitment": [],
"encoded_data": [],
"ephemeral_pub_key": [],
"execution_input": [],
"execution_output": [],
"execution_proof_private": "",
"nullifier_created_hashes": [],
"sc_addr": "",
"secret_r": vec![0; 32],
"state_changes": [null, 0],
"tweak": "0".repeat(64),
"tx_kind": "Shielded",
"utxo_commitments_created_hashes": [],
"utxo_commitments_spent_hashes": [],
"message": {
"addresses": [
{ "value": [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] },
{ "value": [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] }
],
"instruction_data": 10,
"nonces": [0],
"program_id": nssa::AuthenticatedTransferProgram::PROGRAM_ID,
},
"public_key": "3056301006072A8648CE3D020106052B8104000A034200041B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F70BEAF8F588B541507FED6A642C5AB42DFDF8120A7F639DE5122D47A69A8E8D1",
"signature": "A4E0D6A25BE829B006124F0DFD766427967AA3BEA96C29219E79BB2CC871891F384748C27E28718A4450AA78709FBF1A57DB33BCD575A2C819D2A439C2D878E6"
"witness_set": {
"signatures_and_public_keys": [
[null, 1]
]
}
}
}
});