89 lines
2.9 KiB
Rust
89 lines
2.9 KiB
Rust
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)] // 13 bytes
|
|
pub struct UnsignedRewardsTransaction {
|
|
pub txtype: u8, // 1 byte transaction type, should be 1
|
|
pub timestamp: u32, // 4 bytes timestamp used in the reward payload
|
|
pub value: u64, // 8 bytes reward value
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Clone)]
|
|
pub struct RewardsTransaction {
|
|
// 13 bytes
|
|
pub unsigned: UnsignedRewardsTransaction, // 13 bytes consensus-created reward data
|
|
}
|
|
|
|
impl UnsignedRewardsTransaction {
|
|
// Create an unsigned reward transaction for a mined block.
|
|
pub async fn new(txtype: u8, timestamp: u32, value: u64) -> Self {
|
|
Self {
|
|
txtype,
|
|
timestamp,
|
|
value,
|
|
}
|
|
}
|
|
|
|
// Hash the unsigned reward data for transaction indexing.
|
|
pub async fn hash(&self) -> String {
|
|
let serialized = to_string(self).unwrap();
|
|
skein_256_hash_data(&serialized)
|
|
}
|
|
}
|
|
|
|
impl RewardsTransaction {
|
|
pub const BYTE_LENGTH: usize = 1 + 4 + 8;
|
|
|
|
pub async fn new(unsigned: UnsignedRewardsTransaction) -> Self {
|
|
// Rewards are not wallet-signed, so the final transaction
|
|
// only wraps the consensus-created unsigned data.
|
|
Self { unsigned }
|
|
}
|
|
|
|
pub async fn load(unsigned: UnsignedRewardsTransaction) -> Self {
|
|
// Rebuild a reward transaction already read from storage.
|
|
Self { unsigned }
|
|
}
|
|
|
|
pub async fn to_bytes(&self) -> tokio::io::Result<Vec<u8>> {
|
|
// Serialize into the fixed reward layout: type, timestamp, value.
|
|
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.timestamp.to_le_bytes())
|
|
.await?;
|
|
cursor.write_all(&self.unsigned.value.to_le_bytes()).await?;
|
|
Ok(buffer)
|
|
}
|
|
|
|
pub async fn from_bytes(txtype: u8, bytes: &[u8]) -> tokio::io::Result<Self> {
|
|
// The block parser already consumed the transaction type byte.
|
|
if bytes.len() != Self::BYTE_LENGTH - 1 {
|
|
return Err(tokio::io::Error::other("Invalid Byte Count"));
|
|
}
|
|
|
|
// Read the remaining fixed reward bytes.
|
|
let mut cursor = Cursor::new(bytes);
|
|
|
|
// Decode timestamp and reward value in the same order they were written.
|
|
let timestamp = cursor.read_u32_le().await?;
|
|
let value = cursor.read_u64_le().await?;
|
|
|
|
// Rebuild the unsigned reward payload.
|
|
let unsigned = UnsignedRewardsTransaction {
|
|
txtype,
|
|
timestamp,
|
|
value,
|
|
};
|
|
|
|
// Wrap the rebuilt unsigned reward payload.
|
|
Ok(RewardsTransaction { unsigned })
|
|
}
|
|
}
|