152 lines
4.4 KiB
Rust
Raw Normal View History

2024-11-25 07:26:16 +02:00
use rs_merkle::Hasher;
2025-09-03 10:29:51 +03:00
use std::io::{Cursor, Read};
2024-10-10 14:09:31 +03:00
2025-09-08 10:11:04 +03:00
use crate::{OwnHasher, transaction::EncodedTransaction};
2024-10-10 14:09:31 +03:00
pub type BlockHash = [u8; 32];
pub type BlockId = u64;
2025-08-28 12:00:04 +03:00
pub type TimeStamp = u64;
2024-10-10 14:09:31 +03:00
2025-08-12 12:18:13 -03:00
#[derive(Debug, Clone)]
2025-08-28 12:00:04 +03:00
pub struct BlockHeader {
2024-10-10 14:09:31 +03:00
pub block_id: BlockId,
pub prev_block_hash: BlockHash,
2024-10-10 14:09:31 +03:00
pub hash: BlockHash,
2025-08-28 12:00:04 +03:00
pub timestamp: TimeStamp,
2025-09-03 10:29:51 +03:00
pub signature: nssa::Signature,
2025-08-28 12:00:04 +03:00
}
#[derive(Debug, Clone)]
pub struct BlockBody {
2025-09-08 10:11:04 +03:00
pub transactions: Vec<EncodedTransaction>,
2025-08-28 12:00:04 +03:00
}
#[derive(Debug, Clone)]
pub struct Block {
pub header: BlockHeader,
pub body: BlockBody,
2024-10-10 14:09:31 +03:00
}
2024-11-25 07:26:16 +02:00
2025-08-12 12:18:13 -03:00
#[derive(Debug, PartialEq, Eq)]
2024-11-25 07:26:16 +02:00
pub struct HashableBlockData {
pub block_id: BlockId,
pub prev_block_hash: BlockHash,
2025-08-28 12:00:04 +03:00
pub timestamp: TimeStamp,
2025-09-08 10:11:04 +03:00
pub transactions: Vec<EncodedTransaction>,
2024-11-25 07:26:16 +02:00
}
2025-09-03 10:29:51 +03:00
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 {
2025-08-28 12:00:04 +03:00
header: BlockHeader {
2025-09-03 10:29:51 +03:00
block_id: self.block_id,
prev_block_hash: self.prev_block_hash,
2025-08-28 12:00:04 +03:00
hash,
2025-09-03 10:29:51 +03:00
timestamp: self.timestamp,
signature,
2025-08-28 12:00:04 +03:00
},
body: BlockBody {
2025-09-03 10:29:51 +03:00
transactions: self.transactions,
2025-08-28 12:00:04 +03:00
},
2024-11-25 07:26:16 +02:00
}
}
}
2025-08-12 12:18:13 -03:00
impl From<Block> for HashableBlockData {
fn from(value: Block) -> Self {
Self {
2025-09-02 10:17:00 +03:00
block_id: value.header.block_id,
prev_block_hash: value.header.prev_block_hash,
timestamp: value.header.timestamp,
transactions: value.body.transactions,
2025-08-12 12:18:13 -03:00
}
}
}
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_hash);
2025-09-02 10:17:00 +03:00
bytes.extend_from_slice(&self.timestamp.to_le_bytes());
2025-08-12 12:18:13 -03:00
let num_transactions: u32 = self.transactions.len() as u32;
bytes.extend_from_slice(&num_transactions.to_le_bytes());
for tx in &self.transactions {
2025-09-03 10:29:51 +03:00
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());
2025-08-12 12:18:13 -03:00
bytes.extend_from_slice(&tx.to_bytes());
}
bytes
}
2025-08-12 23:31:41 -03:00
// TODO: Improve error handling. Remove unwraps.
2025-08-12 12:18:13 -03:00
pub fn from_bytes(data: &[u8]) -> Self {
let mut cursor = Cursor::new(data);
let block_id = u64_from_cursor(&mut cursor);
let mut prev_block_hash = [0u8; 32];
cursor.read_exact(&mut prev_block_hash).unwrap();
2025-09-02 11:06:41 +03:00
let timestamp = u64_from_cursor(&mut cursor);
2025-08-12 12:18:13 -03:00
let num_transactions = u32_from_cursor(&mut cursor) as usize;
let mut transactions = Vec::with_capacity(num_transactions);
for _ in 0..num_transactions {
2025-09-03 10:29:51 +03:00
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]);
}
2025-09-08 10:11:04 +03:00
let tx = EncodedTransaction::from_bytes(tx_bytes);
2025-08-12 12:18:13 -03:00
transactions.push(tx);
}
Self {
block_id,
prev_block_hash,
2025-09-02 11:06:41 +03:00
timestamp,
2025-08-12 12:18:13 -03:00
transactions,
}
}
}
2025-08-12 23:31:41 -03:00
// TODO: Improve error handling. Remove unwraps.
2025-09-02 10:17:00 +03:00
pub fn u32_from_cursor(cursor: &mut Cursor<&[u8]>) -> u32 {
2025-08-12 12:18:13 -03:00
let mut word_buf = [0u8; 4];
cursor.read_exact(&mut word_buf).unwrap();
u32::from_le_bytes(word_buf)
}
2025-08-12 23:31:41 -03:00
// TODO: Improve error handling. Remove unwraps.
2025-09-02 10:17:00 +03:00
pub fn u64_from_cursor(cursor: &mut Cursor<&[u8]>) -> u64 {
2025-08-12 12:18:13 -03:00
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]
2025-08-12 23:31:41 -03:00
fn test_encoding_roundtrip() {
2025-08-12 12:18:13 -03:00
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();
2025-08-12 23:31:41 -03:00
let block_from_bytes = HashableBlockData::from_bytes(&bytes);
assert_eq!(hashable, block_from_bytes);
2025-08-12 12:18:13 -03:00
}
}