fix: suggestions fix

This commit is contained in:
Oleksandr Pravdyvyi 2025-09-08 10:11:04 +03:00
parent 5747070e39
commit 0e1905ad22
No known key found for this signature in database
GPG Key ID: 9F8955C63C443871
19 changed files with 131 additions and 100 deletions

View File

@ -1,7 +1,7 @@
use rs_merkle::Hasher;
use std::io::{Cursor, Read};
use crate::{OwnHasher, transaction::TransactionBody};
use crate::{OwnHasher, transaction::EncodedTransaction};
pub type BlockHash = [u8; 32];
pub type BlockId = u64;
@ -10,7 +10,6 @@ pub type TimeStamp = u64;
#[derive(Debug, Clone)]
pub struct BlockHeader {
pub block_id: BlockId,
pub prev_block_id: BlockId,
pub prev_block_hash: BlockHash,
pub hash: BlockHash,
pub timestamp: TimeStamp,
@ -19,7 +18,7 @@ pub struct BlockHeader {
#[derive(Debug, Clone)]
pub struct BlockBody {
pub transactions: Vec<TransactionBody>,
pub transactions: Vec<EncodedTransaction>,
}
#[derive(Debug, Clone)]
@ -31,10 +30,9 @@ pub struct Block {
#[derive(Debug, PartialEq, Eq)]
pub struct HashableBlockData {
pub block_id: BlockId,
pub prev_block_id: BlockId,
pub prev_block_hash: BlockHash,
pub timestamp: TimeStamp,
pub transactions: Vec<TransactionBody>,
pub transactions: Vec<EncodedTransaction>,
}
impl HashableBlockData {
@ -45,7 +43,6 @@ impl HashableBlockData {
Block {
header: BlockHeader {
block_id: self.block_id,
prev_block_id: self.prev_block_id,
prev_block_hash: self.prev_block_hash,
hash,
timestamp: self.timestamp,
@ -62,7 +59,6 @@ impl From<Block> for HashableBlockData {
fn from(value: Block) -> Self {
Self {
block_id: value.header.block_id,
prev_block_id: value.header.prev_block_id,
prev_block_hash: value.header.prev_block_hash,
timestamp: value.header.timestamp,
transactions: value.body.transactions,
@ -74,7 +70,6 @@ impl HashableBlockData {
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.extend_from_slice(&self.block_id.to_le_bytes());
bytes.extend_from_slice(&self.prev_block_id.to_le_bytes());
bytes.extend_from_slice(&self.prev_block_hash);
bytes.extend_from_slice(&self.timestamp.to_le_bytes());
let num_transactions: u32 = self.transactions.len() as u32;
@ -94,7 +89,6 @@ impl HashableBlockData {
let mut cursor = Cursor::new(data);
let block_id = u64_from_cursor(&mut cursor);
let prev_block_id = u64_from_cursor(&mut cursor);
let mut prev_block_hash = [0u8; 32];
cursor.read_exact(&mut prev_block_hash).unwrap();
@ -114,13 +108,12 @@ impl HashableBlockData {
tx_bytes.push(buff[0]);
}
let tx = TransactionBody::from_bytes(tx_bytes);
let tx = EncodedTransaction::from_bytes(tx_bytes);
transactions.push(tx);
}
Self {
block_id,
prev_block_id,
prev_block_hash,
timestamp,
transactions,

View File

@ -12,7 +12,7 @@ use crate::rpc_primitives::requests::{
GetTransactionByHashResponse,
};
use crate::sequencer_client::json::AccountInitialData;
use crate::transaction::TransactionBody;
use crate::transaction::{EncodedTransaction, NSSATransaction};
use crate::{SequencerClientError, SequencerRpcError};
pub mod json;
@ -132,7 +132,7 @@ impl SequencerClient {
&self,
transaction: nssa::PublicTransaction,
) -> Result<SendTxResponse, SequencerClientError> {
let transaction = TransactionBody::from(nssa::NSSATransaction::Public(transaction));
let transaction = EncodedTransaction::from(NSSATransaction::Public(transaction));
let tx_req = SendTxRequest {
transaction: transaction.to_bytes(),

View File

@ -1,8 +1,6 @@
use nssa::NSSATransaction;
use crate::{
block::{Block, HashableBlockData},
transaction::TransactionBody,
transaction::{EncodedTransaction, NSSATransaction},
};
//Helpers
@ -19,15 +17,14 @@ pub fn sequencer_sign_key_for_testing() -> nssa::PrivateKey {
///
/// `prev_hash` - hash of previous block, provide None for genesis
///
/// `transactions` - vector of `AuthenticatedTransaction` objects
/// `transactions` - vector of `EncodedTransaction` objects
pub fn produce_dummy_block(
id: u64,
prev_hash: Option<[u8; 32]>,
transactions: Vec<TransactionBody>,
transactions: Vec<EncodedTransaction>,
) -> Block {
let block_data = HashableBlockData {
block_id: id,
prev_block_id: id.saturating_sub(1),
prev_block_hash: prev_hash.unwrap_or_default(),
timestamp: id * 100,
transactions,
@ -36,7 +33,7 @@ pub fn produce_dummy_block(
block_data.into_block(&sequencer_sign_key_for_testing())
}
pub fn produce_dummy_empty_transaction() -> TransactionBody {
pub fn produce_dummy_empty_transaction() -> EncodedTransaction {
let program_id = nssa::program::Program::authenticated_transfer_program().id();
let addresses = vec![];
let nonces = vec![];
@ -49,7 +46,7 @@ pub fn produce_dummy_empty_transaction() -> TransactionBody {
let nssa_tx = nssa::PublicTransaction::new(message, witness_set);
TransactionBody::from(NSSATransaction::Public(nssa_tx))
EncodedTransaction::from(NSSATransaction::Public(nssa_tx))
}
pub fn create_transaction_native_token_transfer(
@ -58,7 +55,7 @@ pub fn create_transaction_native_token_transfer(
to: [u8; 32],
balance_to_move: u128,
signing_key: nssa::PrivateKey,
) -> TransactionBody {
) -> EncodedTransaction {
let addresses = vec![nssa::Address::new(from), nssa::Address::new(to)];
let nonces = vec![nonce];
let program_id = nssa::program::Program::authenticated_transfer_program().id();
@ -69,5 +66,5 @@ pub fn create_transaction_native_token_transfer(
let nssa_tx = nssa::PublicTransaction::new(message, witness_set);
TransactionBody::from(NSSATransaction::Public(nssa_tx))
EncodedTransaction::from(NSSATransaction::Public(nssa_tx))
}

View File

@ -10,6 +10,24 @@ use elliptic_curve::{
};
use sha2::digest::typenum::{UInt, UTerm};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NSSATransaction {
Public(nssa::PublicTransaction),
PrivacyPreserving(nssa::PrivacyPreservingTransaction),
}
impl From<nssa::PublicTransaction> for NSSATransaction {
fn from(value: nssa::PublicTransaction) -> Self {
Self::Public(value)
}
}
impl From<nssa::PrivacyPreservingTransaction> for NSSATransaction {
fn from(value: nssa::PrivacyPreservingTransaction) -> Self {
Self::PrivacyPreserving(value)
}
}
use crate::TreeHashType;
pub type CipherText = Vec<u8>;
@ -24,20 +42,20 @@ pub enum TxKind {
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
///General transaction object
pub struct TransactionBody {
pub struct EncodedTransaction {
pub tx_kind: TxKind,
///Encoded blobs of data
pub encoded_transaction_data: Vec<u8>,
}
impl From<nssa::NSSATransaction> for TransactionBody {
fn from(value: nssa::NSSATransaction) -> Self {
impl From<NSSATransaction> for EncodedTransaction {
fn from(value: NSSATransaction) -> Self {
match value {
nssa::NSSATransaction::Public(tx) => Self {
NSSATransaction::Public(tx) => Self {
tx_kind: TxKind::Public,
encoded_transaction_data: tx.to_bytes(),
},
nssa::NSSATransaction::PrivacyPreserving(tx) => Self {
NSSATransaction::PrivacyPreserving(tx) => Self {
tx_kind: TxKind::PrivacyPreserving,
encoded_transaction_data: tx.to_bytes(),
},
@ -45,10 +63,10 @@ impl From<nssa::NSSATransaction> for TransactionBody {
}
}
impl TryFrom<&TransactionBody> for nssa::NSSATransaction {
impl TryFrom<&EncodedTransaction> for NSSATransaction {
type Error = nssa::error::NssaError;
fn try_from(value: &TransactionBody) -> Result<Self, Self::Error> {
fn try_from(value: &EncodedTransaction) -> Result<Self, Self::Error> {
match value.tx_kind {
TxKind::Public => nssa::PublicTransaction::from_bytes(&value.encoded_transaction_data)
.map(|tx| tx.into()),
@ -153,7 +171,7 @@ impl ActionData {
}
}
impl TransactionBody {
impl EncodedTransaction {
/// 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();
@ -189,11 +207,11 @@ mod tests {
use crate::{
TreeHashType,
transaction::{TransactionBody, TxKind},
transaction::{EncodedTransaction, TxKind},
};
fn test_transaction_body() -> TransactionBody {
TransactionBody {
fn test_transaction_body() -> EncodedTransaction {
EncodedTransaction {
tx_kind: TxKind::Public,
encoded_transaction_data: vec![1, 2, 3, 4],
}
@ -219,7 +237,7 @@ mod tests {
let body = test_transaction_body();
let body_bytes = body.to_bytes();
let body_new = TransactionBody::from_bytes(body_bytes);
let body_new = EncodedTransaction::from_bytes(body_bytes);
assert_eq!(body, body_new);
}

2
nssa/src/encoding/mod.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod privacy_preserving_transaction;
pub mod public_transaction;

View File

@ -10,12 +10,12 @@ use crate::{
Address, PrivacyPreservingTransaction, PublicKey, Signature,
error::NssaError,
privacy_preserving_transaction::{
circuit::Proof, message::EncryptedAccountData, witness_set::WitnessSet,
circuit::Proof,
message::{EncryptedAccountData, Message},
witness_set::WitnessSet,
},
};
use super::message::Message;
const MESSAGE_ENCODING_PREFIX_LEN: usize = 22;
const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] = b"\x01/NSSA/v0.1/TxMessage/";

View File

@ -1,4 +1,5 @@
pub mod address;
pub mod encoding;
pub mod error;
mod merkle_tree;
mod privacy_preserving_transaction;
@ -16,21 +17,3 @@ pub use signature::PrivateKey;
pub use signature::PublicKey;
pub use signature::Signature;
pub use state::V01State;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum NSSATransaction {
Public(PublicTransaction),
PrivacyPreserving(PrivacyPreservingTransaction),
}
impl From<PublicTransaction> for NSSATransaction {
fn from(value: PublicTransaction) -> Self {
Self::Public(value)
}
}
impl From<PrivacyPreservingTransaction> for NSSATransaction {
fn from(value: PrivacyPreservingTransaction) -> Self {
Self::PrivacyPreserving(value)
}
}

View File

@ -14,7 +14,7 @@ use program_methods::{PRIVACY_PRESERVING_CIRCUIT_ELF, PRIVACY_PRESERVING_CIRCUIT
/// Proof of the privacy preserving execution circuit
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Proof(Vec<u8>);
pub struct Proof(pub(super) Vec<u8>);
impl Proof {
pub(crate) fn is_valid_for(&self, circuit_output: &PrivacyPreservingCircuitOutput) -> bool {
@ -34,7 +34,14 @@ impl Proof {
pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Result<Self, NssaError> {
let proof_len = u32_from_cursor(cursor) as usize;
let mut proof = Vec::with_capacity(proof_len);
cursor.read_exact(&mut proof)?;
for _ in 0..proof_len {
let mut one_byte_buf = [0u8];
cursor.read_exact(&mut one_byte_buf)?;
proof.push(one_byte_buf[0]);
}
Ok(Self(proof))
}
}

View File

@ -1,4 +1,3 @@
mod encoding;
pub mod message;
pub mod transaction;
pub mod witness_set;

View File

@ -167,3 +167,42 @@ fn n_unique<T: Eq + Hash>(data: &[T]) -> usize {
let set: HashSet<&T> = data.iter().collect();
set.len()
}
#[cfg(test)]
mod tests {
use crate::{
Address, PrivacyPreservingTransaction, PrivateKey, PublicKey,
privacy_preserving_transaction::{
circuit::Proof, message::tests::message_for_tests, witness_set::WitnessSet,
},
};
fn keys_for_tests() -> (PrivateKey, PrivateKey, Address, Address) {
let key1 = PrivateKey::try_new([1; 32]).unwrap();
let key2 = PrivateKey::try_new([2; 32]).unwrap();
let addr1 = Address::from(&PublicKey::new_from_private_key(&key1));
let addr2 = Address::from(&PublicKey::new_from_private_key(&key2));
(key1, key2, addr1, addr2)
}
fn proof_for_tests() -> Proof {
Proof(vec![1, 2, 3, 4, 5])
}
fn transaction_for_tests() -> PrivacyPreservingTransaction {
let (key1, key2, _, _) = keys_for_tests();
let message = message_for_tests();
let witness_set = WitnessSet::for_message(&message, proof_for_tests(), &[&key1, &key2]);
PrivacyPreservingTransaction::new(message, witness_set)
}
#[test]
fn test_privacy_preserving_transaction_encoding_bytes_roundtrip() {
let tx = transaction_for_tests();
let bytes = tx.to_bytes();
let tx_from_bytes = PrivacyPreservingTransaction::from_bytes(&bytes).unwrap();
assert_eq!(tx, tx_from_bytes);
}
}

View File

@ -5,8 +5,8 @@ use crate::{
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WitnessSet {
pub(super) signatures_and_public_keys: Vec<(Signature, PublicKey)>,
pub(super) proof: Proof,
pub(crate) signatures_and_public_keys: Vec<(Signature, PublicKey)>,
pub(crate) proof: Proof,
}
impl WitnessSet {

View File

@ -1,4 +1,3 @@
mod encoding;
mod message;
mod transaction;
mod witness_set;

View File

@ -2,7 +2,7 @@ use crate::{PrivateKey, PublicKey, Signature, public_transaction::Message};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WitnessSet {
pub(super) signatures_and_public_keys: Vec<(Signature, PublicKey)>,
pub(crate) signatures_and_public_keys: Vec<(Signature, PublicKey)>,
}
impl WitnessSet {

View File

@ -1,11 +1,14 @@
use std::fmt::Display;
use anyhow::Result;
use common::{TreeHashType, block::HashableBlockData, transaction::TransactionBody};
use common::{
TreeHashType,
block::HashableBlockData,
transaction::{EncodedTransaction, NSSATransaction},
};
use config::SequencerConfig;
use log::{info, warn};
use log::warn;
use mempool::MemPool;
use nssa::NSSATransaction;
use sequencer_store::SequecerChainStore;
use serde::{Deserialize, Serialize};
@ -14,7 +17,7 @@ pub mod sequencer_store;
pub struct SequencerCore {
pub store: SequecerChainStore,
pub mempool: MemPool<TransactionBody>,
pub mempool: MemPool<EncodedTransaction>,
pub sequencer_config: SequencerConfig,
pub chain_height: u64,
}
@ -85,7 +88,7 @@ impl SequencerCore {
pub fn push_tx_into_mempool_pre_check(
&mut self,
transaction: TransactionBody,
transaction: EncodedTransaction,
) -> Result<(), TransactionMalformationErrorKind> {
let transaction = NSSATransaction::try_from(&transaction).map_err(|_| {
TransactionMalformationErrorKind::FailedToDecode {
@ -93,8 +96,6 @@ impl SequencerCore {
}
})?;
info!("Transaction got {transaction:#?}");
let mempool_size = self.mempool.len();
if mempool_size >= self.sequencer_config.max_num_tx_in_block {
return Err(TransactionMalformationErrorKind::MempoolFullForRound);
@ -135,24 +136,23 @@ impl SequencerCore {
pub fn produce_new_block_with_mempool_transactions(&mut self) -> Result<u64> {
let new_block_height = self.chain_height + 1;
let transactions = self
.mempool
.pop_size(self.sequencer_config.max_num_tx_in_block);
let mut num_valid_transactions_in_block = 0;
let mut valid_transactions = vec![];
let mut nssa_transactions = vec![];
for tx in transactions {
while let Some(tx) = self.mempool.pop_last() {
let nssa_transaction = NSSATransaction::try_from(&tx)
.map_err(|_| TransactionMalformationErrorKind::FailedToDecode { tx: tx.hash() })?;
nssa_transactions.push(nssa_transaction);
}
if let Ok(valid_tx) = self.execute_check_transaction_on_state(nssa_transaction) {
valid_transactions.push(valid_tx.into());
let valid_transactions: Vec<_> = nssa_transactions
.into_iter()
.filter_map(|tx| self.execute_check_transaction_on_state(tx).ok())
.map(Into::into)
.collect();
num_valid_transactions_in_block += 1;
if num_valid_transactions_in_block >= self.sequencer_config.max_num_tx_in_block {
break;
}
}
}
let prev_block_hash = self
.store
@ -165,7 +165,6 @@ impl SequencerCore {
let hashable_data = HashableBlockData {
block_id: new_block_height,
prev_block_id: self.chain_height,
transactions: valid_transactions,
prev_block_hash,
timestamp: curr_time,
@ -189,7 +188,7 @@ mod tests {
use super::*;
fn parse_unwrap_tx_body_into_nssa_tx(tx_body: TransactionBody) -> NSSATransaction {
fn parse_unwrap_tx_body_into_nssa_tx(tx_body: EncodedTransaction) -> NSSATransaction {
NSSATransaction::try_from(&tx_body)
.map_err(|_| TransactionMalformationErrorKind::FailedToDecode { tx: tx_body.hash() })
.unwrap()

View File

@ -1,7 +1,7 @@
use std::{collections::HashMap, path::Path};
use anyhow::Result;
use common::{TreeHashType, block::Block, transaction::TransactionBody};
use common::{TreeHashType, block::Block, transaction::EncodedTransaction};
use storage::RocksDBIO;
pub struct SequecerBlockStore {
@ -57,7 +57,7 @@ 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<TransactionBody> {
pub fn get_transaction_by_hash(&self, hash: TreeHashType) -> Option<EncodedTransaction> {
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 {
@ -96,7 +96,6 @@ mod tests {
let genesis_block_hashable_data = HashableBlockData {
block_id: 0,
prev_block_id: 0,
prev_block_hash: [0; 32],
timestamp: 0,
transactions: vec![],

View File

@ -41,7 +41,6 @@ impl SequecerChainStore {
let hashable_data = HashableBlockData {
block_id: genesis_id,
prev_block_id: genesis_id.saturating_sub(1),
transactions: vec![],
prev_block_hash,
timestamp: curr_time,

View File

@ -18,7 +18,7 @@ use common::{
GetTransactionByHashResponse,
},
},
transaction::TransactionBody,
transaction::EncodedTransaction,
};
use common::rpc_primitives::requests::{
@ -75,7 +75,7 @@ impl JsonHandler {
async fn process_send_tx(&self, request: Request) -> Result<Value, RpcErr> {
let send_tx_req = SendTxRequest::parse(Some(request.params))?;
let tx = TransactionBody::from_bytes(send_tx_req.transaction);
let tx = EncodedTransaction::from_bytes(send_tx_req.transaction);
let tx_hash = hex::encode(tx.hash());
{
@ -280,7 +280,7 @@ mod tests {
use base64::{Engine, engine::general_purpose};
use common::{
rpc_primitives::RpcPollingConfig, test_utils::sequencer_sign_key_for_testing,
transaction::TransactionBody,
transaction::EncodedTransaction,
};
use sequencer_core::{
@ -329,7 +329,7 @@ mod tests {
}
}
fn components_for_tests() -> (JsonHandler, Vec<AccountInitialData>, TransactionBody) {
fn components_for_tests() -> (JsonHandler, Vec<AccountInitialData>, EncodedTransaction) {
let config = sequencer_config_for_tests();
let mut sequencer_core = SequencerCore::start_from_config(config);
let initial_accounts = sequencer_core.sequencer_config.initial_accounts.clone();

View File

@ -4,7 +4,7 @@ use base64::Engine;
use common::{
ExecutionFailureKind,
sequencer_client::{SequencerClient, json::SendTxResponse},
transaction::TransactionBody,
transaction::{EncodedTransaction, NSSATransaction},
};
use anyhow::Result;
@ -146,16 +146,13 @@ impl WalletCore {
}
///Poll transactions
pub async fn poll_public_native_token_transfer(
&self,
hash: String,
) -> Result<nssa::NSSATransaction> {
pub async fn poll_public_native_token_transfer(&self, hash: String) -> Result<NSSATransaction> {
let transaction_encoded = self.poller.poll_tx(hash).await?;
let tx_base64_decode =
base64::engine::general_purpose::STANDARD.decode(transaction_encoded)?;
let pub_tx = TransactionBody::from_bytes(tx_base64_decode);
let pub_tx = EncodedTransaction::from_bytes(tx_base64_decode);
Ok(nssa::NSSATransaction::try_from(&pub_tx)?)
Ok(NSSATransaction::try_from(&pub_tx)?)
}
}