refactor all

This commit is contained in:
Sergio Chouhy 2025-08-12 12:18:13 -03:00
parent bab1112251
commit 82907f5d8f
14 changed files with 138 additions and 70 deletions

View File

@ -43,6 +43,7 @@ light-poseidon = "0.3.0"
ark-bn254 = "0.5.0" ark-bn254 = "0.5.0"
ark-ff = "0.5.0" ark-ff = "0.5.0"
tiny-keccak = { version = "2.0.2", features = ["keccak"] } tiny-keccak = { version = "2.0.2", features = ["keccak"] }
base64 = "0.22.1"
rocksdb = { version = "0.21.0", default-features = false, features = [ rocksdb = { version = "0.21.0", default-features = false, features = [
"snappy", "snappy",

View File

@ -1,36 +1,33 @@
use std::io::{Cursor, Read};
use rs_merkle::Hasher; use rs_merkle::Hasher;
use serde::{Deserialize, Serialize};
use crate::merkle_tree_public::hasher::OwnHasher; use crate::merkle_tree_public::hasher::OwnHasher;
use nssa; use nssa;
pub type BlockHash = [u8; 32]; pub type BlockHash = [u8; 32];
pub type Data = Vec<u8>;
pub type BlockId = u64; pub type BlockId = u64;
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Clone)]
pub struct Block { pub struct Block {
pub block_id: BlockId, pub block_id: BlockId,
pub prev_block_id: BlockId, pub prev_block_id: BlockId,
pub prev_block_hash: BlockHash, pub prev_block_hash: BlockHash,
pub hash: BlockHash, pub hash: BlockHash,
pub transactions: Vec<nssa::PublicTransaction>, pub transactions: Vec<nssa::PublicTransaction>,
pub data: Data,
} }
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, PartialEq, Eq)]
pub struct HashableBlockData { pub struct HashableBlockData {
pub block_id: BlockId, pub block_id: BlockId,
pub prev_block_id: BlockId, pub prev_block_id: BlockId,
pub prev_block_hash: BlockHash, pub prev_block_hash: BlockHash,
pub transactions: Vec<nssa::PublicTransaction>, pub transactions: Vec<nssa::PublicTransaction>,
pub data: Data,
} }
impl From<HashableBlockData> for Block { impl From<HashableBlockData> for Block {
fn from(value: HashableBlockData) -> Self { fn from(value: HashableBlockData) -> Self {
let data = serde_json::to_vec(&value).unwrap(); let data = value.to_bytes();
let hash = OwnHasher::hash(&data); let hash = OwnHasher::hash(&data);
Self { Self {
@ -38,8 +35,87 @@ impl From<HashableBlockData> for Block {
prev_block_id: value.prev_block_id, prev_block_id: value.prev_block_id,
hash, hash,
transactions: value.transactions, transactions: value.transactions,
data: value.data,
prev_block_hash: value.prev_block_hash, prev_block_hash: value.prev_block_hash,
} }
} }
} }
impl From<Block> for HashableBlockData {
fn from(value: Block) -> Self {
Self {
block_id: value.block_id,
prev_block_id: value.prev_block_id,
prev_block_hash: value.prev_block_hash,
transactions: value.transactions,
}
}
}
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);
let num_transactions: u32 = self.transactions.len() as u32;
bytes.extend_from_slice(&num_transactions.to_le_bytes());
for tx in &self.transactions {
bytes.extend_from_slice(&tx.to_bytes());
}
bytes
}
pub fn from_bytes(data: &[u8]) -> Self {
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();
let num_transactions = u32_from_cursor(&mut cursor) as usize;
let mut transactions = Vec::with_capacity(num_transactions);
for _ in 0..num_transactions {
let tx = nssa::PublicTransaction::from_cursor(&mut cursor);
transactions.push(tx);
}
Self {
block_id,
prev_block_id,
prev_block_hash,
transactions,
}
}
}
fn u32_from_cursor(cursor: &mut Cursor<&[u8]>) -> u32 {
let mut word_buf = [0u8; 4];
cursor.read_exact(&mut word_buf).unwrap();
u32::from_le_bytes(word_buf)
}
fn u64_from_cursor(cursor: &mut Cursor<&[u8]>) -> u64 {
let mut word_buf = [0u8; 8];
cursor.read_exact(&mut word_buf).unwrap();
u64::from_le_bytes(word_buf)
}
#[cfg(test)]
mod tests {
use crate::{block::HashableBlockData, test_utils};
#[test]
fn test() {
let transactions = vec![test_utils::produce_dummy_empty_transaction()];
let block = test_utils::produce_dummy_block(1, Some([1; 32]), transactions);
let hashable = HashableBlockData::from(block);
let bytes = hashable.to_bytes();
let recov = HashableBlockData::from_bytes(&bytes);
assert_eq!(hashable, recov);
}
}

View File

@ -17,7 +17,7 @@ pub struct RegisterAccountRequest {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct SendTxRequest { pub struct SendTxRequest {
pub transaction: nssa::PublicTransaction, pub transaction: Vec<u8>
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -71,7 +71,7 @@ pub struct SendTxResponse {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct GetBlockDataResponse { pub struct GetBlockDataResponse {
pub block: Block, pub block: Vec<u8>,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@ -91,5 +91,5 @@ pub struct GetAccountBalanceResponse {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct GetTransactionByHashResponse { pub struct GetTransactionByHashResponse {
pub transaction: Option<nssa::PublicTransaction>, pub transaction: Option<String>,
} }

View File

@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct SendTxRequest { pub struct SendTxRequest {
pub transaction: nssa::PublicTransaction, pub transaction: Vec<u8>,
} }
//Responses //Responses

View File

@ -91,7 +91,7 @@ impl SequencerClient {
&self, &self,
transaction: nssa::PublicTransaction, transaction: nssa::PublicTransaction,
) -> Result<SendTxResponse, SequencerClientError> { ) -> Result<SendTxResponse, SequencerClientError> {
let tx_req = SendTxRequest { transaction }; let tx_req = SendTxRequest { transaction: transaction.to_bytes() };
let req = serde_json::to_value(tx_req)?; let req = serde_json::to_value(tx_req)?;

View File

@ -11,20 +11,16 @@ use crate::block::{Block, HashableBlockData};
/// `prev_hash` - hash of previous block, provide None for genesis /// `prev_hash` - hash of previous block, provide None for genesis
/// ///
/// `transactions` - vector of `Transaction` objects /// `transactions` - vector of `Transaction` objects
///
/// `additional_data` - vector with additional data
pub fn produce_dummy_block( pub fn produce_dummy_block(
id: u64, id: u64,
prev_hash: Option<[u8; 32]>, prev_hash: Option<[u8; 32]>,
transactions: Vec<nssa::PublicTransaction>, transactions: Vec<nssa::PublicTransaction>,
additional_data: Vec<u8>,
) -> Block { ) -> Block {
let block_data = HashableBlockData { let block_data = HashableBlockData {
block_id: id, block_id: id,
prev_block_id: id.saturating_sub(1), prev_block_id: id.saturating_sub(1),
prev_block_hash: prev_hash.unwrap_or_default(), prev_block_hash: prev_hash.unwrap_or_default(),
transactions, transactions,
data: additional_data,
}; };
block_data.into() block_data.into()

View File

@ -47,16 +47,15 @@ impl PublicTransaction {
} }
} }
fn to_bytes(&self) -> Vec<u8> { pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = self.message.message_to_bytes(); let mut bytes = self.message.message_to_bytes();
bytes.extend_from_slice(&self.witness_set.to_bytes()); bytes.extend_from_slice(&self.witness_set.to_bytes());
bytes bytes
} }
fn from_bytes(bytes: &[u8]) -> Self { pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Self {
let mut cursor = Cursor::new(bytes); let message = Message::from_cursor(cursor);
let message = Message::from_cursor(&mut cursor); let witness_set = WitnessSet::from_cursor(cursor);
let witness_set = WitnessSet::from_cursor(&mut cursor);
Self { Self {
message, message,
witness_set, witness_set,
@ -137,6 +136,8 @@ impl PublicTransaction {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::io::Cursor;
use crate::{ use crate::{
Address, PrivateKey, PublicTransaction, PublicKey, Address, PrivateKey, PublicTransaction, PublicKey,
program::Program, program::Program,
@ -163,7 +164,8 @@ mod tests {
let tx = PublicTransaction::new(message, witness_set); let tx = PublicTransaction::new(message, witness_set);
let bytes = tx.to_bytes(); let bytes = tx.to_bytes();
let recov_tx = PublicTransaction::from_bytes(&bytes); let mut cursor: Cursor<&[u8]> = Cursor::new(&bytes);
let recov_tx = PublicTransaction::from_cursor(&mut cursor);
assert_eq!(tx, recov_tx); assert_eq!(tx, recov_tx);
} }
} }

View File

@ -120,7 +120,6 @@ impl SequencerCore {
block_id: new_block_height, block_id: new_block_height,
prev_block_id: self.chain_height, prev_block_id: self.chain_height,
transactions: valid_transactions, transactions: valid_transactions,
data: vec![],
prev_block_hash, prev_block_hash,
}; };

View File

@ -89,14 +89,13 @@ mod tests {
prev_block_hash: [0; 32], prev_block_hash: [0; 32],
hash: [1; 32], hash: [1; 32],
transactions: vec![], transactions: vec![],
data: vec![],
}; };
// Start an empty node store // Start an empty node store
let mut node_store = let mut node_store =
SequecerBlockStore::open_db_with_genesis(path, Some(genesis_block)).unwrap(); SequecerBlockStore::open_db_with_genesis(path, Some(genesis_block)).unwrap();
let tx = common::test_utils::produce_dummy_empty_transaction(); let tx = common::test_utils::produce_dummy_empty_transaction();
let block = common::test_utils::produce_dummy_block(1, None, vec![tx.clone()], vec![]); let block = common::test_utils::produce_dummy_block(1, None, vec![tx.clone()]);
// Try retrieve a tx that's not in the chain yet. // 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.hash());

View File

@ -49,7 +49,6 @@ impl SequecerChainStore {
block_id: genesis_id, block_id: genesis_id,
prev_block_id: genesis_id.saturating_sub(1), prev_block_id: genesis_id.saturating_sub(1),
transactions: vec![], transactions: vec![],
data: data.to_vec(),
prev_block_hash, prev_block_hash,
}; };

View File

@ -14,6 +14,7 @@ actix-cors.workspace = true
futures.workspace = true futures.workspace = true
hex.workspace = true hex.workspace = true
tempfile.workspace = true tempfile.workspace = true
base64.workspace = true
actix-web.workspace = true actix-web.workspace = true
tokio.workspace = true tokio.workspace = true

View File

@ -1,9 +1,13 @@
use std::io::Cursor;
use actix_web::Error as HttpError; use actix_web::Error as HttpError;
use base64::{engine::general_purpose, Engine};
use nssa; use nssa;
use sequencer_core::config::AccountInitialData; use sequencer_core::config::AccountInitialData;
use serde_json::Value; use serde_json::Value;
use common::{ use common::{
block::HashableBlockData,
merkle_tree_public::TreeHashType, merkle_tree_public::TreeHashType,
rpc_primitives::{ rpc_primitives::{
errors::RpcError, errors::RpcError,
@ -68,11 +72,15 @@ impl JsonHandler {
async fn process_send_tx(&self, request: Request) -> Result<Value, RpcErr> { async fn process_send_tx(&self, request: Request) -> Result<Value, RpcErr> {
let send_tx_req = SendTxRequest::parse(Some(request.params))?; let send_tx_req = SendTxRequest::parse(Some(request.params))?;
let tx = {
let mut cursor: Cursor<&[u8]> = Cursor::new(&send_tx_req.transaction);
nssa::PublicTransaction::from_cursor(&mut cursor)
};
{ {
let mut state = self.sequencer_state.lock().await; let mut state = self.sequencer_state.lock().await;
state.push_tx_into_mempool_pre_check(send_tx_req.transaction)?; state.push_tx_into_mempool_pre_check(tx)?;
} }
let helperstruct = SendTxResponse { let helperstruct = SendTxResponse {
@ -94,7 +102,9 @@ impl JsonHandler {
.get_block_at_id(get_block_req.block_id)? .get_block_at_id(get_block_req.block_id)?
}; };
let helperstruct = GetBlockDataResponse { block }; let helperstruct = GetBlockDataResponse {
block: HashableBlockData::from(block).to_bytes(),
};
respond(helperstruct) respond(helperstruct)
} }
@ -177,9 +187,16 @@ impl JsonHandler {
let transaction = { let transaction = {
let state = self.sequencer_state.lock().await; let state = self.sequencer_state.lock().await;
state.store.block_store.get_transaction_by_hash(hash) state
.store
.block_store
.get_transaction_by_hash(hash)
.map(|tx| tx.to_bytes())
};
let base64_encoded = transaction.map(|tx| general_purpose::STANDARD.encode(tx));
let helperstruct = GetTransactionByHashResponse {
transaction: base64_encoded,
}; };
let helperstruct = GetTransactionByHashResponse { transaction };
respond(helperstruct) respond(helperstruct)
} }
@ -217,15 +234,13 @@ mod tests {
let tempdir = tempdir().unwrap(); let tempdir = tempdir().unwrap();
let home = tempdir.path().to_path_buf(); let home = tempdir.path().to_path_buf();
let acc1_addr = vec![ let acc1_addr = vec![
// 13, 150, 223, 204, 65, 64, 25, 56, 12, 157, 222, 12, 211, 220, 229, 170, 201, 15, 181, 27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, 24,
// 68, 59, 248, 113, 16, 135, 65, 174, 175, 222, 85, 42, 215, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143,
1; 32
]; ];
let acc2_addr = vec![ let acc2_addr = vec![
// 151, 72, 112, 233, 190, 141, 10, 192, 138, 168, 59, 63, 199, 167, 166, 134, 41, 29, 77, 75, 108, 209, 54, 16, 50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217, 234,
// 135, 50, 80, 138, 186, 152, 179, 96, 128, 243, 156, 44, 243, 100, 216, 10, 201, 66, 51, 116, 196, 81, 167, 37, 77, 7, 102,
2; 32
]; ];
let initial_acc1 = AccountInitialData { let initial_acc1 = AccountInitialData {
@ -264,7 +279,10 @@ mod tests {
let signing_key = nssa::PrivateKey::try_new([1; 32]).unwrap(); let signing_key = nssa::PrivateKey::try_new([1; 32]).unwrap();
let balance_to_move = 10; let balance_to_move = 10;
let tx = common::test_utils::create_transaction_native_token_transfer( let tx = common::test_utils::create_transaction_native_token_transfer(
[1; 32], [
27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30,
24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143,
],
0, 0,
[2; 32], [2; 32],
balance_to_move, balance_to_move,
@ -490,25 +508,9 @@ mod tests {
"id": 1, "id": 1,
"jsonrpc": "2.0", "jsonrpc": "2.0",
"result": { "result": {
"transaction": { "transaction": "TlNTQS92MC4xL1R4TWVzc2FnZTYHPd+eRGuYF2kuC9CQp8t7bp1UuMIyqCp4yOzP4zCBAgAAABuExVZ7EmRAmV0+1aq6BWXXHhg0YEgZ/5wX9enV3QePAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIBAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAKAAAAAAAAAAAAAAAAAAAAAQAAAKvsz0Lg2apthMPOsOhYarLVuZmMeUYDneKtr95L7Ia6C+Z3/dw3CAtb2wIa4/Ow5JwatpstOGwC9uS2mySzf9UbhMVWexJkQJldPtWqugVl1x4YNGBIGf+cF/Xp1d0Hjw==",
"message": {
"addresses": [
{ "value": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] },
{ "value": [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2] }
],
"instruction_data": [10, 0, 0, 0],
"nonces": [0],
"program_id": nssa::program::Program::authenticated_transfer_program().id(),
},
"witness_set": {
"signatures_and_public_keys": [
[1, 1]
]
}
}
} }
}); });
let response = call_rpc_handler_with_json(json_handler, request).await; let response = call_rpc_handler_with_json(json_handler, request).await;
assert_eq!(response, expected_response); assert_eq!(response, expected_response);

View File

@ -1,6 +1,6 @@
use std::{path::Path, sync::Arc}; use std::{path::Path, sync::Arc};
use common::block::Block; use common::block::{Block, HashableBlockData};
use error::DbError; use error::DbError;
use rocksdb::{ use rocksdb::{
BoundColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, MultiThreaded, Options, BoundColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, MultiThreaded, Options,
@ -242,12 +242,7 @@ impl RocksDBIO {
.put_cf( .put_cf(
&cf_block, &cf_block,
block.block_id.to_be_bytes(), block.block_id.to_be_bytes(),
serde_json::to_vec(&block).map_err(|serr| { HashableBlockData::from(block).to_bytes(),
DbError::serde_cast_message(
serr,
Some("Block Serialization failed".to_string()),
)
})?,
) )
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
Ok(()) Ok(())
@ -261,9 +256,7 @@ impl RocksDBIO {
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?; .map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
if let Some(data) = res { if let Some(data) = res {
Ok(serde_json::from_slice::<Block>(&data).map_err(|serr| { Ok(HashableBlockData::from_bytes(&data).into())
DbError::serde_cast_message(serr, Some("Block Deserialization failed".to_string()))
})?)
} else { } else {
Err(DbError::db_interaction_error( Err(DbError::db_interaction_error(
"Block on this id not found".to_string(), "Block on this id not found".to_string(),

View File

@ -80,11 +80,11 @@ mod tests {
fn create_initial_accounts() -> Vec<Account> { fn create_initial_accounts() -> Vec<Account> {
let initial_acc1 = serde_json::from_str(r#"{ let initial_acc1 = serde_json::from_str(r#"{
"address": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], "address": [27, 132, 197, 86, 123, 18, 100, 64, 153, 93, 62, 213, 170, 186, 5, 101, 215, 30, 24, 52, 96, 72, 25, 255, 156, 23, 245, 233, 213, 221, 7, 143],
"balance": 100, "balance": 100,
"key_holder": { "key_holder": {
"nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718", "nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718",
"pub_account_signing_key": 1, "pub_account_signing_key": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
"top_secret_key_holder": { "top_secret_key_holder": {
"secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4" "secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4"
}, },
@ -98,11 +98,11 @@ mod tests {
}"#).unwrap(); }"#).unwrap();
let initial_acc2 = serde_json::from_str(r#"{ let initial_acc2 = serde_json::from_str(r#"{
"address": [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2], "address": [77, 75, 108, 209, 54, 16, 50, 202, 155, 210, 174, 185, 217, 0, 170, 77, 69, 217, 234, 216, 10, 201, 66, 51, 116, 196, 81, 167, 37, 77, 7, 102],
"balance": 200, "balance": 200,
"key_holder": { "key_holder": {
"nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271", "nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271",
"pub_account_signing_key": 2, "pub_account_signing_key": [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
"top_secret_key_holder": { "top_secret_key_holder": {
"secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179" "secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179"
}, },