diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b717c10..f7f923d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,35 +14,13 @@ on: name: General jobs: - build-ubuntu-latest: + ubuntu-latest-pipeline: runs-on: ubuntu-latest timeout-minutes: 60 - name: build - ubuntu-latest + name: ubuntu-latest-pipeline steps: - uses: actions/checkout@v3 - - name: Install stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - - name: build - ubuntu-latest - if: success() || failure() - run: chmod 777 ./ci_scripts/build-ubuntu.sh && ./ci_scripts/build-ubuntu.sh - - - lint: - strategy: - matrix: - platform: [ ubuntu-latest ] - runs-on: ${{ matrix.platform }} - timeout-minutes: 60 - - name: lint - ${{ matrix.crate }} - ${{ matrix.platform }} - steps: - - name: Checkout sources - uses: actions/checkout@v3 - name: Install stable toolchain uses: actions-rs/toolchain@v1 with: @@ -53,25 +31,6 @@ jobs: - name: lint - ubuntu-latest if: success() || failure() run: chmod 777 ./ci_scripts/lint-ubuntu.sh && ./ci_scripts/lint-ubuntu.sh - - - test: - strategy: - matrix: - platform: [ ubuntu-latest ] - runs-on: ${{ matrix.platform }} - timeout-minutes: 60 - - name: test - ${{ matrix.crate }} - ${{ matrix.platform }} - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - name: Install stable toolchain - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - name: test ubuntu-latest if: success() || failure() run: chmod 777 ./ci_scripts/test-ubuntu.sh && ./ci_scripts/test-ubuntu.sh diff --git a/Cargo.lock b/Cargo.lock index e837cb3..717be5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1010,6 +1010,7 @@ dependencies = [ "anyhow", "elliptic-curve", "hex", + "k256", "log", "reqwest 0.11.27", "risc0-zkvm", @@ -1260,6 +1261,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", + "pem-rfc7468", "zeroize", ] @@ -1499,6 +1501,7 @@ dependencies = [ "ff", "generic-array", "group", + "pem-rfc7468", "pkcs8", "rand_core 0.6.4", "sec1", @@ -3209,6 +3212,15 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" diff --git a/Cargo.toml b/Cargo.toml index f8be323..f2bcab8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,7 +55,7 @@ features = ["std", "std_rng", "getrandom"] version = "0.8.5" [workspace.dependencies.k256] -features = ["ecdsa-core", "arithmetic", "expose-field", "serde"] +features = ["ecdsa-core", "arithmetic", "expose-field", "serde", "pem"] version = "0.13.4" [workspace.dependencies.elliptic-curve] diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs index 24ac045..6fa1462 100644 --- a/accounts/src/key_management/mod.rs +++ b/accounts/src/key_management/mod.rs @@ -2,12 +2,14 @@ use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit}; use common::merkle_tree_public::TreeHashType; use constants_types::{CipherText, Nonce}; use elliptic_curve::point::AffineCoordinates; -use k256::AffinePoint; +use k256::{ecdsa::SigningKey, AffinePoint, FieldBytes}; use log::info; +use rand::{rngs::OsRng, RngCore}; use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder}; use serde::{Deserialize, Serialize}; use crate::account_core::PublicKey; +pub type PublicAccountSigningKey = [u8; 32]; pub mod constants_types; pub mod ephemeral_key_holder; @@ -20,6 +22,7 @@ pub struct AddressKeyHolder { #[allow(dead_code)] top_secret_key_holder: TopSecretKeyHolder, pub utxo_secret_key_holder: UTXOSecretKeyHolder, + pub_account_signing_key: PublicAccountSigningKey, pub address: TreeHashType, pub nullifer_public_key: PublicKey, pub viewing_public_key: PublicKey, @@ -38,15 +41,29 @@ impl AddressKeyHolder { let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key(); 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 + }; + Self { top_secret_key_holder, utxo_secret_key_holder, address, nullifer_public_key, viewing_public_key, + pub_account_signing_key, } } + /// 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 calculate_shared_secret_receiver( &self, ephemeral_public_key_sender: AffinePoint, @@ -166,7 +183,7 @@ mod tests { .decrypt_data( ephemeral_public_key_sender, CipherText::from(ciphertext), - nonce.clone(), + *nonce, ) .unwrap(); @@ -186,7 +203,7 @@ mod tests { assert!(!Into::::into( address_key_holder.viewing_public_key.is_identity() )); - assert!(address_key_holder.address.as_slice().len() > 0); // Assume TreeHashType has non-zero length for a valid address + assert!(!address_key_holder.address.as_slice().is_empty()); // Assume TreeHashType has non-zero length for a valid address } #[test] @@ -228,7 +245,7 @@ mod tests { .decrypt_data( ephemeral_public_key_sender, CipherText::from(ciphertext.clone()), - incorrect_nonce.clone(), + *incorrect_nonce, ) .unwrap(); @@ -264,7 +281,7 @@ mod tests { .decrypt_data( ephemeral_public_key_sender, CipherText::from(corrupted_ciphertext), - nonce.clone(), + *nonce, ) .unwrap(); @@ -297,7 +314,7 @@ mod tests { .decrypt_data( ephemeral_public_key_sender, CipherText::from(ciphertext), - nonce.clone(), + *nonce, ) .unwrap(); @@ -305,6 +322,16 @@ mod tests { assert_eq!(decrypted_data, plaintext); } + #[test] + 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 + ); + } + #[test] fn key_generation_test() { let seed_holder = SeedHolder::new_os_random(); diff --git a/ci_scripts/lint-ubuntu.sh b/ci_scripts/lint-ubuntu.sh index d30ef67..35a0e4a 100644 --- a/ci_scripts/lint-ubuntu.sh +++ b/ci_scripts/lint-ubuntu.sh @@ -1,9 +1,10 @@ set -e -curl -L https://risczero.com/install | bash -/home/runner/.risc0/bin/rzup install source env.sh cargo install taplo-cli --locked cargo fmt -- --check -taplo fmt --check \ No newline at end of file +taplo fmt --check + +export RISC0_SKIP_BUILD=1 +cargo clippy --workspace --all-targets -- -D warnings diff --git a/common/Cargo.toml b/common/Cargo.toml index bc929e3..7e4e0ab 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -10,6 +10,7 @@ serde_json.workspace = true serde.workspace = true reqwest.workspace = true risc0-zkvm = { git = "https://github.com/risc0/risc0.git", branch = "release-2.3" } +k256.workspace = true rs_merkle.workspace = true sha2.workspace = true diff --git a/common/src/lib.rs b/common/src/lib.rs index 46868d9..96a7b55 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -88,3 +88,9 @@ impl ExecutionFailureKind { Self::DBError(err) } } + +#[derive(Debug, thiserror::Error)] +pub enum TransactionSignatureError { + #[error("invalid signature for transaction body")] + InvalidSignature, +} diff --git a/common/src/merkle_tree_public/merkle_tree.rs b/common/src/merkle_tree_public/merkle_tree.rs index d8e99ec..e2eb715 100644 --- a/common/src/merkle_tree_public/merkle_tree.rs +++ b/common/src/merkle_tree_public/merkle_tree.rs @@ -140,7 +140,7 @@ impl HashStorageMerkleTree { } } - pub fn add_tx(&mut self, tx: Leav) { + pub fn add_tx(&mut self, tx: &Leav) { let last = self.leaves.len(); self.leaves.insert(last, tx.clone()); @@ -267,7 +267,7 @@ mod tests { let mut tree = HashStorageMerkleTree::new(vec![tx1.clone()]); - tree.add_tx(tx2.clone()); + tree.add_tx(&tx2); assert_eq!(tree.leaves.len(), 2); assert_eq!(tree.get_tx(tx2.hash()), Some(&tx2)); } diff --git a/common/src/merkle_tree_public/tree_leav_item.rs b/common/src/merkle_tree_public/tree_leav_item.rs index 1fbbb1a..3b919a8 100644 --- a/common/src/merkle_tree_public/tree_leav_item.rs +++ b/common/src/merkle_tree_public/tree_leav_item.rs @@ -8,7 +8,7 @@ pub trait TreeLeavItem { impl TreeLeavItem for Transaction { fn hash(&self) -> TreeHashType { - self.hash() + self.body().hash() } } diff --git a/common/src/rpc_primitives/message.rs b/common/src/rpc_primitives/message.rs index 9378b60..c6bdc58 100644 --- a/common/src/rpc_primitives/message.rs +++ b/common/src/rpc_primitives/message.rs @@ -447,7 +447,7 @@ mod tests { /// A helper for the `broken` test. /// /// Check that the given JSON string parses, but is not recognized as a valid RPC message. - + /// /// Test things that are almost but not entirely JSONRPC are rejected /// /// The reject is done by returning it as Unmatched. diff --git a/common/src/transaction.rs b/common/src/transaction.rs index 3d16fcd..26dc670 100644 --- a/common/src/transaction.rs +++ b/common/src/transaction.rs @@ -1,6 +1,11 @@ +use k256::ecdsa::{ + signature::{Signer, Verifier}, + Signature, SigningKey, VerifyingKey, +}; use log::info; use secp256k1_zkp::{PedersenCommitment, Tweak}; use serde::{Deserialize, Serialize}; + use sha2::{digest::FixedOutput, Digest}; use crate::merkle_tree_public::TreeHashType; @@ -11,6 +16,8 @@ use elliptic_curve::{ }; use sha2::digest::typenum::{UInt, UTerm}; +use crate::TransactionSignatureError; + pub type CipherText = Vec; pub type Nonce = GenericArray, B1>, B0>, B0>>; pub type Tag = u8; @@ -25,7 +32,7 @@ pub enum TxKind { #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] ///General transaction object -pub struct Transaction { +pub struct TransactionBody { pub tx_kind: TxKind, ///Tx input data (public part) pub execution_input: Vec, @@ -144,22 +151,26 @@ impl ActionData { .into_iter() .map(|owned_utxo| owned_utxo.into()) .collect(); - format!("Published utxos {:?}", pub_own_utxo) + format!("Published utxos {pub_own_utxo:?}") } } } } -impl Transaction { +impl TransactionBody { /// Computes and returns the SHA-256 hash of the JSON-serialized representation of `self`. pub fn hash(&self) -> TreeHashType { + let bytes_to_hash = self.to_bytes(); + let mut hasher = sha2::Sha256::new(); + hasher.update(&bytes_to_hash); + TreeHashType::from(hasher.finalize_fixed()) + } + + fn to_bytes(&self) -> Vec { // TODO: Remove `unwrap` by implementing a `to_bytes` method // that deterministically encodes all transaction fields to bytes // and guarantees serialization will succeed. - let raw_data = serde_json::to_vec(&self).unwrap(); - let mut hasher = sha2::Sha256::new(); - hasher.update(&raw_data); - TreeHashType::from(hasher.finalize_fixed()) + serde_json::to_vec(&self).unwrap() } pub fn log(&self) { @@ -183,21 +194,21 @@ impl Transaction { "Transaction utxo_commitments_spent_hashes is {:?}", self.utxo_commitments_spent_hashes .iter() - .map(|val| hex::encode(val.clone())) + .map(|val| hex::encode(*val)) .collect::>() ); info!( "Transaction utxo_commitments_created_hashes is {:?}", self.utxo_commitments_created_hashes .iter() - .map(|val| hex::encode(val.clone())) + .map(|val| hex::encode(*val)) .collect::>() ); info!( "Transaction nullifier_created_hashes is {:?}", self.nullifier_created_hashes .iter() - .map(|val| hex::encode(val.clone())) + .map(|val| hex::encode(*val)) .collect::>() ); info!( @@ -214,19 +225,89 @@ impl Transaction { } } +type TransactionHash = [u8; 32]; +pub type TransactionSignature = Signature; +pub type SignaturePublicKey = VerifyingKey; +pub type SignaturePrivateKey = SigningKey; + +/// A container for a transaction body with a signature. +/// Meant to be sent through the network to the sequencer +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] +pub struct Transaction { + body: TransactionBody, + signature: TransactionSignature, + public_key: VerifyingKey, +} + +impl Transaction { + /// Returns a new transaction signed with the provided `private_key`. + /// The signature is generated over the hash of the body as computed by `body.hash()` + pub fn new(body: TransactionBody, private_key: SigningKey) -> Transaction { + let signature: TransactionSignature = private_key.sign(&body.to_bytes()); + let public_key = VerifyingKey::from(&private_key); + Self { + body, + signature, + public_key, + } + } + + /// Converts the transaction into an `AuthenticatedTransaction` by verifying its signature. + /// Returns an error if the signature verification fails. + pub fn into_authenticated(self) -> Result { + let hash = self.body.hash(); + + self.public_key + .verify(&self.body.to_bytes(), &self.signature) + .map_err(|_| TransactionSignatureError::InvalidSignature)?; + + Ok(AuthenticatedTransaction { + hash, + transaction: self, + }) + } + + /// Returns the body of the transaction + pub fn body(&self) -> &TransactionBody { + &self.body + } +} + +/// A transaction with a valid signature over the hash of its body. +/// Can only be constructed from an `Transaction` +/// if the signature is valid +#[derive(Debug, Clone)] +pub struct AuthenticatedTransaction { + hash: TransactionHash, + transaction: Transaction, +} + +impl AuthenticatedTransaction { + /// Returns the underlying transaction + pub fn transaction(&self) -> &Transaction { + &self.transaction + } + + /// Returns the precomputed hash over the body of the transaction + pub fn hash(&self) -> &TransactionHash { + &self.hash + } +} + #[cfg(test)] mod tests { + use super::*; + use k256::{ecdsa::signature::Signer, FieldBytes}; use secp256k1_zkp::{constants::SECRET_KEY_SIZE, Tweak}; use sha2::{digest::FixedOutput, Digest}; use crate::{ merkle_tree_public::TreeHashType, - transaction::{Transaction, TxKind}, + transaction::{Transaction, TransactionBody, TxKind}, }; - #[test] - fn test_transaction_hash_is_sha256_of_json_bytes() { - let tx = Transaction { + fn test_transaction_body() -> TransactionBody { + TransactionBody { tx_kind: TxKind::Public, execution_input: vec![1, 2, 3, 4], execution_output: vec![5, 6, 7, 8], @@ -241,16 +322,100 @@ mod tests { secret_r: [8; 32], sc_addr: "someAddress".to_string(), state_changes: (serde_json::Value::Null, 10), - }; + } + } + + fn test_transaction() -> Transaction { + let body = test_transaction_body(); + let key_bytes = FieldBytes::from_slice(&[37; 32]); + let private_key: SigningKey = SigningKey::from_bytes(key_bytes).unwrap(); + Transaction::new(body, private_key) + } + + #[test] + fn test_transaction_hash_is_sha256_of_json_bytes() { + let body = test_transaction_body(); let expected_hash = { - let data = serde_json::to_vec(&tx).unwrap(); + let data = serde_json::to_vec(&body).unwrap(); let mut hasher = sha2::Sha256::new(); hasher.update(&data); TreeHashType::from(hasher.finalize_fixed()) }; - let hash = tx.hash(); + let hash = body.hash(); assert_eq!(expected_hash, hash); } + + #[test] + fn test_transaction_constructor() { + let body = test_transaction_body(); + let key_bytes = FieldBytes::from_slice(&[37; 32]); + let private_key: SigningKey = SigningKey::from_bytes(key_bytes).unwrap(); + let transaction = Transaction::new(body.clone(), private_key.clone()); + assert_eq!( + transaction.public_key, + SignaturePublicKey::from(&private_key) + ); + assert_eq!(transaction.body, body); + } + + #[test] + fn test_transaction_body_getter() { + let body = test_transaction_body(); + let key_bytes = FieldBytes::from_slice(&[37; 32]); + let private_key: SigningKey = SigningKey::from_bytes(key_bytes).unwrap(); + let transaction = Transaction::new(body.clone(), private_key.clone()); + assert_eq!(transaction.body(), &body); + } + + #[test] + fn test_into_authenticated_succeeds_for_valid_signature() { + let transaction = test_transaction(); + let authenticated_tx = transaction.clone().into_authenticated().unwrap(); + + let signature = authenticated_tx.transaction().signature; + let hash = authenticated_tx.hash(); + + assert_eq!(authenticated_tx.transaction(), &transaction); + assert_eq!(hash, &transaction.body.hash()); + assert!(authenticated_tx + .transaction() + .public_key + .verify(&transaction.body.to_bytes(), &signature) + .is_ok()); + } + + #[test] + fn test_into_authenticated_fails_for_invalid_signature() { + let body = test_transaction_body(); + let key_bytes = FieldBytes::from_slice(&[37; 32]); + let private_key: SigningKey = SigningKey::from_bytes(key_bytes).unwrap(); + let transaction = { + let mut this = Transaction::new(body, private_key.clone()); + // Modify the signature to make it invalid + // We do this by changing it to the signature of something else + this.signature = private_key.sign(b"deadbeef"); + this + }; + + matches!( + transaction.into_authenticated(), + Err(TransactionSignatureError::InvalidSignature) + ); + } + + #[test] + fn test_authenticated_transaction_getter() { + let transaction = test_transaction(); + let authenticated_tx = transaction.clone().into_authenticated().unwrap(); + assert_eq!(authenticated_tx.transaction(), &transaction); + } + + #[test] + fn test_authenticated_transaction_hash_getter() { + let transaction = test_transaction(); + let authenticated_tx = transaction.clone().into_authenticated().unwrap(); + assert_eq!(authenticated_tx.hash(), &transaction.body.hash()); + } } diff --git a/node_core/src/chain_storage/accounts_store.rs b/node_core/src/chain_storage/accounts_store.rs index 6cdb100..1bd6dfc 100644 --- a/node_core/src/chain_storage/accounts_store.rs +++ b/node_core/src/chain_storage/accounts_store.rs @@ -54,7 +54,7 @@ mod tests { let mut store = NodeAccountsStore::new(); let account = create_sample_account(100); - let account_addr = account.address.clone(); + let account_addr = account.address; store.register_account(account); @@ -68,7 +68,7 @@ mod tests { let mut store = NodeAccountsStore::new(); let account = create_sample_account(100); - let account_addr = account.address.clone(); + let account_addr = account.address; store.register_account(account); assert_eq!(store.accounts.len(), 1); @@ -94,8 +94,8 @@ mod tests { let account1 = create_sample_account(100); let account2 = create_sample_account(200); - let address_1 = account1.address.clone(); - let address_2 = account2.address.clone(); + let address_1 = account1.address; + let address_2 = account2.address; store.register_account(account1); store.register_account(account2); diff --git a/node_core/src/chain_storage/block_store.rs b/node_core/src/chain_storage/block_store.rs index 677f426..ba97c3c 100644 --- a/node_core/src/chain_storage/block_store.rs +++ b/node_core/src/chain_storage/block_store.rs @@ -145,8 +145,8 @@ mod tests { fn create_sample_block(block_id: u64, prev_block_id: u64) -> Block { Block { - block_id: block_id, - prev_block_id: prev_block_id, + block_id, + prev_block_id, prev_block_hash: [0; 32], hash: [1; 32], transactions: vec![], @@ -211,7 +211,7 @@ mod tests { // The genesis block should be available on reload let result = node_store.get_block_at_id(0); - assert!(!result.is_err()); + assert!(result.is_ok()); } #[test] diff --git a/node_core/src/chain_storage/mod.rs b/node_core/src/chain_storage/mod.rs index 3227512..c470a0a 100644 --- a/node_core/src/chain_storage/mod.rs +++ b/node_core/src/chain_storage/mod.rs @@ -79,7 +79,7 @@ impl NodeChainStore { Ok(( Self { - acc_map: From::from(acc_map), + acc_map, block_store, nullifier_store, utxo_commitments_store, @@ -126,8 +126,9 @@ impl NodeChainStore { let block_id = block.block_id; for tx in &block.transactions { - if !tx.execution_input.is_empty() { - let public_action = serde_json::from_slice::(&tx.execution_input); + if !tx.body().execution_input.is_empty() { + let public_action = + serde_json::from_slice::(&tx.body().execution_input); if let Ok(public_action) = public_action { match public_action { @@ -161,24 +162,25 @@ impl NodeChainStore { } self.utxo_commitments_store.add_tx_multiple( - tx.utxo_commitments_created_hashes + tx.body() + .utxo_commitments_created_hashes .clone() .into_iter() .map(|hash| UTXOCommitment { hash }) .collect(), ); - for nullifier in tx.nullifier_created_hashes.iter() { + for nullifier in tx.body().nullifier_created_hashes.iter() { self.nullifier_store.insert(UTXONullifier { utxo_hash: *nullifier, }); } - if !tx.encoded_data.is_empty() { + if !tx.body().encoded_data.is_empty() { let ephemeral_public_key_sender = - serde_json::from_slice::(&tx.ephemeral_pub_key)?; + serde_json::from_slice::(&tx.body().ephemeral_pub_key)?; - for (ciphertext, nonce, tag) in tx.encoded_data.clone() { + 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); @@ -203,13 +205,13 @@ impl NodeChainStore { } } - self.pub_tx_store.add_tx(tx.clone()); + self.pub_tx_store.add_tx(tx); } self.block_store.put_block_at_id(block)?; //Snapshot - if block_id % self.node_config.shapshot_frequency_in_blocks == 0 { + 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 @@ -241,8 +243,7 @@ impl NodeChainStore { ); info!( - "Snapshot executed at {:?} with results {snapshot_trace:#?}", - block_id + "Snapshot executed at {block_id:?} with results {snapshot_trace:#?}" ); } } @@ -283,7 +284,7 @@ mod tests { use accounts::account_core::Account; use common::block::{Block, Data}; use common::merkle_tree_public::TreeHashType; - use common::transaction::{Transaction, TxKind}; + use common::transaction::{SignaturePrivateKey, Transaction, TransactionBody, TxKind}; use secp256k1_zkp::Tweak; use std::path::PathBuf; use tempfile::tempdir; @@ -306,7 +307,7 @@ mod tests { ) -> Transaction { let mut rng = rand::thread_rng(); - Transaction { + let body = TransactionBody { tx_kind: TxKind::Private, execution_input: vec![], execution_output: vec![], @@ -321,13 +322,14 @@ mod tests { 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: block_id, - prev_block_id: prev_block_id, + block_id, + prev_block_id, prev_block_hash: [0; 32], hash: [1; 32], transactions: vec![], @@ -417,7 +419,7 @@ mod tests { store .utxo_commitments_store .add_tx_multiple(vec![UTXOCommitment { hash: [3u8; 32] }]); - store.pub_tx_store.add_tx(create_dummy_transaction( + store.pub_tx_store.add_tx(&create_dummy_transaction( vec![[9; 32]], vec![[7; 32]], vec![[8; 32]], @@ -435,9 +437,6 @@ mod tests { assert_eq!(block_id, 1); assert_eq!(recovered_store.acc_map.len(), 1); - assert_eq!( - recovered_store.utxo_commitments_store.get_root().is_some(), - true - ); + assert!(recovered_store.utxo_commitments_store.get_root().is_some()); } } diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index 3df8de6..e2c31c5 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -3,7 +3,7 @@ use std::sync::{ Arc, }; -use common::ExecutionFailureKind; +use common::{transaction::Transaction, ExecutionFailureKind}; use accounts::{ account_core::{Account, AccountAddress}, @@ -11,7 +11,7 @@ use accounts::{ }; use anyhow::Result; use chain_storage::NodeChainStore; -use common::transaction::{Transaction, TxKind}; +use common::transaction::{TransactionBody, TxKind}; use config::NodeConfig; use log::info; use sc_core::proofs_circuits::{ @@ -39,7 +39,7 @@ pub mod sequencer_client; fn vec_u8_to_vec_u64(bytes: Vec) -> Vec { // Pad with zeros to make sure it's a multiple of 8 let mut padded = bytes.clone(); - while padded.len() % 8 != 0 { + while !padded.len().is_multiple_of(8) { padded.push(0); } @@ -214,12 +214,11 @@ impl NodeCore { let tag = account.make_tag(); - let comm = generate_commitments(&vec![utxo]); + let comm = generate_commitments(&[utxo]); let mint_utxo_addr_bytes: Vec = zkvm::test_methods::MINT_UTXO_ID .iter() - .map(|num| num.to_le_bytes()) - .flatten() + .flat_map(|num| num.to_le_bytes()) .collect(); let sc_addr = hex::encode(mint_utxo_addr_bytes); @@ -247,31 +246,30 @@ impl NodeCore { let vec_public_info: Vec = vec_values_u64.into_iter().flatten().collect(); let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info); + let transaction_body = TransactionBody { + tx_kind: TxKind::Private, + execution_input: vec![], + execution_output: vec![], + utxo_commitments_spent_hashes: vec![], + utxo_commitments_created_hashes: comm + .into_iter() + .map(|hash_data| hash_data.try_into().unwrap()) + .collect(), + nullifier_created_hashes: vec![], + execution_proof_private: sc_core::transaction_payloads_tools::encode_receipt(receipt) + .unwrap(), + encoded_data: vec![(encoded_data.0, encoded_data.1.to_vec(), tag)], + ephemeral_pub_key: eph_pub_key.to_vec(), + commitment, + tweak, + secret_r, + sc_addr, + state_changes, + }; + let key_to_sign_transaction = account.key_holder.get_pub_account_signing_key(); Ok(( - Transaction { - tx_kind: TxKind::Private, - execution_input: vec![], - execution_output: vec![], - utxo_commitments_spent_hashes: vec![], - utxo_commitments_created_hashes: comm - .into_iter() - .map(|hash_data| hash_data.try_into().unwrap()) - .collect(), - nullifier_created_hashes: vec![], - execution_proof_private: sc_core::transaction_payloads_tools::encode_receipt( - receipt, - ) - .unwrap(), - encoded_data: vec![(encoded_data.0, encoded_data.1.to_vec(), tag)], - ephemeral_pub_key: eph_pub_key.to_vec(), - commitment, - tweak, - secret_r, - sc_addr, - state_changes, - } - .into(), + Transaction::new(transaction_body, key_to_sign_transaction), result_hash, )) } @@ -315,8 +313,7 @@ impl NodeCore { let mint_multiple_utxo_addr_bytes: Vec = zkvm::test_methods::MINT_UTXO_MULTIPLE_ASSETS_ID .iter() - .map(|num| num.to_le_bytes()) - .flatten() + .flat_map(|num| num.to_le_bytes()) .collect(); let sc_addr = hex::encode(mint_multiple_utxo_addr_bytes); @@ -345,30 +342,30 @@ impl NodeCore { let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info); - Ok(( - Transaction { - tx_kind: TxKind::Private, - execution_input: vec![], - execution_output: vec![], - utxo_commitments_spent_hashes: vec![], - utxo_commitments_created_hashes: comm - .into_iter() - .map(|hash_data| hash_data.try_into().unwrap()) - .collect(), - nullifier_created_hashes: vec![], - execution_proof_private: sc_core::transaction_payloads_tools::encode_receipt( - receipt, - ) + let transaction_body = TransactionBody { + tx_kind: TxKind::Private, + execution_input: vec![], + execution_output: vec![], + utxo_commitments_spent_hashes: vec![], + utxo_commitments_created_hashes: comm + .into_iter() + .map(|hash_data| hash_data.try_into().unwrap()) + .collect(), + nullifier_created_hashes: vec![], + execution_proof_private: sc_core::transaction_payloads_tools::encode_receipt(receipt) .unwrap(), - encoded_data, - ephemeral_pub_key: eph_pub_key.to_vec(), - commitment, - tweak, - secret_r, - sc_addr, - state_changes, - } - .into(), + encoded_data, + ephemeral_pub_key: eph_pub_key.to_vec(), + commitment, + tweak, + secret_r, + sc_addr, + state_changes, + }; + let key_to_sign_transaction = account.key_holder.get_pub_account_signing_key(); + + Ok(( + Transaction::new(transaction_body, key_to_sign_transaction), result_hashes, )) } @@ -389,14 +386,13 @@ impl NodeCore { .key_holder .utxo_secret_key_holder .nullifier_secret_key - .to_bytes() - .to_vec(), + .to_bytes(), ); let (resulting_utxos, receipt) = prove_send_utxo(utxo, receivers)?; let utxo_hashes = resulting_utxos .iter() - .map(|(utxo, addr)| (addr.clone(), utxo.hash)) + .map(|(utxo, addr)| (*addr, utxo.hash)) .collect(); let utxos: Vec = resulting_utxos @@ -431,8 +427,7 @@ impl NodeCore { let send_utxo_addr_bytes: Vec = zkvm::test_methods::SEND_UTXO_ID .iter() - .map(|num| num.to_le_bytes()) - .flatten() + .flat_map(|num| num.to_le_bytes()) .collect(); let sc_addr = hex::encode(send_utxo_addr_bytes); @@ -461,30 +456,31 @@ impl NodeCore { let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info); - Ok(( - Transaction { - tx_kind: TxKind::Private, - execution_input: vec![], - execution_output: vec![], - utxo_commitments_spent_hashes: vec![commitment_in], - utxo_commitments_created_hashes: commitments - .into_iter() - .map(|hash_data| hash_data.try_into().unwrap()) - .collect(), - nullifier_created_hashes: vec![nullifier.try_into().unwrap()], - execution_proof_private: sc_core::transaction_payloads_tools::encode_receipt( - receipt, - ) + let transaction_body = TransactionBody { + tx_kind: TxKind::Private, + execution_input: vec![], + execution_output: vec![], + utxo_commitments_spent_hashes: vec![commitment_in], + utxo_commitments_created_hashes: commitments + .into_iter() + .map(|hash_data| hash_data.try_into().unwrap()) + .collect(), + nullifier_created_hashes: vec![nullifier.try_into().unwrap()], + execution_proof_private: sc_core::transaction_payloads_tools::encode_receipt(receipt) .unwrap(), - encoded_data, - ephemeral_pub_key: eph_pub_key.to_vec(), - commitment, - tweak, - secret_r, - sc_addr, - state_changes, - } - .into(), + encoded_data, + ephemeral_pub_key: eph_pub_key.to_vec(), + commitment, + tweak, + secret_r, + sc_addr, + state_changes, + }; + + let key_to_sign_transaction = account.key_holder.get_pub_account_signing_key(); + + Ok(( + Transaction::new(transaction_body, key_to_sign_transaction), utxo_hashes, )) } @@ -576,8 +572,7 @@ impl NodeCore { let send_multiple_utxo_addr_bytes: Vec = zkvm::test_methods::SEND_UTXO_MULTIPLE_ASSETS_ID .iter() - .map(|num| num.to_le_bytes()) - .flatten() + .flat_map(|num| num.to_le_bytes()) .collect(); let sc_addr = hex::encode(send_multiple_utxo_addr_bytes); @@ -606,30 +601,31 @@ impl NodeCore { let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info); - Ok(( - Transaction { - tx_kind: TxKind::Private, - execution_input: vec![], - execution_output: vec![], - utxo_commitments_spent_hashes: commitments_in, - utxo_commitments_created_hashes: commitments - .into_iter() - .map(|hash_data| hash_data.try_into().unwrap()) - .collect(), - nullifier_created_hashes: nullifiers, - execution_proof_private: sc_core::transaction_payloads_tools::encode_receipt( - receipt, - ) + let transaction_body = TransactionBody { + tx_kind: TxKind::Private, + execution_input: vec![], + execution_output: vec![], + utxo_commitments_spent_hashes: commitments_in, + utxo_commitments_created_hashes: commitments + .into_iter() + .map(|hash_data| hash_data.try_into().unwrap()) + .collect(), + nullifier_created_hashes: nullifiers, + execution_proof_private: sc_core::transaction_payloads_tools::encode_receipt(receipt) .unwrap(), - encoded_data, - ephemeral_pub_key: eph_pub_key.to_vec(), - commitment, - tweak, - secret_r, - sc_addr, - state_changes, - } - .into(), + encoded_data, + ephemeral_pub_key: eph_pub_key.to_vec(), + commitment, + tweak, + secret_r, + sc_addr, + state_changes, + }; + + let key_to_sign_transaction = account.key_holder.get_pub_account_signing_key(); + + Ok(( + Transaction::new(transaction_body, key_to_sign_transaction), utxo_hashes_receiver, utxo_hashes_not_spent, )) @@ -657,14 +653,13 @@ impl NodeCore { .key_holder .utxo_secret_key_holder .nullifier_secret_key - .to_bytes() - .to_vec(), + .to_bytes(), ); let (resulting_utxos, receipt) = prove_send_utxo_shielded(acc, balance as u128, receivers)?; let utxo_hashes = resulting_utxos .iter() - .map(|(utxo, addr)| (addr.clone(), utxo.hash)) + .map(|(utxo, addr)| (*addr, utxo.hash)) .collect(); let utxos: Vec = resulting_utxos @@ -699,8 +694,7 @@ impl NodeCore { let mint_utxo_addr_bytes: Vec = zkvm::test_methods::SEND_UTXO_ID .iter() - .map(|num| num.to_le_bytes()) - .flatten() + .flat_map(|num| num.to_le_bytes()) .collect(); let sc_addr = hex::encode(mint_utxo_addr_bytes); @@ -729,36 +723,37 @@ impl NodeCore { let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info); + let transaction_body = TransactionBody { + tx_kind: TxKind::Shielded, + execution_input: serde_json::to_vec(&ActionData::SendMoneyShieldedTx( + SendMoneyShieldedTx { + acc_sender: acc, + amount: balance as u128, + }, + )) + .unwrap(), + execution_output: vec![], + utxo_commitments_spent_hashes: vec![], + utxo_commitments_created_hashes: commitments + .into_iter() + .map(|hash_data| hash_data.try_into().unwrap()) + .collect(), + nullifier_created_hashes: vec![nullifier.try_into().unwrap()], + execution_proof_private: sc_core::transaction_payloads_tools::encode_receipt(receipt) + .unwrap(), + encoded_data, + ephemeral_pub_key: eph_pub_key.to_vec(), + commitment, + tweak, + secret_r, + sc_addr, + state_changes, + }; + + let key_to_sign_transaction = account.key_holder.get_pub_account_signing_key(); + Ok(( - Transaction { - tx_kind: TxKind::Shielded, - execution_input: serde_json::to_vec(&ActionData::SendMoneyShieldedTx( - SendMoneyShieldedTx { - acc_sender: acc, - amount: balance as u128, - }, - )) - .unwrap(), - execution_output: vec![], - utxo_commitments_spent_hashes: vec![], - utxo_commitments_created_hashes: commitments - .into_iter() - .map(|hash_data| hash_data.try_into().unwrap()) - .collect(), - nullifier_created_hashes: vec![nullifier.try_into().unwrap()], - execution_proof_private: sc_core::transaction_payloads_tools::encode_receipt( - receipt, - ) - .unwrap(), - encoded_data, - ephemeral_pub_key: eph_pub_key.to_vec(), - commitment, - tweak, - secret_r, - sc_addr, - state_changes, - } - .into(), + Transaction::new(transaction_body, key_to_sign_transaction), utxo_hashes, )) } @@ -785,16 +780,14 @@ impl NodeCore { .key_holder .utxo_secret_key_holder .nullifier_secret_key - .to_bytes() - .to_vec(), + .to_bytes(), ); let (resulting_balances, receipt) = prove_send_utxo_deshielded(utxo, receivers)?; let send_utxo_addr_bytes: Vec = zkvm::test_methods::SEND_UTXO_ID .iter() - .map(|num| num.to_le_bytes()) - .flatten() + .flat_map(|num| num.to_le_bytes()) .collect(); let sc_addr = hex::encode(send_utxo_addr_bytes); @@ -823,7 +816,7 @@ impl NodeCore { let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info); - Ok(Transaction { + let transaction_body = TransactionBody { tx_kind: TxKind::Deshielded, execution_input: serde_json::to_vec(&ActionData::SendMoneyDeshieldedTx( SendMoneyDeshieldedTx { @@ -844,8 +837,11 @@ impl NodeCore { secret_r, sc_addr, state_changes, - } - .into()) + }; + + let key_to_sign_transaction = account.key_holder.get_pub_account_signing_key(); + + Ok(Transaction::new(transaction_body, key_to_sign_transaction)) } pub async fn send_private_mint_tx( @@ -858,10 +854,10 @@ impl NodeCore { let point_before_prove = std::time::Instant::now(); let (tx, utxo_hash) = self.mint_utxo_private(acc, amount).await?; - tx.log(); + tx.body().log(); let point_after_prove = std::time::Instant::now(); - let commitment_generated_hash = tx.utxo_commitments_created_hashes[0]; + let commitment_generated_hash = tx.body().utxo_commitments_created_hashes[0]; let timedelta = (point_after_prove - point_before_prove).as_millis(); info!("Mint utxo proof spent {timedelta:?} milliseconds"); @@ -886,10 +882,10 @@ impl NodeCore { let (tx, utxo_hashes) = self .mint_utxo_multiple_assets_private(acc, amount, number_of_assets) .await?; - tx.log(); + tx.body().log(); let point_after_prove = std::time::Instant::now(); - let commitment_generated_hashes = tx.utxo_commitments_created_hashes.clone(); + let commitment_generated_hashes = tx.body().utxo_commitments_created_hashes.clone(); let timedelta = (point_after_prove - point_before_prove).as_millis(); info!("Mint utxo proof spent {timedelta:?} milliseconds"); @@ -901,50 +897,50 @@ impl NodeCore { )) } - pub async fn send_public_deposit( - &self, - acc: AccountAddress, - amount: u128, - ) -> Result { - //Considering proof time, needs to be done before proof - let tx_roots = self.get_roots().await; - - let public_context = { - let read_guard = self.storage.read().await; - - read_guard.produce_context(acc) - }; - - let (tweak, secret_r, commitment) = pedersen_commitment_vec( - //Will not panic, as public context is serializable - public_context.produce_u64_list_from_context().unwrap(), - ); - - let sc_addr = hex::encode([0; 32]); - - //Sc does not change its state - let state_changes: Vec = vec![]; - let new_len = 0; - let state_changes = (serde_json::to_value(state_changes).unwrap(), new_len); - - let tx: Transaction = - sc_core::transaction_payloads_tools::create_public_transaction_payload( - serde_json::to_vec(&ActionData::MintMoneyPublicTx(MintMoneyPublicTx { - acc, - amount, - })) - .unwrap(), - commitment, - tweak, - secret_r, - sc_addr, - state_changes, - ) - .into(); - tx.log(); - - Ok(self.sequencer_client.send_tx(tx, tx_roots).await?) - } + // pub async fn send_public_deposit( + // &self, + // acc: AccountAddress, + // amount: u128, + // ) -> Result { + // //Considering proof time, needs to be done before proof + // let tx_roots = self.get_roots().await; + // + // let public_context = { + // let read_guard = self.storage.read().await; + // + // read_guard.produce_context(acc) + // }; + // + // let (tweak, secret_r, commitment) = pedersen_commitment_vec( + // //Will not panic, as public context is serializable + // public_context.produce_u64_list_from_context().unwrap(), + // ); + // + // let sc_addr = hex::encode([0; 32]); + // + // //Sc does not change its state + // let state_changes: Vec = vec![]; + // let new_len = 0; + // let state_changes = (serde_json::to_value(state_changes).unwrap(), new_len); + // + // let tx: TransactionBody = + // sc_core::transaction_payloads_tools::create_public_transaction_payload( + // serde_json::to_vec(&ActionData::MintMoneyPublicTx(MintMoneyPublicTx { + // acc, + // amount, + // })) + // .unwrap(), + // commitment, + // tweak, + // secret_r, + // sc_addr, + // state_changes, + // ) + // .into(); + // tx.log(); + // + // Ok(self.sequencer_client.send_tx(tx, tx_roots).await?) + // } pub async fn send_private_send_tx( &self, @@ -959,7 +955,7 @@ impl NodeCore { let (tx, utxo_hashes) = self .transfer_utxo_private(utxo, comm_hash, receivers) .await?; - tx.log(); + tx.body().log(); let point_after_prove = std::time::Instant::now(); let timedelta = (point_after_prove - point_before_prove).as_millis(); @@ -985,7 +981,7 @@ impl NodeCore { let (tx, utxo_hashes_received, utxo_hashes_not_spent) = self .transfer_utxo_multiple_assets_private(utxos, comm_hashes, number_to_send, receiver) .await?; - tx.log(); + tx.body().log(); let point_after_prove = std::time::Instant::now(); let timedelta = (point_after_prove - point_before_prove).as_millis(); @@ -1011,7 +1007,7 @@ impl NodeCore { let (tx, utxo_hashes) = self .transfer_balance_shielded(acc, amount, receivers) .await?; - tx.log(); + tx.body().log(); let point_after_prove = std::time::Instant::now(); let timedelta = (point_after_prove - point_before_prove).as_millis(); @@ -1036,7 +1032,7 @@ impl NodeCore { let tx = self .transfer_utxo_deshielded(utxo, comm_gen_hash, receivers) .await?; - tx.log(); + tx.body().log(); let point_after_prove = std::time::Instant::now(); let timedelta = (point_after_prove - point_before_prove).as_millis(); @@ -1170,46 +1166,46 @@ impl NodeCore { Ok(()) } - pub async fn operate_account_deposit_public( - &mut self, - acc_addr: AccountAddress, - amount: u128, - ) -> Result<(), ExecutionFailureKind> { - let old_balance = { - let acc_map_read_guard = self.storage.read().await; - - let acc = acc_map_read_guard.acc_map.get(&acc_addr).unwrap(); - - acc.balance - }; - - info!( - "Balance of {:?} now is {old_balance:?}", - hex::encode(acc_addr) - ); - - let resp = self.send_public_deposit(acc_addr, amount).await?; - info!("Response for public deposit is {resp:?}"); - - info!("Awaiting new blocks"); - tokio::time::sleep(std::time::Duration::from_secs(BLOCK_GEN_DELAY_SECS)).await; - - let new_balance = { - let acc_map_read_guard = self.storage.read().await; - - let acc = acc_map_read_guard.acc_map.get(&acc_addr).unwrap(); - - acc.balance - }; - - info!( - "Balance of {:?} now is {new_balance:?}, delta is {:?}", - hex::encode(acc_addr), - new_balance - old_balance - ); - - Ok(()) - } + // pub async fn operate_account_deposit_public( + // &mut self, + // acc_addr: AccountAddress, + // amount: u128, + // ) -> Result<(), ExecutionFailureKind> { + // let old_balance = { + // let acc_map_read_guard = self.storage.read().await; + // + // let acc = acc_map_read_guard.acc_map.get(&acc_addr).unwrap(); + // + // acc.balance + // }; + // + // info!( + // "Balance of {:?} now is {old_balance:?}", + // hex::encode(acc_addr) + // ); + // + // let resp = self.send_public_deposit(acc_addr, amount).await?; + // info!("Response for public deposit is {resp:?}"); + // + // info!("Awaiting new blocks"); + // tokio::time::sleep(std::time::Duration::from_secs(BLOCK_GEN_DELAY_SECS)).await; + // + // let new_balance = { + // let acc_map_read_guard = self.storage.read().await; + // + // let acc = acc_map_read_guard.acc_map.get(&acc_addr).unwrap(); + // + // acc.balance + // }; + // + // info!( + // "Balance of {:?} now is {new_balance:?}, delta is {:?}", + // hex::encode(acc_addr), + // new_balance - old_balance + // ); + // + // Ok(()) + // } pub async fn operate_account_send_shielded_one_receiver( &mut self, @@ -1375,14 +1371,13 @@ impl NodeCore { .key_holder .utxo_secret_key_holder .nullifier_secret_key - .to_bytes() - .to_vec(), + .to_bytes(), ); let (resulting_utxos, receipt) = prove_send_utxo(utxo, receivers)?; let utxo_hashes = resulting_utxos .iter() - .map(|(utxo, addr)| (addr.clone(), utxo.hash)) + .map(|(utxo, addr)| (*addr, utxo.hash)) .collect(); let utxos: Vec = resulting_utxos @@ -1431,8 +1426,7 @@ impl NodeCore { let send_utxo_addr_bytes: Vec = zkvm::test_methods::SEND_UTXO_ID .iter() - .map(|num| num.to_le_bytes()) - .flatten() + .flat_map(|num| num.to_le_bytes()) .collect(); let sc_addr = hex::encode(send_utxo_addr_bytes); @@ -1461,31 +1455,31 @@ impl NodeCore { let (tweak, secret_r, commitment) = pedersen_commitment_vec(vec_public_info); - Ok(( - Transaction { - tx_kind: TxKind::Shielded, - execution_input: vec![], - execution_output: serde_json::to_vec(&publication).unwrap(), - utxo_commitments_spent_hashes: vec![commitment_in], - utxo_commitments_created_hashes: commitments - .clone() - .into_iter() - .map(|hash_data| hash_data.try_into().unwrap()) - .collect(), - nullifier_created_hashes: vec![nullifier.try_into().unwrap()], - execution_proof_private: sc_core::transaction_payloads_tools::encode_receipt( - receipt, - ) + let transaction_body = TransactionBody { + tx_kind: TxKind::Shielded, + execution_input: vec![], + execution_output: serde_json::to_vec(&publication).unwrap(), + utxo_commitments_spent_hashes: vec![commitment_in], + utxo_commitments_created_hashes: commitments + .clone() + .into_iter() + .map(|hash_data| hash_data.try_into().unwrap()) + .collect(), + nullifier_created_hashes: vec![nullifier.try_into().unwrap()], + execution_proof_private: sc_core::transaction_payloads_tools::encode_receipt(receipt) .unwrap(), - encoded_data, - ephemeral_pub_key: eph_pub_key.to_vec(), - commitment, - tweak, - secret_r, - sc_addr, - state_changes, - } - .into(), + encoded_data, + ephemeral_pub_key: eph_pub_key.to_vec(), + commitment, + tweak, + secret_r, + sc_addr, + state_changes, + }; + let key_to_sign_transaction = account.key_holder.get_pub_account_signing_key(); + + Ok(( + Transaction::new(transaction_body, key_to_sign_transaction), utxo_hashes, )) } @@ -1505,13 +1499,13 @@ impl NodeCore { let (tx, utxo_hashes) = self .split_utxo(utxo, comm_hash, receivers, visibility_list) .await?; - tx.log(); + tx.body().log(); let point_after_prove = std::time::Instant::now(); let timedelta = (point_after_prove - point_before_prove).as_millis(); info!("Send private utxo proof spent {timedelta:?} milliseconds"); - let commitments = tx.utxo_commitments_created_hashes.clone(); + let commitments = tx.body().utxo_commitments_created_hashes.clone(); Ok(( self.sequencer_client.send_tx(tx, tx_roots).await?, @@ -1531,10 +1525,7 @@ impl NodeCore { .send_split_tx( utxo.clone(), comm_gen_hash, - addrs_receivers - .clone() - .map(|addr| (utxo.amount / 3, addr)) - .to_vec(), + addrs_receivers.map(|addr| (utxo.amount / 3, addr)).to_vec(), visibility_list, ) .await?; @@ -1585,20 +1576,8 @@ impl NodeCore { Ok(()) } - ///Deposit balance, make it private - pub async fn subscenario_2(&mut self) -> Result<(), ExecutionFailureKind> { - let acc_addr = self.create_new_account().await; - - self.operate_account_deposit_public(acc_addr, 100).await?; - - self.operate_account_send_shielded_one_receiver(acc_addr, acc_addr, 100) - .await?; - - Ok(()) - } - ///Mint utxo, privately send it to another user - pub async fn subscenario_3(&mut self) -> Result<(), ExecutionFailureKind> { + pub async fn subscenario_2(&mut self) -> Result<(), ExecutionFailureKind> { let acc_addr = self.create_new_account().await; let acc_addr_rec = self.create_new_account().await; @@ -1610,21 +1589,8 @@ impl NodeCore { Ok(()) } - ///Deposit balance, shielded send it to another user - pub async fn subscenario_4(&mut self) -> Result<(), ExecutionFailureKind> { - let acc_addr = self.create_new_account().await; - let acc_addr_rec = self.create_new_account().await; - - self.operate_account_deposit_public(acc_addr, 100).await?; - - self.operate_account_send_shielded_one_receiver(acc_addr, acc_addr_rec, 100) - .await?; - - Ok(()) - } - ///Mint utxo, deshielded send it to another user - pub async fn subscenario_5(&mut self) -> Result<(), ExecutionFailureKind> { + pub async fn subscenario_3(&mut self) -> Result<(), ExecutionFailureKind> { let acc_addr = self.create_new_account().await; let acc_addr_rec = self.create_new_account().await; diff --git a/node_core/src/pre_start.rs b/node_core/src/pre_start.rs index fe21e2b..e79dafc 100644 --- a/node_core/src/pre_start.rs +++ b/node_core/src/pre_start.rs @@ -22,8 +22,7 @@ pub async fn setup_empty_sc_states(node: &NodeChainStore) -> Result<()> { let mint_utxo_addr_bytes: Vec = zkvm::test_methods::MINT_UTXO_ID .iter() - .map(|num| num.to_le_bytes()) - .flatten() + .flat_map(|num| num.to_le_bytes()) .collect(); let mint_utxo_addr = hex::encode(mint_utxo_addr_bytes); node.block_store @@ -32,8 +31,7 @@ pub async fn setup_empty_sc_states(node: &NodeChainStore) -> Result<()> { let single_utxo_transfer_addr_bytes: Vec = zkvm::test_methods::SEND_UTXO_ID .iter() - .map(|num| num.to_le_bytes()) - .flatten() + .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( @@ -46,8 +44,7 @@ pub async fn setup_empty_sc_states(node: &NodeChainStore) -> Result<()> { let mint_utxo_multiple_assets_addr_bytes: Vec = zkvm::test_methods::MINT_UTXO_MULTIPLE_ASSETS_ID .iter() - .map(|num| num.to_le_bytes()) - .flatten() + .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( @@ -60,8 +57,7 @@ pub async fn setup_empty_sc_states(node: &NodeChainStore) -> Result<()> { let multiple_assets_utxo_transfer_addr_bytes: Vec = zkvm::test_methods::SEND_UTXO_MULTIPLE_ASSETS_ID .iter() - .map(|num| num.to_le_bytes()) - .flatten() + .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( diff --git a/node_rpc/src/net_utils.rs b/node_rpc/src/net_utils.rs index 6d68b26..215106c 100644 --- a/node_rpc/src/net_utils.rs +++ b/node_rpc/src/net_utils.rs @@ -53,7 +53,7 @@ pub fn new_http_server( polling_config, limits_config, } = config; - info!(target:"network", "Starting http server at {}", addr); + info!(target:"network", "Starting http server at {addr}"); let handler = web::Data::new(JsonHandler { polling_config, node_core_config: node_config, diff --git a/node_rpc/src/process.rs b/node_rpc/src/process.rs index f4937e9..29ac787 100644 --- a/node_rpc/src/process.rs +++ b/node_rpc/src/process.rs @@ -23,8 +23,7 @@ use crate::types::{ ExecuteScenarioSplitResponse, ExecuteSubscenarioRequest, ExecuteSubscenarioResponse, ShowAccountPublicBalanceRequest, ShowAccountPublicBalanceResponse, ShowAccountUTXORequest, ShowAccountUTXOResponse, ShowTransactionRequest, ShowTransactionResponse, - UTXOShortEssentialStruct, WriteDepositPublicBalanceRequest, - WriteDepositPublicBalanceResponse, WriteMintPrivateUTXOMultipleAssetsRequest, + UTXOShortEssentialStruct, WriteMintPrivateUTXOMultipleAssetsRequest, WriteMintPrivateUTXOMultipleAssetsResponse, WriteMintPrivateUTXORequest, WriteMintPrivateUTXOResponse, WriteSendDeshieldedBalanceRequest, WriteSendDeshieldedUTXOResponse, WriteSendPrivateUTXORequest, WriteSendPrivateUTXOResponse, @@ -42,7 +41,6 @@ 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_DEPOSIT_PUBLIC_BALANCE: &str = "write_deposit_public_balance"; 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"; @@ -92,14 +90,6 @@ impl JsonHandler { .subscenario_3() .await .map_err(cast_common_execution_error_into_rpc_error)?, - 4 => store - .subscenario_4() - .await - .map_err(cast_common_execution_error_into_rpc_error)?, - 5 => store - .subscenario_5() - .await - .map_err(cast_common_execution_error_into_rpc_error)?, _ => return Err(RpcErr(RpcError::invalid_params("Scenario id not found"))), } } @@ -312,42 +302,46 @@ impl JsonHandler { ShowTransactionResponse { hash: req.tx_hash, - tx_kind: tx.tx_kind, + tx_kind: tx.body().tx_kind, public_input: if let Ok(action) = - serde_json::from_slice::(&tx.execution_input) + serde_json::from_slice::(&tx.body().execution_input) { action.into_hexed_print() } else { "".to_string() }, public_output: if let Ok(action) = - serde_json::from_slice::(&tx.execution_output) + serde_json::from_slice::(&tx.body().execution_output) { action.into_hexed_print() } else { "".to_string() }, utxo_commitments_created_hashes: tx + .body() .utxo_commitments_created_hashes .iter() - .map(|val| hex::encode(val.clone())) + .map(hex::encode) .collect::>(), utxo_commitments_spent_hashes: tx + .body() .utxo_commitments_spent_hashes .iter() - .map(|val| hex::encode(val.clone())) + .map(hex::encode) .collect::>(), utxo_nullifiers_created_hashes: tx + .body() .nullifier_created_hashes .iter() - .map(|val| hex::encode(val.clone())) + .map(hex::encode) .collect::>(), encoded_data: tx + .body() .encoded_data .iter() .map(|val| (hex::encode(val.0.clone()), hex::encode(val.1.clone()))) .collect::>(), - ephemeral_pub_key: hex::encode(tx.ephemeral_pub_key.clone()), + ephemeral_pub_key: hex::encode(tx.body().ephemeral_pub_key.clone()), } } }; @@ -355,36 +349,6 @@ impl JsonHandler { respond(helperstruct) } - pub async fn process_write_deposit_public_balance( - &self, - request: Request, - ) -> Result { - let req = WriteDepositPublicBalanceRequest::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 mut cover_guard = self.node_chain_store.lock().await; - - cover_guard - .operate_account_deposit_public(acc_addr, req.amount as u128) - .await - .map_err(cast_common_execution_error_into_rpc_error)?; - }; - - let helperstruct = WriteDepositPublicBalanceResponse { - status: SUCCESS.to_string(), - }; - - respond(helperstruct) - } - pub async fn process_write_mint_utxo(&self, request: Request) -> Result { let req = WriteMintPrivateUTXORequest::parse(Some(request.params))?; @@ -529,7 +493,7 @@ impl JsonHandler { utxo_result: UTXOShortEssentialStruct { hash: hex::encode(new_utxo_rec.hash), asset: new_utxo_rec.asset.clone(), - commitment_hash: hex::encode(generate_commitments_helper(&vec![new_utxo_rec])[0]), + commitment_hash: hex::encode(generate_commitments_helper(&[new_utxo_rec])[0]), }, }; @@ -582,7 +546,7 @@ impl JsonHandler { utxo_result: UTXOShortEssentialStruct { hash: hex::encode(new_utxo_rec.hash), asset: new_utxo_rec.asset.clone(), - commitment_hash: hex::encode(generate_commitments_helper(&vec![new_utxo_rec])[0]), + commitment_hash: hex::encode(generate_commitments_helper(&[new_utxo_rec])[0]), }, }; @@ -777,9 +741,6 @@ impl JsonHandler { 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_DEPOSIT_PUBLIC_BALANCE => { - self.process_write_deposit_public_balance(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 diff --git a/sc_core/src/blob_utils.rs b/sc_core/src/blob_utils.rs index d0a3485..d1210ba 100644 --- a/sc_core/src/blob_utils.rs +++ b/sc_core/src/blob_utils.rs @@ -16,19 +16,11 @@ pub fn produce_blob_list_from_sc_public_state( //`ToDo` Replace with `next_chunk` usage, when feature stabilizes in Rust for i in 0..=(ser_data.len() / SC_DATA_BLOB_SIZE) { - let next_chunk: Vec; - - if (i + 1) * SC_DATA_BLOB_SIZE < ser_data.len() { - next_chunk = ser_data[(i * SC_DATA_BLOB_SIZE)..((i + 1) * SC_DATA_BLOB_SIZE)] - .iter() - .cloned() - .collect(); + let next_chunk: Vec = if (i + 1) * SC_DATA_BLOB_SIZE < ser_data.len() { + ser_data[(i * SC_DATA_BLOB_SIZE)..((i + 1) * SC_DATA_BLOB_SIZE)].to_vec() } else { - next_chunk = ser_data[(i * SC_DATA_BLOB_SIZE)..(ser_data.len())] - .iter() - .cloned() - .collect(); - } + ser_data[(i * SC_DATA_BLOB_SIZE)..(ser_data.len())].to_vec() + }; blob_list.push(produce_blob_from_fit_vec(next_chunk)); } @@ -52,11 +44,8 @@ pub fn compare_blob_lists( changed_ids.push(DataBlobChangeVariant::Deleted { id }); } } else if new_len > old_len { - for id in old_len..new_len { - changed_ids.push(DataBlobChangeVariant::Created { - id, - blob: blob_list_new[id], - }); + for (id, blob) in blob_list_new.iter().enumerate().take(new_len).skip(old_len) { + changed_ids.push(DataBlobChangeVariant::Created { id, blob: *blob }); } } diff --git a/sc_core/src/proofs_circuits.rs b/sc_core/src/proofs_circuits.rs index b5627f0..5143922 100644 --- a/sc_core/src/proofs_circuits.rs +++ b/sc_core/src/proofs_circuits.rs @@ -52,10 +52,10 @@ pub fn generate_commitments(input_utxos: &[UTXO]) -> Vec> { /// /// ToDo: Solve it in more scalable way pub fn validate_in_commitments_tree( - in_commitment: &Vec, + in_commitment: &[u8], commitment_tree: &UTXOCommitmentsMerkleTree, ) -> bool { - let alighned_hash: [u8; 32] = in_commitment.clone().try_into().unwrap(); + let alighned_hash: [u8; 32] = in_commitment.try_into().unwrap(); commitment_tree.get_proof(alighned_hash).is_some() } @@ -75,7 +75,7 @@ pub fn private_circuit( ) -> (Vec>, Vec>) { assert!(check_balances_private(input_utxos, output_utxos)); - let in_commitments = generate_commitments(&input_utxos); + let in_commitments = generate_commitments(input_utxos); let mut in_nullifiers = vec![]; @@ -104,7 +104,7 @@ pub fn private_circuit( assert!(!public_context.nullifiers_set.contains(&nullifier)); } - (in_nullifiers, generate_commitments(&output_utxos)) + (in_nullifiers, generate_commitments(output_utxos)) } /// Check balances DE @@ -124,7 +124,7 @@ pub fn deshielded_circuit( ) -> Vec> { assert!(check_balances_de(input_utxos, output_balance)); - let in_commitments = generate_commitments(&input_utxos); + let in_commitments = generate_commitments(input_utxos); let mut in_nullifiers = vec![]; diff --git a/sc_core/src/public_context.rs b/sc_core/src/public_context.rs index 9694fbc..641ce10 100644 --- a/sc_core/src/public_context.rs +++ b/sc_core/src/public_context.rs @@ -77,16 +77,11 @@ impl PublicSCContext { //`ToDo` Replace with `next_chunk` usage, when feature stabilizes in Rust for i in 0..=(ser_data.len() / 8) { - let next_chunk: Vec; - - if (i + 1) * 8 < ser_data.len() { - next_chunk = ser_data[(i * 8)..((i + 1) * 8)].iter().cloned().collect(); + let next_chunk: Vec = if (i + 1) * 8 < ser_data.len() { + ser_data[(i * 8)..((i + 1) * 8)].to_vec() } else { - next_chunk = ser_data[(i * 8)..(ser_data.len())] - .iter() - .cloned() - .collect(); - } + ser_data[(i * 8)..(ser_data.len())].to_vec() + }; u64_list.push(PublicSCContext::produce_u64_from_fit_vec(next_chunk)); } diff --git a/sc_core/src/transaction_payloads_tools.rs b/sc_core/src/transaction_payloads_tools.rs index e819a24..fa0e28e 100644 --- a/sc_core/src/transaction_payloads_tools.rs +++ b/sc_core/src/transaction_payloads_tools.rs @@ -1,6 +1,6 @@ use accounts::{account_core::Account, key_management::ephemeral_key_holder::EphemeralKeyHolder}; use anyhow::Result; -use common::transaction::{Transaction, TxKind}; +use common::transaction::{TransactionBody, TxKind}; use rand::thread_rng; use risc0_zkvm::Receipt; use secp256k1_zkp::{CommitmentSecrets, PedersenCommitment, Tweak}; @@ -15,8 +15,8 @@ pub fn create_public_transaction_payload( secret_r: [u8; 32], sc_addr: String, state_changes: (serde_json::Value, usize), -) -> Transaction { - Transaction { +) -> TransactionBody { + TransactionBody { tx_kind: TxKind::Public, execution_input, execution_output: vec![], @@ -66,8 +66,7 @@ pub fn generate_nullifiers_spent_utxos(utxos_spent: Vec<(UTXO, &Account)>) -> Ve .key_holder .utxo_secret_key_holder .nullifier_secret_key - .to_bytes() - .to_vec(), + .to_bytes(), ); all_nullifiers.push(nullifier); @@ -91,8 +90,7 @@ pub fn generate_secret_random_commitment( .key_holder .utxo_secret_key_holder .viewing_secret_key - .to_bytes() - .to_vec(), + .to_bytes(), )?, generator_blinding_factor: Tweak::new(&mut thread_rng()), }; diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 9067758..bfde1f6 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -6,22 +6,22 @@ use common::{ block::{Block, HashableBlockData}, merkle_tree_public::TreeHashType, nullifier::UTXONullifier, - transaction::{Transaction, TxKind}, + transaction::{AuthenticatedTransaction, Transaction, TransactionBody, TxKind}, utxo_commitment::UTXOCommitment, }; use config::SequencerConfig; use mempool::MemPool; +use mempool_transaction::MempoolTransaction; use sequencer_store::SequecerChainStore; use serde::{Deserialize, Serialize}; -use transaction_mempool::TransactionMempool; pub mod config; +pub mod mempool_transaction; pub mod sequencer_store; -pub mod transaction_mempool; pub struct SequencerCore { pub store: SequecerChainStore, - pub mempool: MemPool, + pub mempool: MemPool, pub sequencer_config: SequencerConfig, pub chain_height: u64, } @@ -36,6 +36,7 @@ pub enum TransactionMalformationErrorKind { MempoolFullForRound { tx: TreeHashType }, ChainStateFurtherThanTransactionState { tx: TreeHashType }, FailedToInsert { tx: TreeHashType, details: String }, + InvalidSignature, } impl Display for TransactionMalformationErrorKind { @@ -55,7 +56,7 @@ impl SequencerCore { config.is_genesis_random, &config.initial_accounts, ), - mempool: MemPool::::default(), + mempool: MemPool::::default(), chain_height: config.genesis_id, sequencer_config: config, } @@ -73,18 +74,23 @@ impl SequencerCore { pub fn transaction_pre_check( &mut self, - tx: &Transaction, + tx: Transaction, tx_roots: [[u8; 32]; 2], - ) -> Result<(), TransactionMalformationErrorKind> { - let Transaction { + ) -> Result { + 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; - let tx_hash = tx.hash(); + } = tx.transaction().body(); + + let tx_hash = *tx.hash(); let mempool_size = self.mempool.len(); @@ -133,73 +139,77 @@ impl SequencerCore { //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() - .map(|nullifier_hash| { - self.store.nullifier_store.contains(&UTXONullifier { - utxo_hash: *nullifier_hash, - }) + let nullifier_tree_check = nullifier_created_hashes.iter().any(|nullifier_hash| { + self.store.nullifier_store.contains(&UTXONullifier { + utxo_hash: *nullifier_hash, }) - .any(|check| check); - let utxo_commitments_check = utxo_commitments_created_hashes - .iter() - .map(|utxo_commitment_hash| { - self.store - .utxo_commitments_store - .get_tx(*utxo_commitment_hash) - .is_some() - }) - .any(|check| check); + }); + 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() }, + TransactionMalformationErrorKind::TxHashAlreadyPresentInTree { tx: *tx.hash() }, ); } if nullifier_tree_check { return Err( - TransactionMalformationErrorKind::NullifierAlreadyPresentInTree { tx: tx.hash() }, + TransactionMalformationErrorKind::NullifierAlreadyPresentInTree { tx: *tx.hash() }, ); } if utxo_commitments_check { return Err( TransactionMalformationErrorKind::UTXOCommitmentAlreadyPresentInTree { - tx: tx.hash(), + tx: *tx.hash(), }, ); } - Ok(()) + Ok(tx) } pub fn push_tx_into_mempool_pre_check( &mut self, - item: TransactionMempool, + transaction: Transaction, tx_roots: [[u8; 32]; 2], ) -> Result<(), TransactionMalformationErrorKind> { - self.transaction_pre_check(&item.tx, tx_roots)?; + 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(), + }); + } - self.mempool.push_item(item); + let authenticated_tx = self.transaction_pre_check(transaction, tx_roots)?; + + self.mempool.push_item(authenticated_tx.into()); Ok(()) } fn execute_check_transaction_on_state( &mut self, - tx: TransactionMempool, + mempool_tx: &MempoolTransaction, ) -> Result<(), TransactionMalformationErrorKind> { - let Transaction { + let TransactionBody { ref utxo_commitments_created_hashes, ref nullifier_created_hashes, .. - } = tx.tx; + } = mempool_tx.auth_tx.transaction().body(); for utxo_comm in utxo_commitments_created_hashes { self.store .utxo_commitments_store - .add_tx(UTXOCommitment { hash: *utxo_comm }); + .add_tx(&UTXOCommitment { hash: *utxo_comm }); } for nullifier in nullifier_created_hashes.iter() { @@ -208,7 +218,9 @@ impl SequencerCore { }); } - self.store.pub_tx_store.add_tx(tx.tx); + self.store + .pub_tx_store + .add_tx(mempool_tx.auth_tx.transaction()); Ok(()) } @@ -226,7 +238,7 @@ impl SequencerCore { .pop_size(self.sequencer_config.max_num_tx_in_block); for tx in &transactions { - self.execute_check_transaction_on_state(tx.clone())?; + self.execute_check_transaction_on_state(tx)?; } let prev_block_hash = self @@ -238,7 +250,10 @@ impl SequencerCore { let hashable_data = HashableBlockData { block_id: new_block_height, prev_block_id: self.chain_height, - transactions: transactions.into_iter().map(|tx_mem| tx_mem.tx).collect(), + transactions: transactions + .into_iter() + .map(|tx_mem| tx_mem.auth_tx.transaction().clone()) + .collect(), data: vec![], prev_block_hash, }; @@ -260,10 +275,10 @@ mod tests { use super::*; use std::path::PathBuf; - use common::transaction::{Transaction, TxKind}; + use common::transaction::{SignaturePrivateKey, Transaction, TransactionBody, TxKind}; + use mempool_transaction::MempoolTransaction; use rand::Rng; use secp256k1_zkp::Tweak; - use transaction_mempool::TransactionMempool; fn setup_sequencer_config_variable_initial_accounts( initial_accounts: Vec, @@ -271,7 +286,7 @@ mod tests { let mut rng = rand::thread_rng(); let random_u8: u8 = rng.gen(); - let path_str = format!("/tmp/sequencer_{:?}", random_u8); + let path_str = format!("/tmp/sequencer_{random_u8:?}"); SequencerConfig { home: PathBuf::from(path_str), @@ -309,7 +324,7 @@ mod tests { ) -> Transaction { let mut rng = rand::thread_rng(); - Transaction { + let body = TransactionBody { tx_kind: TxKind::Private, execution_input: vec![], execution_output: vec![], @@ -324,13 +339,16 @@ mod tests { 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 common_setup(sequencer: &mut SequencerCore) { let tx = create_dummy_transaction(vec![[9; 32]], vec![[7; 32]], vec![[8; 32]]); - let tx_mempool = TransactionMempool { tx }; - sequencer.mempool.push_item(tx_mempool); + let mempool_tx = MempoolTransaction { + auth_tx: tx.into_authenticated().unwrap(), + }; + sequencer.mempool.push_item(mempool_tx); sequencer .produce_new_block_with_mempool_transactions() @@ -346,18 +364,16 @@ mod tests { assert_eq!(sequencer.sequencer_config.max_num_tx_in_block, 10); assert_eq!(sequencer.sequencer_config.port, 8080); - let acc1_addr: [u8; 32] = hex::decode( - "bfd91e6703273a115ad7f099ef32f621243be69369d00ddef5d3a25117d09a8c".to_string(), - ) - .unwrap() - .try_into() - .unwrap(); - let acc2_addr: [u8; 32] = hex::decode( - "20573479053979b98d2ad09ef31a0750f22c77709bed51c4e64946bd1e376f31".to_string(), - ) - .unwrap() - .try_into() - .unwrap(); + let acc1_addr: [u8; 32] = + hex::decode("bfd91e6703273a115ad7f099ef32f621243be69369d00ddef5d3a25117d09a8c") + .unwrap() + .try_into() + .unwrap(); + let acc2_addr: [u8; 32] = + hex::decode("20573479053979b98d2ad09ef31a0750f22c77709bed51c4e64946bd1e376f31") + .unwrap() + .try_into() + .unwrap(); assert!(sequencer.store.acc_store.contains_account(&acc1_addr)); assert!(sequencer.store.acc_store.contains_account(&acc2_addr)); @@ -400,18 +416,16 @@ mod tests { let config = setup_sequencer_config_variable_initial_accounts(initial_accounts); let sequencer = SequencerCore::start_from_config(config.clone()); - let acc1_addr: [u8; 32] = hex::decode( - "bfd91e6703273a115ad7f099ef32f621243be69369d00ddef5d3a25117ffffff".to_string(), - ) - .unwrap() - .try_into() - .unwrap(); - let acc2_addr: [u8; 32] = hex::decode( - "20573479053979b98d2ad09ef31a0750f22c77709bed51c4e64946bd1effffff".to_string(), - ) - .unwrap() - .try_into() - .unwrap(); + let acc1_addr: [u8; 32] = + hex::decode("bfd91e6703273a115ad7f099ef32f621243be69369d00ddef5d3a25117ffffff") + .unwrap() + .try_into() + .unwrap(); + let acc2_addr: [u8; 32] = + hex::decode("20573479053979b98d2ad09ef31a0750f22c77709bed51c4e64946bd1effffff") + .unwrap() + .try_into() + .unwrap(); assert!(sequencer.store.acc_store.contains_account(&acc1_addr)); assert!(sequencer.store.acc_store.contains_account(&acc2_addr)); @@ -456,13 +470,13 @@ mod tests { 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 result = sequencer.transaction_pre_check(tx, tx_roots); assert!(result.is_ok()); } #[test] - fn test_transaction_pre_check_fail_mempool_full() { + fn test_push_tx_into_mempool_fails_mempool_full() { let config = SequencerConfig { max_num_tx_in_block: 1, ..setup_sequencer_config() @@ -475,10 +489,12 @@ mod tests { let tx_roots = sequencer.get_tree_roots(); // Fill the mempool - let dummy_tx = TransactionMempool { tx: tx.clone() }; + let dummy_tx = MempoolTransaction { + auth_tx: tx.clone().into_authenticated().unwrap(), + }; sequencer.mempool.push_item(dummy_tx); - let result = sequencer.transaction_pre_check(&tx, tx_roots); + let result = sequencer.push_tx_into_mempool_pre_check(tx, tx_roots); assert!(matches!( result, @@ -495,9 +511,8 @@ mod tests { let tx = create_dummy_transaction(vec![[93; 32]], vec![[73; 32]], vec![[83; 32]]); let tx_roots = sequencer.get_tree_roots(); - let tx_mempool = TransactionMempool { tx }; - let result = sequencer.push_tx_into_mempool_pre_check(tx_mempool.clone(), tx_roots); + let result = sequencer.push_tx_into_mempool_pre_check(tx, tx_roots); assert!(result.is_ok()); assert_eq!(sequencer.mempool.len(), 1); } @@ -508,7 +523,9 @@ mod tests { let mut sequencer = SequencerCore::start_from_config(config); let tx = create_dummy_transaction(vec![[94; 32]], vec![[7; 32]], vec![[8; 32]]); - let tx_mempool = TransactionMempool { tx }; + let tx_mempool = MempoolTransaction { + auth_tx: tx.into_authenticated().unwrap(), + }; sequencer.mempool.push_item(tx_mempool); let block_id = sequencer.produce_new_block_with_mempool_transactions(); diff --git a/sequencer_core/src/mempool_transaction.rs b/sequencer_core/src/mempool_transaction.rs new file mode 100644 index 0000000..551aaf3 --- /dev/null +++ b/sequencer_core/src/mempool_transaction.rs @@ -0,0 +1,20 @@ +use common::{merkle_tree_public::TreeHashType, transaction::AuthenticatedTransaction}; +use mempool::mempoolitem::MemPoolItem; + +pub struct MempoolTransaction { + pub auth_tx: AuthenticatedTransaction, +} + +impl From for MempoolTransaction { + fn from(auth_tx: AuthenticatedTransaction) -> Self { + Self { auth_tx } + } +} + +impl MemPoolItem for MempoolTransaction { + type Identifier = TreeHashType; + + fn identifier(&self) -> Self::Identifier { + *self.auth_tx.hash() + } +} diff --git a/sequencer_core/src/sequencer_store/accounts_store.rs b/sequencer_core/src/sequencer_store/accounts_store.rs index 853247f..7d64491 100644 --- a/sequencer_core/src/sequencer_store/accounts_store.rs +++ b/sequencer_core/src/sequencer_store/accounts_store.rs @@ -85,6 +85,11 @@ impl SequencerAccountsStore { pub fn len(&self) -> usize { self.accounts.len() } + + ///Is accounts store empty + pub fn is_empty(&self) -> bool { + self.accounts.is_empty() + } } impl Default for SequencerAccountsStore { @@ -213,4 +218,11 @@ mod tests { assert!(acc_balance.is_none()); } + + #[test] + fn account_sequencer_store_is_empty_test() { + let seq_acc_store = SequencerAccountsStore::default(); + + assert!(seq_acc_store.is_empty()); + } } diff --git a/sequencer_core/src/sequencer_store/block_store.rs b/sequencer_core/src/sequencer_store/block_store.rs index 02843fd..dbefdc2 100644 --- a/sequencer_core/src/sequencer_store/block_store.rs +++ b/sequencer_core/src/sequencer_store/block_store.rs @@ -56,7 +56,7 @@ impl SequecerBlockStore { 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.hash() == hash { + if transaction.body().hash() == hash { return Some(transaction); } } @@ -69,17 +69,18 @@ fn block_to_transactions_map(block: &Block) -> HashMap { block .transactions .iter() - .map(|transaction| (transaction.hash(), block.block_id)) + .map(|transaction| (transaction.body().hash(), block.block_id)) .collect() } #[cfg(test)] mod tests { use super::*; + use common::transaction::{SignaturePrivateKey, TransactionBody}; use tempfile::tempdir; fn create_dummy_block_with_transaction(block_id: u64) -> (Block, Transaction) { - let tx = Transaction { + let body = TransactionBody { tx_kind: common::transaction::TxKind::Public, execution_input: Default::default(), execution_output: Default::default(), @@ -95,6 +96,7 @@ mod tests { sc_addr: Default::default(), state_changes: Default::default(), }; + let tx = Transaction::new(body, SignaturePrivateKey::from_slice(&[1; 32]).unwrap()); ( Block { block_id, @@ -125,12 +127,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.hash()); + let retrieved_tx = node_store.get_transaction_by_hash(tx.body().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.hash()); + let retrieved_tx = node_store.get_transaction_by_hash(tx.body().hash()); assert_eq!(Some(tx), retrieved_tx); } } diff --git a/sequencer_core/src/transaction_mempool.rs b/sequencer_core/src/transaction_mempool.rs deleted file mode 100644 index d932b24..0000000 --- a/sequencer_core/src/transaction_mempool.rs +++ /dev/null @@ -1,43 +0,0 @@ -use common::{merkle_tree_public::TreeHashType, transaction::Transaction}; -use mempool::mempoolitem::MemPoolItem; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone)] -pub struct TransactionMempool { - pub tx: Transaction, -} - -impl From for TransactionMempool { - fn from(value: Transaction) -> Self { - Self { tx: value } - } -} - -impl Serialize for TransactionMempool { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - self.tx.serialize(serializer) - } -} - -impl<'de> Deserialize<'de> for TransactionMempool { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - match Transaction::deserialize(deserializer) { - Ok(tx) => Ok(TransactionMempool { tx }), - Err(err) => Err(err), - } - } -} - -impl MemPoolItem for TransactionMempool { - type Identifier = TreeHashType; - - fn identifier(&self) -> Self::Identifier { - self.tx.hash() - } -} diff --git a/sequencer_rpc/src/net_utils.rs b/sequencer_rpc/src/net_utils.rs index 38e4e38..c421f17 100644 --- a/sequencer_rpc/src/net_utils.rs +++ b/sequencer_rpc/src/net_utils.rs @@ -53,7 +53,7 @@ pub fn new_http_server( polling_config, limits_config, } = config; - info!(target:NETWORK, "Starting http server at {}", addr); + info!(target:NETWORK, "Starting http server at {addr}"); let handler = web::Data::new(JsonHandler { polling_config, sequencer_state: seuquencer_core.clone(), diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index f8dc7da..d25b3ea 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -85,10 +85,7 @@ impl JsonHandler { { let mut state = self.sequencer_state.lock().await; - state.push_tx_into_mempool_pre_check( - send_tx_req.transaction.into(), - send_tx_req.tx_roots, - )?; + state.push_tx_into_mempool_pre_check(send_tx_req.transaction, send_tx_req.tx_roots)?; } let helperstruct = SendTxResponse { @@ -202,10 +199,12 @@ mod tests { use std::sync::Arc; use crate::{rpc_handler, JsonHandler}; - use common::{rpc_primitives::RpcPollingConfig, transaction::Transaction}; + use common::{ + rpc_primitives::RpcPollingConfig, + transaction::{SignaturePrivateKey, Transaction, TransactionBody}, + }; use sequencer_core::{ config::{AccountInitialData, SequencerConfig}, - transaction_mempool::TransactionMempool, SequencerCore, }; use serde_json::Value; @@ -241,7 +240,7 @@ mod tests { fn json_handler_for_tests() -> JsonHandler { let config = sequencer_config_for_tests(); let mut sequencer_core = SequencerCore::start_from_config(config); - let tx = Transaction { + let tx_body = TransactionBody { tx_kind: common::transaction::TxKind::Public, execution_input: Default::default(), execution_output: Default::default(), @@ -257,9 +256,10 @@ mod tests { sc_addr: Default::default(), state_changes: Default::default(), }; + let tx = Transaction::new(tx_body, SignaturePrivateKey::from_slice(&[1; 32]).unwrap()); sequencer_core - .push_tx_into_mempool_pre_check(TransactionMempool { tx }, [[0; 32]; 2]) + .push_tx_into_mempool_pre_check(tx, [[0; 32]; 2]) .unwrap(); sequencer_core .produce_new_block_with_mempool_transactions() @@ -443,20 +443,24 @@ mod tests { "jsonrpc": "2.0", "result": { "transaction": { - "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": "Public", - "utxo_commitments_created_hashes": [], - "utxo_commitments_spent_hashes": [] + "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": "Public", + "utxo_commitments_created_hashes": [], + "utxo_commitments_spent_hashes": [] + }, + "public_key": "3056301006072A8648CE3D020106052B8104000A034200041B84C5567B126440995D3ED5AABA0565D71E1834604819FF9C17F5E9D5DD078F70BEAF8F588B541507FED6A642C5AB42DFDF8120A7F639DE5122D47A69A8E8D1", + "signature": "28CB6CA744864340A3441CB48D5700690F90130DE0760EE5C640F85F4285C5FD2BD7D0E270EC2AC82E4124999E63659AA9C33CF378F959EDF4E50F2626EA3B99" } } }); diff --git a/storage/src/lib.rs b/storage/src/lib.rs index 7616842..ac54406 100644 --- a/storage/src/lib.rs +++ b/storage/src/lib.rs @@ -316,7 +316,7 @@ impl RocksDBIO { let cf_sc = self.sc_column(); let sc_addr_loc = format!("{sc_addr:?}{SC_LEN_SUFFIX}"); - let sc_len_addr = sc_addr_loc.as_str().as_bytes(); + let sc_len_addr = sc_addr_loc.as_bytes(); self.db .put_cf(&cf_sc, sc_len_addr, length.to_be_bytes()) @@ -360,7 +360,7 @@ impl RocksDBIO { let cf_sc = self.sc_column(); let sc_addr_loc = format!("{sc_addr:?}{SC_LEN_SUFFIX}"); - let sc_len_addr = sc_addr_loc.as_str().as_bytes(); + let sc_len_addr = sc_addr_loc.as_bytes(); let sc_len = self .db @@ -379,11 +379,11 @@ impl RocksDBIO { ///Get full sc state from DB pub fn get_sc_sc_state(&self, sc_addr: &str) -> DbResult> { let cf_sc = self.sc_column(); - let sc_len = self.get_sc_sc_state_len(&sc_addr)?; + let sc_len = self.get_sc_sc_state_len(sc_addr)?; let mut data_blob_list = vec![]; for id in 0..sc_len { - let blob_addr = produce_address_for_data_blob_at_id(&sc_addr, id); + let blob_addr = produce_address_for_data_blob_at_id(sc_addr, id); let blob = self .db @@ -541,7 +541,7 @@ impl RocksDBIO { ///Creates address for sc data blob at corresponding id fn produce_address_for_data_blob_at_id(sc_addr: &str, id: usize) -> Vec { - let mut prefix_bytes: Vec = sc_addr.as_bytes().iter().cloned().collect(); + let mut prefix_bytes: Vec = sc_addr.as_bytes().to_vec(); let id_bytes = id.to_be_bytes(); diff --git a/storage/src/sc_db_utils.rs b/storage/src/sc_db_utils.rs index 3ef12c5..c86828e 100644 --- a/storage/src/sc_db_utils.rs +++ b/storage/src/sc_db_utils.rs @@ -49,6 +49,7 @@ impl DataBlob { } } +#[allow(clippy::large_enum_variant)] #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] pub enum DataBlobChangeVariant { Created { @@ -145,7 +146,7 @@ mod tests { #[test] fn test_produce_blob_from_fit_vec() { - let data = (0..0 + 255).collect(); + let data = (0..255).collect(); let blob = produce_blob_from_fit_vec(data); assert_eq!(blob.0[..4], [0, 1, 2, 3]); } diff --git a/utxo/src/utxo_core.rs b/utxo/src/utxo_core.rs index 4e40ce3..07a8830 100644 --- a/utxo/src/utxo_core.rs +++ b/utxo/src/utxo_core.rs @@ -58,7 +58,7 @@ impl UTXO { } pub fn create_utxo_from_payload(payload_with_asset: UTXOPayload) -> Self { let mut hasher = sha2::Sha256::new(); - hasher.update(&payload_with_asset.to_bytes()); + hasher.update(payload_with_asset.to_bytes()); let hash = ::from(hasher.finalize_fixed()); Self { diff --git a/zkvm/src/lib.rs b/zkvm/src/lib.rs index 075657e..9f0940c 100644 --- a/zkvm/src/lib.rs +++ b/zkvm/src/lib.rs @@ -9,6 +9,7 @@ pub mod gas_calculator; pub use test_methods; +#[allow(clippy::result_large_err)] pub fn gas_limits_check( input_buffer: INP, elf: &[u8], @@ -31,6 +32,7 @@ pub fn gas_limits_check( Ok(()) } +#[allow(clippy::result_large_err)] pub fn prove_mint_utxo( amount_to_mint: u128, owner: AccountAddress, @@ -66,6 +68,7 @@ pub fn prove_mint_utxo( Ok((UTXO::create_utxo_from_payload(digest), receipt)) } +#[allow(clippy::result_large_err)] pub fn prove_send_utxo( spent_utxo: UTXO, owners_parts: Vec<(u128, AccountAddress)>, @@ -118,6 +121,7 @@ pub fn prove_send_utxo( )) } +#[allow(clippy::result_large_err)] pub fn prove_send_utxo_multiple_assets_one_receiver( spent_utxos: Vec, number_to_send: usize, @@ -160,17 +164,18 @@ pub fn prove_send_utxo_multiple_assets_one_receiver( digest .0 .into_iter() - .map(|payload| UTXO::create_utxo_from_payload(payload)) + .map(UTXO::create_utxo_from_payload) .collect(), digest .1 .into_iter() - .map(|payload| UTXO::create_utxo_from_payload(payload)) + .map(UTXO::create_utxo_from_payload) .collect(), receipt, )) } +#[allow(clippy::result_large_err)] pub fn prove_send_utxo_shielded( owner: AccountAddress, amount: u128, @@ -226,6 +231,7 @@ pub fn prove_send_utxo_shielded( )) } +#[allow(clippy::result_large_err)] pub fn prove_send_utxo_deshielded( spent_utxo: UTXO, owners_parts: Vec<(u128, AccountAddress)>, @@ -278,6 +284,7 @@ pub fn prove_send_utxo_deshielded( )) } +#[allow(clippy::result_large_err)] pub fn prove_mint_utxo_multiple_assets( amount_to_mint: u128, number_of_assets: usize,