fix: checks added

This commit is contained in:
Oleksandr Pravdyvyi 2025-09-03 10:29:51 +03:00
parent 6efac43210
commit b4f21b2f09
No known key found for this signature in database
GPG Key ID: 9F8955C63C443871
26 changed files with 259 additions and 751 deletions

View File

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

View File

@ -1,9 +1,7 @@
use rs_merkle::Hasher;
use std::io::{Cursor, Read};
use k256::ecdsa::Signature;
use rs_merkle::Hasher;
use crate::{merkle_tree_public::hasher::OwnHasher, transaction::AuthenticatedTransaction};
use crate::{transaction::TransactionBody, OwnHasher};
pub type BlockHash = [u8; 32];
pub type BlockId = u64;
@ -16,12 +14,12 @@ pub struct BlockHeader {
pub prev_block_hash: BlockHash,
pub hash: BlockHash,
pub timestamp: TimeStamp,
pub signature: Signature,
pub signature: nssa::Signature,
}
#[derive(Debug, Clone)]
pub struct BlockBody {
pub transactions: Vec<AuthenticatedTransaction>,
pub transactions: Vec<TransactionBody>,
}
#[derive(Debug, Clone)]
@ -36,26 +34,25 @@ pub struct HashableBlockData {
pub prev_block_id: BlockId,
pub prev_block_hash: BlockHash,
pub timestamp: TimeStamp,
pub signature: Signature,
pub transactions: Vec<AuthenticatedTransaction>,
pub transactions: Vec<TransactionBody>,
}
impl From<HashableBlockData> for Block {
fn from(value: HashableBlockData) -> Self {
let data = value.to_bytes();
let hash = OwnHasher::hash(&data);
Self {
impl HashableBlockData {
pub fn into_block(self, signing_key: &nssa::PrivateKey) -> Block {
let data_bytes = self.to_bytes();
let signature = nssa::Signature::new(signing_key, &data_bytes);
let hash = OwnHasher::hash(&data_bytes);
Block {
header: BlockHeader {
block_id: value.block_id,
prev_block_id: value.prev_block_id,
prev_block_hash: value.prev_block_hash,
block_id: self.block_id,
prev_block_id: self.prev_block_id,
prev_block_hash: self.prev_block_hash,
hash,
timestamp: value.timestamp,
signature: value.signature,
timestamp: self.timestamp,
signature,
},
body: BlockBody {
transactions: value.transactions,
transactions: self.transactions,
},
}
}
@ -68,7 +65,6 @@ impl From<Block> for HashableBlockData {
prev_block_id: value.header.prev_block_id,
prev_block_hash: value.header.prev_block_hash,
timestamp: value.header.timestamp,
signature: value.header.signature,
transactions: value.body.transactions,
}
}
@ -81,10 +77,13 @@ impl HashableBlockData {
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());
bytes.extend_from_slice(&self.signature.to_bytes());
let num_transactions: u32 = self.transactions.len() as u32;
bytes.extend_from_slice(&num_transactions.to_le_bytes());
for tx in &self.transactions {
let transaction_bytes = tx.to_bytes();
let num_transaction_bytes: u32 = transaction_bytes.len() as u32;
bytes.extend_from_slice(&num_transaction_bytes.to_le_bytes());
bytes.extend_from_slice(&tx.to_bytes());
}
bytes
@ -101,17 +100,21 @@ impl HashableBlockData {
cursor.read_exact(&mut prev_block_hash).unwrap();
let timestamp = u64_from_cursor(&mut cursor);
let signature_bytes_len = u32_from_cursor(&mut cursor) as usize;
let mut signature_bytes = Vec::with_capacity(signature_bytes_len);
cursor.read_exact(&mut signature_bytes).unwrap();
let signature = Signature::from_bytes(signature_bytes.as_slice().try_into().unwrap()).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 = AuthenticatedTransaction::from_cursor(&mut cursor);
let tx_len = u32_from_cursor(&mut cursor) as usize;
let mut tx_bytes = Vec::with_capacity(tx_len);
for _ in 0..tx_len {
let mut buff = [0; 1];
cursor.read_exact(&mut buff).unwrap();
tx_bytes.push(buff[0]);
}
let tx = TransactionBody::from_bytes(tx_bytes);
transactions.push(tx);
}
@ -120,7 +123,6 @@ impl HashableBlockData {
prev_block_id,
prev_block_hash,
timestamp,
signature,
transactions,
}
}

View File

@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};
use crate::merkle_tree_public::CommitmentHashType;
use crate::CommitmentHashType;
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq)]
pub struct Commitment {

View File

@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};
use crate::merkle_tree_public::TreeHashType;
use crate::TreeHashType;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PublicNativeTokenSend {

View File

@ -1,10 +1,10 @@
use merkle_tree_public::TreeHashType;
use rs_merkle::Hasher;
use serde::Deserialize;
use sha2::{digest::FixedOutput, Digest, Sha256};
pub mod block;
pub mod commitment;
pub mod execution_input;
pub mod merkle_tree_public;
pub mod nullifier;
pub mod rpc_primitives;
pub mod sequencer_client;
@ -16,6 +16,25 @@ pub mod test_utils;
use rpc_primitives::errors::RpcError;
pub type TreeHashType = [u8; 32];
pub type CommitmentHashType = Vec<u8>;
#[derive(Debug, Clone)]
///Our own hasher.
/// Currently it is SHA256 hasher wrapper. May change in a future.
pub struct OwnHasher {}
impl Hasher for OwnHasher {
type Hash = TreeHashType;
fn hash(data: &[u8]) -> TreeHashType {
let mut hasher = Sha256::new();
hasher.update(data);
<TreeHashType>::from(hasher.finalize_fixed())
}
}
///Account id on blockchain
pub type AccountId = TreeHashType;

View File

@ -1,20 +0,0 @@
use rs_merkle::Hasher;
use sha2::{digest::FixedOutput, Digest, Sha256};
use super::TreeHashType;
#[derive(Debug, Clone)]
///Our own hasher.
/// Currently it is SHA256 hasher wrapper. May change in a future.
pub struct OwnHasher {}
impl Hasher for OwnHasher {
type Hash = TreeHashType;
fn hash(data: &[u8]) -> TreeHashType {
let mut hasher = Sha256::new();
hasher.update(data);
<TreeHashType>::from(hasher.finalize_fixed())
}
}

View File

@ -1,312 +0,0 @@
use std::{collections::HashMap, fmt, marker::PhantomData};
use rs_merkle::{MerkleProof, MerkleTree};
use serde::{
de::{SeqAccess, Visitor},
ser::SerializeSeq,
Deserialize, Deserializer, Serialize,
};
use crate::{transaction::Transaction, utxo_commitment::UTXOCommitment};
use super::{hasher::OwnHasher, tree_leav_item::TreeLeavItem, TreeHashType};
#[derive(Clone)]
pub struct HashStorageMerkleTree<Leav: TreeLeavItem + Clone> {
leaves: HashMap<usize, Leav>,
hash_to_id_map: HashMap<TreeHashType, usize>,
tree: MerkleTree<OwnHasher>,
}
impl<Leav: TreeLeavItem + Clone + Serialize> Serialize for HashStorageMerkleTree<Leav> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut vector = self.leaves.iter().collect::<Vec<_>>();
vector.sort_by(|a, b| a.0.cmp(b.0));
let mut seq = serializer.serialize_seq(Some(self.leaves.len()))?;
for element in vector.iter() {
seq.serialize_element(element.1)?;
}
seq.end()
}
}
struct HashStorageMerkleTreeDeserializer<Leav: TreeLeavItem + Clone> {
marker: PhantomData<fn() -> HashStorageMerkleTree<Leav>>,
}
impl<Leaf: TreeLeavItem + Clone> HashStorageMerkleTreeDeserializer<Leaf> {
fn new() -> Self {
HashStorageMerkleTreeDeserializer {
marker: PhantomData,
}
}
}
impl<'de, Leav: TreeLeavItem + Clone + Deserialize<'de>> Visitor<'de>
for HashStorageMerkleTreeDeserializer<Leav>
{
type Value = HashStorageMerkleTree<Leav>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("HashStorageMerkleTree key value sequence.")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let mut vector = vec![];
loop {
let opt_key = seq.next_element::<Leav>()?;
if let Some(value) = opt_key {
vector.push(value);
} else {
break;
}
}
Ok(HashStorageMerkleTree::new(vector))
}
}
impl<'de, Leav: TreeLeavItem + Clone + Deserialize<'de>> serde::Deserialize<'de>
for HashStorageMerkleTree<Leav>
{
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_seq(HashStorageMerkleTreeDeserializer::new())
}
}
pub type PublicTransactionMerkleTree = HashStorageMerkleTree<Transaction>;
pub type UTXOCommitmentsMerkleTree = HashStorageMerkleTree<UTXOCommitment>;
impl<Leav: TreeLeavItem + Clone> HashStorageMerkleTree<Leav> {
pub fn new(leaves_vec: Vec<Leav>) -> Self {
let mut leaves_map = HashMap::new();
let mut hash_to_id_map = HashMap::new();
let leaves_hashed: Vec<TreeHashType> = leaves_vec
.iter()
.enumerate()
.map(|(id, tx)| {
leaves_map.insert(id, tx.clone());
hash_to_id_map.insert(tx.hash(), id);
tx.hash()
})
.collect();
Self {
leaves: leaves_map,
hash_to_id_map,
tree: MerkleTree::from_leaves(&leaves_hashed),
}
}
pub fn get_tx(&self, hash: TreeHashType) -> Option<&Leav> {
self.hash_to_id_map
.get(&hash)
.and_then(|id| self.leaves.get(id))
}
pub fn get_root(&self) -> Option<TreeHashType> {
self.tree.root()
}
pub fn get_proof(&self, hash: TreeHashType) -> Option<MerkleProof<OwnHasher>> {
self.hash_to_id_map
.get(&hash)
.map(|id| self.tree.proof(&[*id]))
}
pub fn get_proof_multiple(&self, hashes: &[TreeHashType]) -> Option<MerkleProof<OwnHasher>> {
let ids_opt: Vec<Option<&usize>> = hashes
.iter()
.map(|hash| self.hash_to_id_map.get(hash))
.collect();
let is_valid = ids_opt.iter().all(|el| el.is_some());
if is_valid {
let ids: Vec<usize> = ids_opt.into_iter().map(|el| *el.unwrap()).collect();
Some(self.tree.proof(&ids))
} else {
None
}
}
pub fn add_tx(&mut self, tx: &Leav) {
let last = self.leaves.len();
self.leaves.insert(last, tx.clone());
self.hash_to_id_map.insert(tx.hash(), last);
self.tree.insert(tx.hash());
self.tree.commit();
}
pub fn add_tx_multiple(&mut self, txs: Vec<Leav>) {
for tx in txs.iter() {
let last = self.leaves.len();
self.leaves.insert(last, tx.clone());
self.hash_to_id_map.insert(tx.hash(), last);
}
self.tree
.append(&mut txs.iter().map(|tx| tx.hash()).collect());
self.tree.commit();
}
}
#[cfg(test)]
mod tests {
use super::*;
// Mock implementation of TreeLeavItem trait for testing
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
struct MockTransaction {
pub hash: TreeHashType,
}
impl TreeLeavItem for MockTransaction {
fn hash(&self) -> TreeHashType {
self.hash
}
}
fn get_first_32_bytes(s: &str) -> [u8; 32] {
let mut buffer = [0u8; 32];
let bytes = s.as_bytes();
let len = std::cmp::min(32, bytes.len());
buffer[..len].copy_from_slice(&bytes[..len]);
buffer
}
#[test]
fn test_new_merkle_tree() {
let tx1 = MockTransaction {
hash: get_first_32_bytes("tx1"),
};
let tx2 = MockTransaction {
hash: get_first_32_bytes("tx2"),
};
let tree = HashStorageMerkleTree::new(vec![tx1.clone(), tx2.clone()]);
assert_eq!(tree.leaves.len(), 2);
assert!(tree.get_root().is_some());
}
#[test]
fn test_new_merkle_tree_serialize() {
let tx1 = MockTransaction {
hash: get_first_32_bytes("tx1"),
};
let tx2 = MockTransaction {
hash: get_first_32_bytes("tx2"),
};
let tree = HashStorageMerkleTree::new(vec![tx1.clone(), tx2.clone()]);
let binding = serde_json::to_vec(&tree).unwrap();
let obj: HashStorageMerkleTree<MockTransaction> = serde_json::from_slice(&binding).unwrap();
assert_eq!(tree.leaves, obj.leaves);
assert_eq!(tree.hash_to_id_map, obj.hash_to_id_map);
assert_eq!(tree.tree.root(), obj.tree.root());
}
#[test]
fn test_get_tx() {
let tx1 = MockTransaction {
hash: get_first_32_bytes("tx1"),
};
let tx2 = MockTransaction {
hash: get_first_32_bytes("tx2"),
};
let tree = HashStorageMerkleTree::new(vec![tx1.clone(), tx2.clone()]);
assert_eq!(tree.get_tx(tx1.hash()), Some(&tx1));
assert_eq!(tree.get_tx(tx2.hash()), Some(&tx2));
}
#[test]
fn test_get_proof() {
let tx1 = MockTransaction {
hash: get_first_32_bytes("tx1"),
};
let tx2 = MockTransaction {
hash: get_first_32_bytes("tx2"),
};
let tree = HashStorageMerkleTree::new(vec![tx1.clone(), tx2.clone()]);
let proof = tree.get_proof(tx1.hash());
assert!(proof.is_some());
}
#[test]
fn test_add_tx() {
let tx1 = MockTransaction {
hash: get_first_32_bytes("tx1"),
};
let tx2 = MockTransaction {
hash: get_first_32_bytes("tx2"),
};
let mut tree = HashStorageMerkleTree::new(vec![tx1.clone()]);
tree.add_tx(&tx2);
assert_eq!(tree.leaves.len(), 2);
assert_eq!(tree.get_tx(tx2.hash()), Some(&tx2));
}
#[test]
fn test_add_tx_multiple() {
let tx1 = MockTransaction {
hash: get_first_32_bytes("tx1"),
};
let tx2 = MockTransaction {
hash: get_first_32_bytes("tx2"),
};
let tx3 = MockTransaction {
hash: get_first_32_bytes("tx3"),
};
let mut tree = HashStorageMerkleTree::new(vec![tx1.clone()]);
tree.add_tx_multiple(vec![tx2.clone(), tx3.clone()]);
assert_eq!(tree.leaves.len(), 3);
assert_eq!(tree.get_tx(tx2.hash()), Some(&tx2));
assert_eq!(tree.get_tx(tx3.hash()), Some(&tx3));
}
#[test]
fn test_get_proof_multiple() {
let tx1 = MockTransaction {
hash: get_first_32_bytes("tx1"),
};
let tx2 = MockTransaction {
hash: get_first_32_bytes("tx2"),
};
let tx3 = MockTransaction {
hash: get_first_32_bytes("tx3"),
};
let tree = HashStorageMerkleTree::new(vec![tx1.clone(), tx2.clone(), tx3.clone()]);
let proof = tree.get_proof_multiple(&[tx1.hash(), tx2.hash()]);
assert!(proof.is_some());
}
}

View File

@ -1,6 +0,0 @@
pub mod hasher;
pub mod merkle_tree;
pub mod tree_leav_item;
pub type TreeHashType = [u8; 32];
pub type CommitmentHashType = Vec<u8>;

View File

@ -1,19 +0,0 @@
use crate::{transaction::Transaction, utxo_commitment::UTXOCommitment};
use super::TreeHashType;
pub trait TreeLeavItem {
fn hash(&self) -> TreeHashType;
}
impl TreeLeavItem for Transaction {
fn hash(&self) -> TreeHashType {
self.body().hash()
}
}
impl TreeLeavItem for UTXOCommitment {
fn hash(&self) -> TreeHashType {
self.hash
}
}

View File

@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};
use crate::merkle_tree_public::TreeHashType;
use crate::TreeHashType;
//ToDo: Update Nullifier model, when it is clear
#[derive(Debug, Serialize, Deserialize, Clone, Default, PartialEq, Eq, Hash)]

View File

@ -12,6 +12,7 @@ use crate::rpc_primitives::requests::{
GetTransactionByHashResponse,
};
use crate::sequencer_client::json::AccountInitialData;
use crate::transaction::TransactionBody;
use crate::{SequencerClientError, SequencerRpcError};
pub mod json;
@ -127,10 +128,12 @@ impl SequencerClient {
}
///Send transaction to sequencer
pub async fn send_tx(
pub async fn send_tx_public(
&self,
transaction: nssa::PublicTransaction,
) -> Result<SendTxResponse, SequencerClientError> {
let transaction = TransactionBody::from(nssa::NSSATransaction::Public(transaction));
let tx_req = SendTxRequest {
transaction: transaction.to_bytes(),
};

View File

@ -1,8 +1,15 @@
use k256::{ecdsa::{signature::SignerMut, SigningKey}, FieldBytes};
use nssa::{self, NSSATransaction};
use rand::rngs::OsRng;
use nssa::NSSATransaction;
use crate::{block::{Block, HashableBlockData}, transaction::{Transaction, TransactionBody}};
use crate::{
block::{Block, HashableBlockData},
transaction::TransactionBody,
};
//Helpers
pub fn sequencer_sign_key_for_testing() -> nssa::PrivateKey {
nssa::PrivateKey::try_new([37; 32]).unwrap()
}
//Dummy producers
@ -12,38 +19,24 @@ use crate::{block::{Block, HashableBlockData}, transaction::{Transaction, Transa
///
/// `prev_hash` - hash of previous block, provide None for genesis
///
/// `transactions` - vector of `Transaction` objects
/// `transactions` - vector of `AuthenticatedTransaction` objects
pub fn produce_dummy_block(
id: u64,
prev_hash: Option<[u8; 32]>,
transactions: Vec<nssa::PublicTransaction>,
transactions: Vec<TransactionBody>,
) -> Block {
let transactions = transactions.into_iter().map(
|tx| {
let tx_body = TransactionBody::from(NSSATransaction::Public(tx));
//ToDo: Fix signing key
let transaction = Transaction::new(tx_body, SigningKey::random(&mut OsRng));
transaction.into_authenticated().unwrap()
}).collect();
//ToDo: Fix signature
let key_bytes = FieldBytes::from_slice(&[37; 32]);
let mut private_key: SigningKey = SigningKey::from_bytes(key_bytes).unwrap();
let signature = private_key.sign(&[1; 32]);
let block_data = HashableBlockData {
block_id: id,
prev_block_id: id.saturating_sub(1),
prev_block_hash: prev_hash.unwrap_or_default(),
timestamp: 0,
signature,
timestamp: id * 100,
transactions,
};
block_data.into()
block_data.into_block(&sequencer_sign_key_for_testing())
}
pub fn produce_dummy_empty_transaction() -> nssa::PublicTransaction {
pub fn produce_dummy_empty_transaction() -> TransactionBody {
let program_id = nssa::program::Program::authenticated_transfer_program().id();
let addresses = vec![];
let nonces = vec![];
@ -53,7 +46,10 @@ pub fn produce_dummy_empty_transaction() -> nssa::PublicTransaction {
.unwrap();
let private_key = nssa::PrivateKey::try_new([1; 32]).unwrap();
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[&private_key]);
nssa::PublicTransaction::new(message, witness_set)
let nssa_tx = nssa::PublicTransaction::new(message, witness_set);
TransactionBody::from(NSSATransaction::Public(nssa_tx))
}
pub fn create_transaction_native_token_transfer(
@ -62,7 +58,7 @@ pub fn create_transaction_native_token_transfer(
to: [u8; 32],
balance_to_move: u128,
signing_key: nssa::PrivateKey,
) -> nssa::PublicTransaction {
) -> TransactionBody {
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();
@ -70,5 +66,8 @@ pub fn create_transaction_native_token_transfer(
nssa::public_transaction::Message::try_new(program_id, addresses, nonces, balance_to_move)
.unwrap();
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[&signing_key]);
nssa::PublicTransaction::new(message, witness_set)
let nssa_tx = nssa::PublicTransaction::new(message, witness_set);
TransactionBody::from(NSSATransaction::Public(nssa_tx))
}

View File

@ -1,23 +1,16 @@
use std::io::{Cursor, Read};
use k256::ecdsa::{
signature::{Signer, Verifier},
Signature, SigningKey, VerifyingKey,
};
use k256::ecdsa::{Signature, SigningKey, VerifyingKey};
use log::info;
use serde::{Deserialize, Serialize};
use sha2::{digest::FixedOutput, Digest};
use crate::{block::u32_from_cursor, merkle_tree_public::TreeHashType};
use elliptic_curve::{
consts::{B0, B1},
generic_array::GenericArray,
};
use sha2::digest::typenum::{UInt, UTerm};
use crate::TransactionSignatureError;
use crate::TreeHashType;
pub type CipherText = Vec<u8>;
pub type Nonce = GenericArray<u8, UInt<UInt<UInt<UInt<UTerm, B1>, B1>, B0>, B0>>;
@ -40,33 +33,29 @@ pub struct TransactionBody {
impl From<nssa::NSSATransaction> for TransactionBody {
fn from(value: nssa::NSSATransaction) -> Self {
match value {
nssa::NSSATransaction::Public(tx) => {
Self {
tx_kind: TxKind::Public,
encoded_transaction_data: tx.to_bytes(),
}
nssa::NSSATransaction::Public(tx) => Self {
tx_kind: TxKind::Public,
encoded_transaction_data: tx.to_bytes(),
},
nssa::NSSATransaction::PrivacyPreserving(tx) => Self {
tx_kind: TxKind::PrivacyPreserving,
encoded_transaction_data: tx.to_bytes(),
},
nssa::NSSATransaction::PrivacyPreserving(tx) => {
Self {
tx_kind: TxKind::PrivacyPreserving,
encoded_transaction_data: tx.to_bytes(),
}
}
}
}
}
impl TryFrom<TransactionBody> for nssa::NSSATransaction {
impl TryFrom<&TransactionBody> for nssa::NSSATransaction {
type Error = nssa::error::NssaError;
fn try_from(value: TransactionBody) -> Result<Self, Self::Error> {
fn try_from(value: &TransactionBody) -> Result<Self, Self::Error> {
match value.tx_kind {
TxKind::Public => {
nssa::PublicTransaction::from_bytes(&value.encoded_transaction_data).map(|tx| tx.into())
},
TxKind::Public => nssa::PublicTransaction::from_bytes(&value.encoded_transaction_data)
.map(|tx| tx.into()),
TxKind::PrivacyPreserving => {
nssa::PrivacyPreservingTransaction::from_bytes(&value.encoded_transaction_data).map(|tx| tx.into())
},
nssa::PrivacyPreservingTransaction::from_bytes(&value.encoded_transaction_data)
.map(|tx| tx.into())
}
}
}
}
@ -173,14 +162,14 @@ impl TransactionBody {
TreeHashType::from(hasher.finalize_fixed())
}
fn to_bytes(&self) -> Vec<u8> {
pub fn to_bytes(&self) -> Vec<u8> {
// TODO: Remove `unwrap` by implementing a `to_bytes` method
// that deterministically encodes all transaction fields to bytes
// and guarantees serialization will succeed.
serde_json::to_vec(&self).unwrap()
}
fn from_bytes(bytes: Vec<u8>) -> Self {
pub fn from_bytes(bytes: Vec<u8>) -> Self {
serde_json::from_slice(&bytes).unwrap()
}
@ -190,171 +179,31 @@ impl TransactionBody {
}
}
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,
pub signature: TransactionSignature,
pub 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<AuthenticatedTransaction, TransactionSignatureError> {
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
}
}
impl Transaction {
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::new();
let body_bytes = self.body.to_bytes();
let signature_bytes = self.signature.to_bytes();
let public_key_bytes = self.public_key.to_sec1_bytes();
let body_bytes_len = body_bytes.len() as u32;
let signature_bytes_len = signature_bytes.len() as u32;
let public_key_bytes_len = public_key_bytes.len() as u32;
bytes.extend_from_slice(&body_bytes_len.to_le_bytes());
bytes.extend_from_slice(&signature_bytes_len.to_le_bytes());
bytes.extend_from_slice(&public_key_bytes_len.to_le_bytes());
bytes.extend_from_slice(&body_bytes);
bytes.extend_from_slice(&signature_bytes);
bytes.extend_from_slice(&public_key_bytes);
bytes
}
// TODO: Improve error handling. Remove unwraps.
pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Self {
let body_bytes_len = u32_from_cursor(cursor) as usize;
let signature_bytes_len = u32_from_cursor(cursor) as usize;
let public_key_bytes_len = u32_from_cursor(cursor) as usize;
let mut body_bytes = Vec::with_capacity(body_bytes_len);
let mut signature_bytes = Vec::with_capacity(signature_bytes_len);
let mut public_key_bytes = Vec::with_capacity(public_key_bytes_len);
cursor.read_exact(&mut body_bytes).unwrap();
let body = TransactionBody::from_bytes(body_bytes);
cursor.read_exact(&mut signature_bytes).unwrap();
let signature = Signature::from_bytes(signature_bytes.as_slice().try_into().unwrap()).unwrap();
cursor.read_exact(&mut public_key_bytes).unwrap();
let public_key = VerifyingKey::from_sec1_bytes(&public_key_bytes).unwrap();
Self { body, signature, public_key }
}
}
/// 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, PartialEq, Eq)]
pub struct AuthenticatedTransaction {
hash: TransactionHash,
transaction: Transaction,
}
impl AuthenticatedTransaction {
/// Returns the underlying transaction
pub fn transaction(&self) -> &Transaction {
&self.transaction
}
pub fn into_transaction(self) -> Transaction {
self.transaction
}
/// Returns the precomputed hash over the body of the transaction
pub fn hash(&self) -> &TransactionHash {
&self.hash
}
}
impl AuthenticatedTransaction {
pub fn to_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.extend_from_slice(&self.hash);
bytes.extend_from_slice(&self.transaction.to_bytes());
bytes
}
// TODO: Improve error handling. Remove unwraps.
pub fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Self {
let mut hash: [u8; 32] = [0; 32];
cursor.read_exact(&mut hash).unwrap();
let transaction = Transaction::from_cursor(cursor);
Self { hash, transaction }
}
}
#[cfg(test)]
mod tests {
use super::*;
use k256::{ecdsa::signature::Signer, FieldBytes};
use sha2::{digest::FixedOutput, Digest};
use crate::{
merkle_tree_public::TreeHashType,
transaction::{Transaction, TransactionBody, TxKind},
transaction::{TransactionBody, TxKind},
TreeHashType,
};
fn test_transaction_body() -> TransactionBody {
TransactionBody {
tx_kind: TxKind::Public,
encoded_transaction_data: vec![1,2,3,4],
encoded_transaction_data: vec![1, 2, 3, 4],
}
}
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(&body).unwrap();
let data = body.to_bytes();
let mut hasher = sha2::Sha256::new();
hasher.update(&data);
TreeHashType::from(hasher.finalize_fixed())
@ -366,81 +215,12 @@ mod tests {
}
#[test]
fn test_transaction_constructor() {
fn test_to_bytes_from_bytes() {
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);
}
let body_bytes = body.to_bytes();
let body_new = TransactionBody::from_bytes(body_bytes);
#[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());
}
#[test]
fn test_authenticated_transaction_into_transaction() {
let transaction = test_transaction();
let authenticated_tx = transaction.clone().into_authenticated().unwrap();
assert_eq!(authenticated_tx.into_transaction(), transaction);
assert_eq!(body, body_new);
}
}

View File

@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize};
use crate::merkle_tree_public::TreeHashType;
use crate::TreeHashType;
//ToDo: Update UTXO Commitment model, when it is clear
#[derive(Debug, Serialize, Deserialize, Clone)]

View File

@ -15,5 +15,7 @@
"addr": "4d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d0766",
"balance": 20000
}
]
],
"signing_key": [37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
37, 37, 37, 37, 37, 37]
}

View File

@ -1,4 +1,4 @@
use common::merkle_tree_public::TreeHashType;
use common::TreeHashType;
use elliptic_curve::PrimeField;
use k256::{AffinePoint, FieldBytes, Scalar};
use rand::{rngs::OsRng, RngCore};

View File

@ -7,7 +7,11 @@ use nssa_core::{
};
use crate::{
error::NssaError, privacy_preserving_transaction::{circuit::Proof, message::EncryptedAccountData, witness_set::WitnessSet}, Address, PrivacyPreservingTransaction, PublicKey, Signature
Address, PrivacyPreservingTransaction, PublicKey, Signature,
error::NssaError,
privacy_preserving_transaction::{
circuit::Proof, message::EncryptedAccountData, witness_set::WitnessSet,
},
};
use super::message::Message;

View File

@ -15,6 +15,7 @@ elliptic-curve.workspace = true
k256.workspace = true
tiny-keccak.workspace = true
tempfile.workspace = true
chrono.workspace = true
[dependencies.storage]
path = "../storage"

View File

@ -27,4 +27,6 @@ pub struct SequencerConfig {
pub port: u16,
///List of initial accounts data
pub initial_accounts: Vec<AccountInitialData>,
///Sequencer own signing key
pub signing_key: [u8; 32],
}

View File

@ -1,10 +1,11 @@
use std::fmt::Display;
use anyhow::Result;
use common::{block::HashableBlockData, merkle_tree_public::TreeHashType};
use common::{block::HashableBlockData, transaction::TransactionBody, TreeHashType};
use config::SequencerConfig;
use log::warn;
use log::{info, warn};
use mempool::MemPool;
use nssa::NSSATransaction;
use sequencer_store::SequecerChainStore;
use serde::{Deserialize, Serialize};
@ -13,7 +14,7 @@ pub mod sequencer_store;
pub struct SequencerCore {
pub store: SequecerChainStore,
pub mempool: MemPool<nssa::PublicTransaction>,
pub mempool: MemPool<TransactionBody>,
pub sequencer_config: SequencerConfig,
pub chain_height: u64,
}
@ -51,6 +52,7 @@ impl SequencerCore {
config.genesis_id,
config.is_genesis_random,
&config.initial_accounts,
nssa::PrivateKey::try_new(config.signing_key).unwrap(),
),
mempool: MemPool::default(),
chain_height: config.genesis_id,
@ -60,20 +62,39 @@ impl SequencerCore {
pub fn transaction_pre_check(
&mut self,
tx: nssa::PublicTransaction,
) -> Result<nssa::PublicTransaction, TransactionMalformationErrorKind> {
tx: NSSATransaction,
) -> Result<NSSATransaction, TransactionMalformationErrorKind> {
// Stateless checks here
if tx.witness_set().is_valid_for(tx.message()) {
Ok(tx)
} else {
Err(TransactionMalformationErrorKind::InvalidSignature)
match tx {
NSSATransaction::Public(tx) => {
if tx.witness_set().is_valid_for(tx.message()) {
Ok(NSSATransaction::Public(tx))
} else {
Err(TransactionMalformationErrorKind::InvalidSignature)
}
}
NSSATransaction::PrivacyPreserving(tx) => {
if tx.witness_set().signatures_are_valid_for(tx.message()) {
Ok(NSSATransaction::PrivacyPreserving(tx))
} else {
Err(TransactionMalformationErrorKind::InvalidSignature)
}
}
}
}
pub fn push_tx_into_mempool_pre_check(
&mut self,
transaction: nssa::PublicTransaction,
transaction: TransactionBody,
) -> Result<(), TransactionMalformationErrorKind> {
let transaction = NSSATransaction::try_from(&transaction).map_err(|_| {
TransactionMalformationErrorKind::FailedToDecode {
tx: transaction.hash(),
}
})?;
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);
@ -83,19 +104,29 @@ impl SequencerCore {
.transaction_pre_check(transaction)
.inspect_err(|err| warn!("Error at pre_check {err:#?}"))?;
self.mempool.push_item(authenticated_tx);
self.mempool.push_item(authenticated_tx.into());
Ok(())
}
fn execute_check_transaction_on_state(
&mut self,
tx: nssa::PublicTransaction,
) -> Result<nssa::PublicTransaction, nssa::error::NssaError> {
self.store
.state
.transition_from_public_transaction(&tx)
.inspect_err(|err| warn!("Error at transition {err:#?}"))?;
tx: NSSATransaction,
) -> Result<NSSATransaction, nssa::error::NssaError> {
match &tx {
NSSATransaction::Public(tx) => {
self.store
.state
.transition_from_public_transaction(tx)
.inspect_err(|err| warn!("Error at transition {err:#?}"))?;
}
NSSATransaction::PrivacyPreserving(tx) => {
self.store
.state
.transition_from_privacy_preserving_transaction(tx)
.inspect_err(|err| warn!("Error at transition {err:#?}"))?;
}
}
Ok(tx)
}
@ -108,25 +139,39 @@ impl SequencerCore {
.mempool
.pop_size(self.sequencer_config.max_num_tx_in_block);
let valid_transactions: Vec<_> = transactions
let mut nssa_transactions = vec![];
for tx in transactions {
let nssa_transaction = NSSATransaction::try_from(&tx)
.map_err(|_| TransactionMalformationErrorKind::FailedToDecode { tx: tx.hash() })?;
nssa_transactions.push(nssa_transaction);
}
let valid_transactions: Vec<_> = nssa_transactions
.into_iter()
.filter_map(|tx| self.execute_check_transaction_on_state(tx).ok())
.map(Into::into)
.collect();
let prev_block_hash = self
.store
.block_store
.get_block_at_id(self.chain_height)?
.header
.hash;
let curr_time = chrono::Utc::now().timestamp_millis() as u64;
let hashable_data = HashableBlockData {
block_id: new_block_height,
prev_block_id: self.chain_height,
transactions: valid_transactions,
prev_block_hash,
timestamp: curr_time,
};
let block = hashable_data.into();
let block = hashable_data.into_block(&self.store.block_store.signing_key);
self.store.block_store.put_block_at_id(block)?;
@ -138,10 +183,18 @@ impl SequencerCore {
#[cfg(test)]
mod tests {
use common::test_utils::sequencer_sign_key_for_testing;
use crate::config::AccountInitialData;
use super::*;
fn parse_unwrap_tx_body_into_nssa_tx(tx_body: TransactionBody) -> NSSATransaction {
NSSATransaction::try_from(&tx_body)
.map_err(|_| TransactionMalformationErrorKind::FailedToDecode { tx: tx_body.hash() })
.unwrap()
}
fn setup_sequencer_config_variable_initial_accounts(
initial_accounts: Vec<AccountInitialData>,
) -> SequencerConfig {
@ -157,6 +210,7 @@ mod tests {
block_create_timeout_millis: 1000,
port: 8080,
initial_accounts,
signing_key: *sequencer_sign_key_for_testing().value(),
}
}
@ -298,7 +352,7 @@ mod tests {
common_setup(&mut sequencer);
let tx = common::test_utils::produce_dummy_empty_transaction();
let result = sequencer.transaction_pre_check(tx);
let result = sequencer.transaction_pre_check(parse_unwrap_tx_body_into_nssa_tx(tx));
assert!(result.is_ok());
}
@ -324,7 +378,7 @@ mod tests {
let tx = common::test_utils::create_transaction_native_token_transfer(
acc1, 0, acc2, 10, sign_key1,
);
let result = sequencer.transaction_pre_check(tx);
let result = sequencer.transaction_pre_check(parse_unwrap_tx_body_into_nssa_tx(tx));
assert!(result.is_ok());
}
@ -352,7 +406,9 @@ mod tests {
);
// Signature is valid, stateless check pass
let tx = sequencer.transaction_pre_check(tx).unwrap();
let tx = sequencer
.transaction_pre_check(parse_unwrap_tx_body_into_nssa_tx(tx))
.unwrap();
// Signature is not from sender. Execution fails
let result = sequencer.execute_check_transaction_on_state(tx);
@ -385,7 +441,7 @@ mod tests {
acc1, 0, acc2, 10000000, sign_key1,
);
let result = sequencer.transaction_pre_check(tx);
let result = sequencer.transaction_pre_check(parse_unwrap_tx_body_into_nssa_tx(tx));
//Passed pre-check
assert!(result.is_ok());
@ -421,7 +477,9 @@ mod tests {
acc1, 0, acc2, 100, sign_key1,
);
sequencer.execute_check_transaction_on_state(tx).unwrap();
sequencer
.execute_check_transaction_on_state(parse_unwrap_tx_body_into_nssa_tx(tx))
.unwrap();
let bal_from = sequencer
.store
@ -528,7 +586,7 @@ mod tests {
.unwrap();
// Only one should be included in the block
assert_eq!(block.transactions, vec![tx.clone()]);
assert_eq!(block.body.transactions, vec![tx.clone()]);
}
#[test]
@ -563,7 +621,7 @@ mod tests {
.block_store
.get_block_at_id(current_height)
.unwrap();
assert_eq!(block.transactions, vec![tx.clone()]);
assert_eq!(block.body.transactions, vec![tx.clone()]);
// Add same transaction should fail
sequencer.mempool.push_item(tx);
@ -575,6 +633,6 @@ mod tests {
.block_store
.get_block_at_id(current_height)
.unwrap();
assert!(block.transactions.is_empty());
assert!(block.body.transactions.is_empty());
}
}

View File

@ -1,7 +1,7 @@
use std::{collections::HashMap, path::Path};
use anyhow::Result;
use common::{block::Block, merkle_tree_public::TreeHashType};
use common::{block::Block, transaction::TransactionBody, TreeHashType};
use storage::RocksDBIO;
pub struct SequecerBlockStore {
@ -9,6 +9,7 @@ pub struct SequecerBlockStore {
// TODO: Consider adding the hashmap to the database for faster recovery.
tx_hash_to_block_map: HashMap<TreeHashType, u64>,
pub genesis_id: u64,
pub signing_key: nssa::PrivateKey,
}
impl SequecerBlockStore {
@ -16,7 +17,11 @@ impl SequecerBlockStore {
/// Creates files if necessary.
///
/// ATTENTION: Will overwrite genesis block.
pub fn open_db_with_genesis(location: &Path, genesis_block: Option<Block>) -> Result<Self> {
pub fn open_db_with_genesis(
location: &Path,
genesis_block: Option<Block>,
signing_key: nssa::PrivateKey,
) -> Result<Self> {
let tx_hash_to_block_map = if let Some(block) = &genesis_block {
block_to_transactions_map(block)
} else {
@ -31,16 +36,17 @@ impl SequecerBlockStore {
dbio,
genesis_id,
tx_hash_to_block_map,
signing_key,
})
}
///Reopening existing database
pub fn open_db_restart(location: &Path) -> Result<Self> {
SequecerBlockStore::open_db_with_genesis(location, None)
pub fn open_db_restart(location: &Path, signing_key: nssa::PrivateKey) -> Result<Self> {
SequecerBlockStore::open_db_with_genesis(location, None, signing_key)
}
pub fn get_block_at_id(&self, id: u64) -> Result<Block> {
Ok(self.dbio.get_block(id)?)
Ok(self.dbio.get_block(id)?.into_block(&self.signing_key))
}
pub fn put_block_at_id(&mut self, block: Block) -> Result<()> {
@ -51,11 +57,11 @@ 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<nssa::PublicTransaction> {
pub fn get_transaction_by_hash(&self, hash: TreeHashType) -> Option<TransactionBody> {
let block_id = self.tx_hash_to_block_map.get(&hash);
let block = block_id.map(|&id| self.get_block_at_id(id));
if let Some(Ok(block)) = block {
for transaction in block.transactions.into_iter() {
for transaction in block.body.transactions.into_iter() {
if transaction.hash() == hash {
return Some(transaction);
}
@ -67,9 +73,10 @@ impl SequecerBlockStore {
fn block_to_transactions_map(block: &Block) -> HashMap<TreeHashType, u64> {
block
.body
.transactions
.iter()
.map(|transaction| (transaction.hash(), block.block_id))
.map(|transaction| (transaction.hash(), block.header.block_id))
.collect()
}
@ -77,11 +84,7 @@ fn block_to_transactions_map(block: &Block) -> HashMap<TreeHashType, u64> {
mod tests {
use super::*;
use common::block::{BlockBody, BlockHeader};
use k256::{
ecdsa::{signature::SignerMut, Signature, SigningKey},
FieldBytes,
};
use common::{block::HashableBlockData, test_utils::sequencer_sign_key_for_testing};
use tempfile::tempdir;
#[test]
@ -89,25 +92,21 @@ mod tests {
let temp_dir = tempdir().unwrap();
let path = temp_dir.path();
let key_bytes = FieldBytes::from_slice(&[37; 32]);
let mut private_key: SigningKey = SigningKey::from_bytes(key_bytes).unwrap();
let signing_key = sequencer_sign_key_for_testing();
let genesis_block = Block {
header: BlockHeader {
block_id: 0,
prev_block_id: 0,
prev_block_hash: [0; 32],
hash: [1; 32],
timestamp: 0,
signature: private_key.sign(&[42; 32]),
},
body: BlockBody {
transactions: vec![],
},
let genesis_block_hashable_data = HashableBlockData {
block_id: 0,
prev_block_id: 0,
prev_block_hash: [0; 32],
timestamp: 0,
transactions: vec![],
};
let genesis_block = genesis_block_hashable_data.into_block(&signing_key);
// Start an empty 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), signing_key)
.unwrap();
let tx = common::test_utils::produce_dummy_empty_transaction();
let block = common::test_utils::produce_dummy_block(1, None, vec![tx.clone()]);

View File

@ -20,6 +20,7 @@ impl SequecerChainStore {
genesis_id: u64,
is_genesis_random: bool,
initial_accounts: &[AccountInitialData],
signing_key: nssa::PrivateKey,
) -> Self {
let init_accs: Vec<(Address, u128)> = initial_accounts
.iter()
@ -36,20 +37,24 @@ impl SequecerChainStore {
OsRng.fill_bytes(&mut prev_block_hash);
}
let curr_time = chrono::Utc::now().timestamp_millis() as u64;
let hashable_data = HashableBlockData {
block_id: genesis_id,
prev_block_id: genesis_id.saturating_sub(1),
transactions: vec![],
prev_block_hash,
timestamp: curr_time,
};
let genesis_block = hashable_data.into();
let genesis_block = hashable_data.into_block(&signing_key);
//Sequencer should panic if unable to open db,
//as fixing this issue may require actions non-native to program scope
let block_store = SequecerBlockStore::open_db_with_genesis(
&home_dir.join("rocksdb"),
Some(genesis_block),
signing_key,
)
.unwrap();

View File

@ -6,7 +6,6 @@ use serde_json::Value;
use common::{
block::HashableBlockData,
merkle_tree_public::TreeHashType,
rpc_primitives::{
errors::RpcError,
message::{Message, Request},
@ -17,6 +16,8 @@ use common::{
GetTransactionByHashRequest, GetTransactionByHashResponse,
},
},
transaction::TransactionBody,
TreeHashType,
};
use common::rpc_primitives::requests::{
@ -72,8 +73,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 = nssa::PublicTransaction::from_bytes(&send_tx_req.transaction)
.map_err(|e| RpcError::serialization_error(&e.to_string()))?;
let tx = TransactionBody::from_bytes(send_tx_req.transaction);
let tx_hash = hex::encode(tx.hash());
{
@ -254,7 +254,10 @@ mod tests {
use crate::{rpc_handler, JsonHandler};
use base64::{engine::general_purpose, Engine};
use common::rpc_primitives::RpcPollingConfig;
use common::{
rpc_primitives::RpcPollingConfig, test_utils::sequencer_sign_key_for_testing,
transaction::TransactionBody,
};
use sequencer_core::{
config::{AccountInitialData, SequencerConfig},
@ -298,14 +301,11 @@ mod tests {
block_create_timeout_millis: 1000,
port: 8080,
initial_accounts,
signing_key: *sequencer_sign_key_for_testing().value(),
}
}
fn components_for_tests() -> (
JsonHandler,
Vec<AccountInitialData>,
nssa::PublicTransaction,
) {
fn components_for_tests() -> (JsonHandler, Vec<AccountInitialData>, TransactionBody) {
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

@ -248,7 +248,7 @@ impl RocksDBIO {
Ok(())
}
pub fn get_block(&self, block_id: u64) -> DbResult<Block> {
pub fn get_block(&self, block_id: u64) -> DbResult<HashableBlockData> {
let cf_block = self.block_column();
let res = self
.db
@ -256,7 +256,7 @@ impl RocksDBIO {
.map_err(|rerr| DbError::rocksdb_cast_message(rerr, None))?;
if let Some(data) = res {
Ok(HashableBlockData::from_bytes(&data).into())
Ok(HashableBlockData::from_bytes(&data))
} else {
Err(DbError::db_interaction_error(
"Block on this id not found".to_string(),

View File

@ -1,14 +1,12 @@
use std::collections::HashMap;
use anyhow::Result;
use common::merkle_tree_public::merkle_tree::UTXOCommitmentsMerkleTree;
use key_protocol::key_protocol_core::NSSAUserData;
use crate::config::{PersistentAccountData, WalletConfig};
pub struct WalletChainStore {
pub user_data: NSSAUserData,
pub utxo_commitments_store: UTXOCommitmentsMerkleTree,
pub wallet_config: WalletConfig,
}
@ -21,11 +19,8 @@ impl WalletChainStore {
.map(|init_acc_data| (init_acc_data.address, init_acc_data.pub_sign_key))
.collect();
let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]);
Ok(Self {
user_data: NSSAUserData::new_with_accounts(accounts_keys)?,
utxo_commitments_store,
wallet_config: config,
})
}
@ -94,11 +89,6 @@ mod tests {
let config = create_sample_wallet_config(path.to_path_buf());
let store = WalletChainStore::new(config.clone()).unwrap();
assert_eq!(
store.utxo_commitments_store.get_root().unwrap_or([0; 32]),
[0; 32]
);
let _ = WalletChainStore::new(config.clone()).unwrap();
}
}

View File

@ -3,6 +3,7 @@ use std::{fs::File, io::Write, path::PathBuf, str::FromStr, sync::Arc};
use base64::Engine;
use common::{
sequencer_client::{json::SendTxResponse, SequencerClient},
transaction::TransactionBody,
ExecutionFailureKind,
};
@ -108,7 +109,6 @@ impl WalletCore {
balance_to_move,
)
.unwrap();
let signing_key = self.storage.user_data.get_account_signing_key(&from);
if let Some(signing_key) = signing_key {
@ -119,7 +119,7 @@ impl WalletCore {
let tx = nssa::PublicTransaction::new(message, witness_set);
Ok(self.sequencer_client.send_tx(tx).await?)
Ok(self.sequencer_client.send_tx_public(tx).await?)
} else {
Err(ExecutionFailureKind::KeyNotFoundError)
}
@ -156,13 +156,13 @@ impl WalletCore {
pub async fn poll_public_native_token_transfer(
&self,
hash: String,
) -> Result<nssa::PublicTransaction> {
) -> Result<nssa::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 = nssa::PublicTransaction::from_bytes(&tx_base64_decode)?;
let pub_tx = TransactionBody::from_bytes(tx_base64_decode);
Ok(pub_tx)
Ok(nssa::NSSATransaction::try_from(&pub_tx)?)
}
}