83 lines
2.8 KiB
Rust
83 lines
2.8 KiB
Rust
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<Vec<u8>> {
|
|
// 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<Self> {
|
|
// 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 })
|
|
}
|
|
}
|