diff --git a/common/src/test_utils.rs b/common/src/test_utils.rs index 173886f..bd3fadc 100644 --- a/common/src/test_utils.rs +++ b/common/src/test_utils.rs @@ -34,7 +34,7 @@ pub fn produce_dummy_empty_transaction() -> nssa::PublicTransaction { let program_id = nssa::program::Program::authenticated_transfer_program().id(); let addresses = vec![]; let nonces = vec![]; - let instruction_data = 0; + let instruction_data: u128 = 0; let message = nssa::public_transaction::Message::try_new(program_id, addresses, nonces, instruction_data).unwrap(); let private_key = nssa::PrivateKey::try_new([1; 32]).unwrap(); diff --git a/nssa/Cargo.toml b/nssa/Cargo.toml index 90bd34f..5788e30 100644 --- a/nssa/Cargo.toml +++ b/nssa/Cargo.toml @@ -9,7 +9,6 @@ risc0-zkvm = "2.3.1" nssa-core = { path = "core" } program-methods = { path = "program_methods" } serde = "1.0.219" -serde_cbor = "0.11.2" sha2 = "0.10.9" secp256k1 = "0.31.1" diff --git a/nssa/src/public_transaction/message.rs b/nssa/src/public_transaction/message.rs index aaa04ed..6ae02d5 100644 --- a/nssa/src/public_transaction/message.rs +++ b/nssa/src/public_transaction/message.rs @@ -1,3 +1,5 @@ +use std::io::{Cursor, Read}; + use nssa_core::{ account::Nonce, program::{InstructionData, ProgramId}, @@ -5,6 +7,8 @@ use nssa_core::{ use serde::{Deserialize, Serialize}; use crate::{Address, error::NssaError, program::Program}; +const MESSAGE_ENCODING_PREFIX_LEN: usize = 19; +const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] = b"NSSA/v0.1/TxMessage"; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct Message { @@ -34,8 +38,6 @@ impl Message { /// TAG || (bytes LE) * 8 || addresses_len (4 bytes LE) || addresses (32 bytes * N) || nonces_len (4 bytes LE) || nonces (16 bytes * M) || instruction_data_len || instruction_data (4 bytes * K) /// Integers and words are encoded in little-endian byte order, and fields appear in the above order. pub(crate) fn message_to_bytes(&self) -> Vec { - const MESSAGE_ENCODING_PREFIX: &[u8; 19] = b"NSSA/v0.1/TxMessage"; - let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec(); // program_id: [u32; 8] for word in &self.program_id { @@ -64,4 +66,52 @@ impl Message { bytes } + + pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Self { + let prefix = { + let mut this = [0u8; MESSAGE_ENCODING_PREFIX_LEN]; + cursor.read_exact(&mut this).unwrap(); + this + }; + assert_eq!(&prefix, MESSAGE_ENCODING_PREFIX); + let program_id: ProgramId = { + let mut this = [0u32; 8]; + for i in 0..8 { + this[i] = u32_from_cursor(cursor); + } + this + }; + let addresses_len = u32_from_cursor(cursor); + let mut addresses = Vec::with_capacity(addresses_len as usize); + for _ in 0..addresses_len { + let mut value = [0u8; 32]; + cursor.read_exact(&mut value).unwrap(); + addresses.push(Address::new(value)) + } + let nonces_len = u32_from_cursor(cursor); + let mut nonces = Vec::with_capacity(nonces_len as usize); + for _ in 0..nonces_len { + let mut buf = [0u8; 16]; + cursor.read_exact(&mut buf).unwrap(); + nonces.push(u128::from_le_bytes(buf)) + } + let instruction_data_len = u32_from_cursor(cursor); + let mut instruction_data = Vec::with_capacity(instruction_data_len as usize); + for _ in 0..instruction_data_len { + let word = u32_from_cursor(cursor); + instruction_data.push(word) + } + Self { + program_id, + addresses, + nonces, + instruction_data, + } + } +} + +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) } diff --git a/nssa/src/public_transaction/mod.rs b/nssa/src/public_transaction/mod.rs index 162257a..269f7d5 100644 --- a/nssa/src/public_transaction/mod.rs +++ b/nssa/src/public_transaction/mod.rs @@ -1,10 +1,12 @@ -use std::collections::{HashMap, HashSet}; +use std::{ + collections::{HashMap, HashSet}, + io::Cursor, +}; use nssa_core::{ account::{Account, AccountWithMetadata}, program::validate_execution, }; -use serde::{Deserialize, Serialize}; use sha2::{Digest, digest::FixedOutput}; use crate::{V01State, address::Address, error::NssaError}; @@ -15,7 +17,7 @@ mod witness_set; pub use message::Message; pub use witness_set::WitnessSet; -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct PublicTransaction { message: Message, witness_set: WitnessSet, @@ -45,8 +47,24 @@ impl PublicTransaction { } } + fn to_bytes(&self) -> Vec { + 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); + Self { + message, + witness_set, + } + } + pub fn hash(&self) -> [u8; 32] { - let bytes = serde_cbor::to_vec(&self).unwrap(); + let bytes = self.to_bytes(); let mut hasher = sha2::Sha256::new(); hasher.update(&bytes); hasher.finalize_fixed().into() @@ -116,3 +134,36 @@ impl PublicTransaction { Ok(message.addresses.iter().cloned().zip(post_states).collect()) } } + +#[cfg(test)] +mod tests { + use crate::{ + Address, PrivateKey, PublicTransaction, PublicKey, + program::Program, + public_transaction::{Message, WitnessSet}, + }; + + #[test] + fn test() { + let key1 = PrivateKey::try_new([1; 32]).unwrap(); + let key2 = PrivateKey::try_new([2; 32]).unwrap(); + let addr1 = Address::from_public_key(&PublicKey::new(&key1)); + let addr2 = Address::from_public_key(&PublicKey::new(&key2)); + let nonces = vec![5, 99]; + let instruction = 1337; + let message = Message::try_new( + Program::authenticated_transfer_program().id(), + vec![addr1, addr2], + nonces, + instruction, + ) + .unwrap(); + + let witness_set = WitnessSet::for_message(&message, &[&key1, &key2]); + let tx = PublicTransaction::new(message, witness_set); + + let bytes = tx.to_bytes(); + let recov_tx = PublicTransaction::from_bytes(&bytes); + assert_eq!(tx, recov_tx); + } +} diff --git a/nssa/src/public_transaction/witness_set.rs b/nssa/src/public_transaction/witness_set.rs index 262f976..4477d46 100644 --- a/nssa/src/public_transaction/witness_set.rs +++ b/nssa/src/public_transaction/witness_set.rs @@ -1,8 +1,10 @@ +use std::io::{Cursor, Read}; + use serde::{Deserialize, Serialize}; -use crate::{PrivateKey, PublicKey, Signature, public_transaction::Message}; +use crate::{PrivateKey, PublicKey, Signature, error::NssaError, public_transaction::Message}; -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct WitnessSet { pub(crate) signatures_and_public_keys: Vec<(Signature, PublicKey)>, } @@ -32,4 +34,33 @@ impl WitnessSet { pub fn iter_signatures(&self) -> impl Iterator { self.signatures_and_public_keys.iter() } + + pub(crate) fn to_bytes(&self) -> Vec { + let mut bytes = Vec::new(); + let size = self.signatures_and_public_keys.len() as u32; + bytes.extend_from_slice(&size.to_le_bytes()); + for (signature, public_key) in &self.signatures_and_public_keys { + bytes.extend_from_slice(&signature.value); + bytes.extend_from_slice(&public_key.0); + } + bytes + } + + // TODO: remove unwraps and return Result + pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Self { + let num_signatures: u32 = { + let mut buf = [0u8; 4]; + cursor.read_exact(&mut buf).unwrap(); + u32::from_le_bytes(buf) + }; + let mut signatures_and_public_keys = Vec::with_capacity(num_signatures as usize); + for i in 0..num_signatures { + let signature = Signature::from_cursor(cursor); + let public_key = PublicKey::from_cursor(cursor); + signatures_and_public_keys.push((signature, public_key)) + } + Self { + signatures_and_public_keys, + } + } } diff --git a/nssa/src/signature/public_key.rs b/nssa/src/signature/public_key.rs index 1073cba..a040f04 100644 --- a/nssa/src/signature/public_key.rs +++ b/nssa/src/signature/public_key.rs @@ -1,10 +1,11 @@ +use std::io::{Cursor, Read}; + use serde::{Deserialize, Serialize}; use crate::PrivateKey; - // TODO: Dummy impl. Replace by actual public key. -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct PublicKey(pub(crate) [u8; 32]); impl PublicKey { @@ -19,3 +20,12 @@ impl PublicKey { Self(value) } } + +impl PublicKey { + // TODO: remove unwraps and return Result + pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Self { + let mut value = [0u8; 32]; + cursor.read_exact(&mut value).unwrap(); + Self(value) + } +} diff --git a/nssa/src/signature/signature.rs b/nssa/src/signature/signature.rs index eb0fe24..2f859a4 100644 --- a/nssa/src/signature/signature.rs +++ b/nssa/src/signature/signature.rs @@ -1,10 +1,10 @@ -use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::io::{Cursor, Read}; use crate::{PrivateKey, PublicKey, error::NssaError, public_transaction::Message}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct Signature { - value: [u8; 64], + pub(crate) value: [u8; 64], } impl Signature { @@ -27,30 +27,11 @@ impl Signature { } } -impl Serialize for Signature { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - // Serialize as a slice - serializer.serialize_bytes(&self.value) - } -} - -impl<'de> Deserialize<'de> for Signature { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let bytes: &[u8] = Deserialize::deserialize(deserializer)?; - if bytes.len() != 64 { - return Err(serde::de::Error::invalid_length( - bytes.len(), - &"expected 64 bytes", - )); - } +impl Signature { + // TODO: remove unwraps and return Result + pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Self { let mut value = [0u8; 64]; - value.copy_from_slice(bytes); - Ok(Signature { value }) + cursor.read_exact(&mut value).unwrap(); + Self { value } } } diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 2e69bfe..ac59b63 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -102,10 +102,13 @@ impl SequencerCore { .mempool .pop_size(self.sequencer_config.max_num_tx_in_block); - let valid_transactions = transactions + println!("##"); + println!("{:?}", transactions.len()); + let valid_transactions: Vec<_> = transactions .into_iter() .filter_map(|tx| self.execute_check_transaction_on_state(tx).ok()) .collect(); + println!("{:?}", valid_transactions.len()); let prev_block_hash = self .store @@ -157,15 +160,13 @@ mod tests { fn setup_sequencer_config() -> SequencerConfig { 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 { @@ -236,13 +237,13 @@ mod tests { #[test] fn test_start_different_intial_accounts_balances() { 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, 42, 42, 42, + 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, 42, 42, 42, + 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 {