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-ff = "0.5.0"
tiny-keccak = { version = "2.0.2", features = ["keccak"] }
base64 = "0.22.1"
rocksdb = { version = "0.21.0", default-features = false, features = [
"snappy",

View File

@ -1,36 +1,33 @@
use std::io::{Cursor, Read};
use rs_merkle::Hasher;
use serde::{Deserialize, Serialize};
use crate::merkle_tree_public::hasher::OwnHasher;
use nssa;
pub type BlockHash = [u8; 32];
pub type Data = Vec<u8>;
pub type BlockId = u64;
#[derive(Debug, Serialize, Deserialize, Clone)]
#[derive(Debug, Clone)]
pub struct Block {
pub block_id: BlockId,
pub prev_block_id: BlockId,
pub prev_block_hash: BlockHash,
pub hash: BlockHash,
pub transactions: Vec<nssa::PublicTransaction>,
pub data: Data,
}
#[derive(Debug, Serialize, Deserialize)]
#[derive(Debug, PartialEq, Eq)]
pub struct HashableBlockData {
pub block_id: BlockId,
pub prev_block_id: BlockId,
pub prev_block_hash: BlockHash,
pub transactions: Vec<nssa::PublicTransaction>,
pub data: Data,
}
impl From<HashableBlockData> for Block {
fn from(value: HashableBlockData) -> Self {
let data = serde_json::to_vec(&value).unwrap();
let data = value.to_bytes();
let hash = OwnHasher::hash(&data);
Self {
@ -38,8 +35,87 @@ impl From<HashableBlockData> for Block {
prev_block_id: value.prev_block_id,
hash,
transactions: value.transactions,
data: value.data,
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)]
pub struct SendTxRequest {
pub transaction: nssa::PublicTransaction,
pub transaction: Vec<u8>
}
#[derive(Serialize, Deserialize, Debug)]
@ -71,7 +71,7 @@ pub struct SendTxResponse {
#[derive(Serialize, Deserialize, Debug)]
pub struct GetBlockDataResponse {
pub block: Block,
pub block: Vec<u8>,
}
#[derive(Serialize, Deserialize, Debug)]
@ -91,5 +91,5 @@ pub struct GetAccountBalanceResponse {
#[derive(Serialize, Deserialize, Debug)]
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)]
pub struct SendTxRequest {
pub transaction: nssa::PublicTransaction,
pub transaction: Vec<u8>,
}
//Responses

View File

@ -91,7 +91,7 @@ impl SequencerClient {
&self,
transaction: nssa::PublicTransaction,
) -> Result<SendTxResponse, SequencerClientError> {
let tx_req = SendTxRequest { transaction };
let tx_req = SendTxRequest { transaction: transaction.to_bytes() };
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
///
/// `transactions` - vector of `Transaction` objects
///
/// `additional_data` - vector with additional data
pub fn produce_dummy_block(
id: u64,
prev_hash: Option<[u8; 32]>,
transactions: Vec<nssa::PublicTransaction>,
additional_data: Vec<u8>,
) -> Block {
let block_data = HashableBlockData {
block_id: id,
prev_block_id: id.saturating_sub(1),
prev_block_hash: prev_hash.unwrap_or_default(),
transactions,
data: additional_data,
};
block_data.into()

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

View File

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

View File

@ -89,14 +89,13 @@ mod tests {
prev_block_hash: [0; 32],
hash: [1; 32],
transactions: vec![],
data: vec![],
};
// Start an empty node store
let mut node_store =
SequecerBlockStore::open_db_with_genesis(path, Some(genesis_block)).unwrap();
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.
let retrieved_tx = node_store.get_transaction_by_hash(tx.hash());

View File

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

View File

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

View File

@ -1,9 +1,13 @@
use std::io::Cursor;
use actix_web::Error as HttpError;
use base64::{engine::general_purpose, Engine};
use nssa;
use sequencer_core::config::AccountInitialData;
use serde_json::Value;
use common::{
block::HashableBlockData,
merkle_tree_public::TreeHashType,
rpc_primitives::{
errors::RpcError,
@ -68,11 +72,15 @@ impl JsonHandler {
async fn process_send_tx(&self, request: Request) -> Result<Value, RpcErr> {
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;
state.push_tx_into_mempool_pre_check(send_tx_req.transaction)?;
state.push_tx_into_mempool_pre_check(tx)?;
}
let helperstruct = SendTxResponse {
@ -94,7 +102,9 @@ impl JsonHandler {
.get_block_at_id(get_block_req.block_id)?
};
let helperstruct = GetBlockDataResponse { block };
let helperstruct = GetBlockDataResponse {
block: HashableBlockData::from(block).to_bytes(),
};
respond(helperstruct)
}
@ -177,9 +187,16 @@ impl JsonHandler {
let transaction = {
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)
}
@ -217,15 +234,13 @@ mod tests {
let tempdir = tempdir().unwrap();
let home = tempdir.path().to_path_buf();
let acc1_addr = vec![
// 13, 150, 223, 204, 65, 64, 25, 56, 12, 157, 222, 12, 211, 220, 229, 170, 201, 15, 181,
// 68, 59, 248, 113, 16, 135, 65, 174, 175, 222, 85, 42, 215,
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,
];
let acc2_addr = vec![
// 151, 72, 112, 233, 190, 141, 10, 192, 138, 168, 59, 63, 199, 167, 166, 134, 41, 29,
// 135, 50, 80, 138, 186, 152, 179, 96, 128, 243, 156, 44, 243, 100,
2; 32
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,
];
let initial_acc1 = AccountInitialData {
@ -264,7 +279,10 @@ mod tests {
let signing_key = nssa::PrivateKey::try_new([1; 32]).unwrap();
let balance_to_move = 10;
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,
[2; 32],
balance_to_move,
@ -490,25 +508,9 @@ mod tests {
"id": 1,
"jsonrpc": "2.0",
"result": {
"transaction": {
"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]
]
}
}
"transaction": "TlNTQS92MC4xL1R4TWVzc2FnZTYHPd+eRGuYF2kuC9CQp8t7bp1UuMIyqCp4yOzP4zCBAgAAABuExVZ7EmRAmV0+1aq6BWXXHhg0YEgZ/5wX9enV3QePAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIBAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAKAAAAAAAAAAAAAAAAAAAAAQAAAKvsz0Lg2apthMPOsOhYarLVuZmMeUYDneKtr95L7Ia6C+Z3/dw3CAtb2wIa4/Ow5JwatpstOGwC9uS2mySzf9UbhMVWexJkQJldPtWqugVl1x4YNGBIGf+cF/Xp1d0Hjw==",
}
});
let response = call_rpc_handler_with_json(json_handler, request).await;
assert_eq!(response, expected_response);

View File

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

View File

@ -80,11 +80,11 @@ mod tests {
fn create_initial_accounts() -> Vec<Account> {
let initial_acc1 = serde_json::from_str(r#"{
"address": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
"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,
"key_holder": {
"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": {
"secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4"
},
@ -98,11 +98,11 @@ mod tests {
}"#).unwrap();
let initial_acc2 = serde_json::from_str(r#"{
"address": [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
"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,
"key_holder": {
"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": {
"secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179"
},