use crate::common::binary_conversions::binary_to_string; use crate::common::skein::skein_256_hash_data; use crate::to_string; use crate::Cursor; use crate::Serialize; use crate::{AsyncReadExt, AsyncWriteExt}; #[derive(Debug, Serialize, Clone)] // 49 bytes pub struct UnsignedGenesisTransaction { pub txtype: u8, // 1 byte transaction type, should be 0 pub message: String, // 48 bytes fixed genesis block message } #[derive(Debug, Serialize, Clone)] // 49 bytes pub struct GenesisTransaction { pub unsigned: UnsignedGenesisTransaction, // 49 bytes } impl UnsignedGenesisTransaction { // Create the unsigned genesis transaction. pub async fn new(txtype: u8, message: &str) -> Self { Self { txtype, message: message.to_string(), } } pub async fn hash(&self) -> String { // Genesis hashes the serialized unsigned payload like other // transaction types, even though it has no wallet signature. let serialized = to_string(self).unwrap(); skein_256_hash_data(&serialized) } } impl GenesisTransaction { const MESSAGE_LENGTH: usize = 48; pub const BYTE_LENGTH: usize = 1 + Self::MESSAGE_LENGTH; pub async fn new(unsigned: UnsignedGenesisTransaction) -> Self { // Wrap a freshly created unsigned genesis payload. Self { unsigned } } pub async fn load(unsigned: UnsignedGenesisTransaction) -> Self { // Rebuild a genesis transaction already read from storage. Self { unsigned } } pub async fn to_bytes(&self) -> tokio::io::Result> { // Serialize into the fixed genesis byte layout: // type byte followed by the fixed-length launch message. let mut buffer = Vec::with_capacity(Self::BYTE_LENGTH); let mut cursor = Cursor::new(&mut buffer); cursor .write_all(&self.unsigned.txtype.to_le_bytes()) .await?; cursor.write_all(self.unsigned.message.as_bytes()).await?; Ok(buffer) } pub async fn from_bytes(txtype: u8, bytes: &[u8]) -> tokio::io::Result { // The transaction type is read by the block parser, so this // function receives only the remaining genesis bytes. if bytes.len() != Self::BYTE_LENGTH - 1 { return Err(tokio::io::Error::other("Invalid Byte Count", )); } // Read from the remaining fixed-width transaction bytes. let mut cursor = Cursor::new(bytes); // Decode the fixed 48-byte genesis message. let mut message_bytes = vec![0; Self::MESSAGE_LENGTH]; cursor.read_exact(&mut message_bytes).await?; let message = binary_to_string(message_bytes); let unsigned = UnsignedGenesisTransaction { txtype, message }; Ok(GenesisTransaction { unsigned }) } }