diff --git a/nssa/src/public_transaction/encoding.rs b/nssa/src/public_transaction/encoding.rs new file mode 100644 index 0000000..01483a5 --- /dev/null +++ b/nssa/src/public_transaction/encoding.rs @@ -0,0 +1,147 @@ +use std::io::{Cursor, Read}; + +use nssa_core::program::ProgramId; + +use crate::{ + public_transaction::{Message, WitnessSet}, Address, PublicKey, PublicTransaction, Signature +}; + +const MESSAGE_ENCODING_PREFIX_LEN: usize = 19; +const MESSAGE_ENCODING_PREFIX: &[u8; MESSAGE_ENCODING_PREFIX_LEN] = b"NSSA/v0.1/TxMessage"; + +impl Message { + /// Serializes a `Message` into bytes in the following layout: + /// 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 { + let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec(); + // program_id: [u32; 8] + for word in &self.program_id { + bytes.extend_from_slice(&word.to_le_bytes()); + } + // addresses: Vec<[u8;32]> + // serialize length as u32 little endian, then all addresses concatenated + let addresses_len = self.addresses.len() as u32; + bytes.extend(&addresses_len.to_le_bytes()); + for addr in &self.addresses { + bytes.extend_from_slice(addr.value()); + } + // nonces: Vec + let nonces_len = self.nonces.len() as u32; + bytes.extend(&nonces_len.to_le_bytes()); + for nonce in &self.nonces { + bytes.extend(&nonce.to_le_bytes()); + } + // instruction_data: Vec + // serialize length as u32 little endian, then all addresses concatenated + let instr_len = self.instruction_data.len() as u32; + bytes.extend(&instr_len.to_le_bytes()); + for word in &self.instruction_data { + bytes.extend(&word.to_le_bytes()); + } + + 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, + } + } +} + + +impl WitnessSet { + 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, + } + } +} + +impl PublicTransaction { + pub fn to_bytes(&self) -> Vec { + let mut bytes = self.message.message_to_bytes(); + bytes.extend_from_slice(&self.witness_set.to_bytes()); + bytes + } + + pub fn from_bytes(bytes: &[u8]) -> Self { + let mut cursor = Cursor::new(bytes); + Self::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, + } + } +} + +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/message.rs b/nssa/src/public_transaction/message.rs index 6ae02d5..4b4e72a 100644 --- a/nssa/src/public_transaction/message.rs +++ b/nssa/src/public_transaction/message.rs @@ -7,8 +7,6 @@ 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 { @@ -33,85 +31,5 @@ impl Message { instruction_data, }) } - - /// Serializes a `Message` into bytes in the following layout: - /// 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 { - let mut bytes = MESSAGE_ENCODING_PREFIX.to_vec(); - // program_id: [u32; 8] - for word in &self.program_id { - bytes.extend_from_slice(&word.to_le_bytes()); - } - // addresses: Vec<[u8;32]> - // serialize length as u32 little endian, then all addresses concatenated - let addresses_len = self.addresses.len() as u32; - bytes.extend(&addresses_len.to_le_bytes()); - for addr in &self.addresses { - bytes.extend_from_slice(addr.value()); - } - // nonces: Vec - let nonces_len = self.nonces.len() as u32; - bytes.extend(&nonces_len.to_le_bytes()); - for nonce in &self.nonces { - bytes.extend(&nonce.to_le_bytes()); - } - // instruction_data: Vec - // serialize length as u32 little endian, then all addresses concatenated - let instr_len = self.instruction_data.len() as u32; - bytes.extend(&instr_len.to_le_bytes()); - for word in &self.instruction_data { - bytes.extend(&word.to_le_bytes()); - } - - 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 e91baba..6111bae 100644 --- a/nssa/src/public_transaction/mod.rs +++ b/nssa/src/public_transaction/mod.rs @@ -11,6 +11,7 @@ use sha2::{Digest, digest::FixedOutput}; use crate::{V01State, address::Address, error::NssaError}; +mod encoding; mod message; mod witness_set; @@ -47,20 +48,6 @@ impl PublicTransaction { } } - pub fn to_bytes(&self) -> Vec { - let mut bytes = self.message.message_to_bytes(); - bytes.extend_from_slice(&self.witness_set.to_bytes()); - bytes - } - - 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, - } - } pub fn hash(&self) -> [u8; 32] { let bytes = self.to_bytes(); @@ -145,7 +132,7 @@ mod tests { }; #[test] - fn test() { + fn test_to_bytes() { 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)); diff --git a/nssa/src/public_transaction/witness_set.rs b/nssa/src/public_transaction/witness_set.rs index 4477d46..7d8b5bc 100644 --- a/nssa/src/public_transaction/witness_set.rs +++ b/nssa/src/public_transaction/witness_set.rs @@ -35,32 +35,4 @@ impl WitnessSet { 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/encoding.rs b/nssa/src/signature/encoding.rs new file mode 100644 index 0000000..005cea9 --- /dev/null +++ b/nssa/src/signature/encoding.rs @@ -0,0 +1,22 @@ +use std::io::{Cursor, Read}; + +use crate::{PublicKey, Signature}; + + +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) + } +} + +impl Signature { + // TODO: remove unwraps and return Result + pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Self { + let mut value = [0u8; 64]; + cursor.read_exact(&mut value).unwrap(); + Self { value } + } +} diff --git a/nssa/src/signature/mod.rs b/nssa/src/signature/mod.rs index 9539e45..13a0fe3 100644 --- a/nssa/src/signature/mod.rs +++ b/nssa/src/signature/mod.rs @@ -1,6 +1,7 @@ mod private_key; mod public_key; mod signature; +mod encoding; pub use private_key::PrivateKey; pub use public_key::PublicKey; diff --git a/nssa/src/signature/public_key.rs b/nssa/src/signature/public_key.rs index a040f04..f7a8c25 100644 --- a/nssa/src/signature/public_key.rs +++ b/nssa/src/signature/public_key.rs @@ -21,11 +21,3 @@ impl PublicKey { } } -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 2f859a4..8e4756d 100644 --- a/nssa/src/signature/signature.rs +++ b/nssa/src/signature/signature.rs @@ -27,11 +27,3 @@ impl Signature { } } -impl Signature { - // TODO: remove unwraps and return Result - pub(crate) fn from_cursor(cursor: &mut Cursor<&[u8]>) -> Self { - let mut value = [0u8; 64]; - cursor.read_exact(&mut value).unwrap(); - Self { value } - } -} diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index 69c9c8d..8a880db 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -72,10 +72,7 @@ impl JsonHandler { async fn process_send_tx(&self, request: Request) -> Result { 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 tx = nssa::PublicTransaction::from_bytes(&send_tx_req.transaction); { let mut state = self.sequencer_state.lock().await;