use std::io::{Cursor, Read, Result, Write};
use serde::{Deserialize, Serialize};
use crate::sha256d;
#[inline(always)]
fn read_u8(cur: &mut Cursor<Vec<u8>>) -> Result<u8> {
let mut raw = [0u8; 1];
std::io::Read::read_exact(cur, &mut raw)?;
Ok(raw[0])
}
#[inline(always)]
fn read_u16(cur: &mut Cursor<Vec<u8>>) -> Result<u16> {
let mut raw = [0u8; 2];
std::io::Read::read_exact(cur, &mut raw)?;
Ok(u16::from_le_bytes(raw))
}
#[inline(always)]
fn read_u32(cur: &mut Cursor<Vec<u8>>) -> Result<u32> {
let mut raw = [0u8; 4];
std::io::Read::read_exact(cur, &mut raw)?;
Ok(u32::from_le_bytes(raw))
}
#[inline(always)]
fn read_u64(cur: &mut Cursor<Vec<u8>>) -> Result<u64> {
let mut raw = [0u8; 8];
std::io::Read::read_exact(cur, &mut raw)?;
Ok(u64::from_le_bytes(raw))
}
fn read_var(cur: &mut Cursor<Vec<u8>>) -> Result<u64> {
let pre = read_u8(cur)?;
Ok(match pre {
0xFD => read_u16(cur)? as u64,
0xFE => read_u32(cur)? as u64,
0xFF => read_u64(cur)? as u64,
_ => pre as u64,
})
}
#[inline(always)]
fn read_256(cur: &mut Cursor<Vec<u8>>) -> Result<[u8; 32]> {
let mut hash = [0u8; 32];
std::io::Read::read_exact(cur, &mut hash)?;
hash.reverse(); Ok(hash)
}
#[inline(always)]
fn read_vec(cur: &mut Cursor<Vec<u8>>, len: u64) -> Result<Box<[u8]>> {
let mut vec = vec![0; len as usize];
std::io::Read::read_exact(cur, &mut vec)?;
assert_eq!(len, vec.len() as u64, "read_vec: {} != {}", len, vec.len());
Ok(vec.into_boxed_slice())
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TxIn {
pub prev_tx: [u8; 32],
pub prev_idx: u32,
pub script_len: u64,
pub script_sig: Box<[u8]>,
pub sequence: u32,
}
impl TxIn {
pub fn load(cur: &mut Cursor<Vec<u8>>) -> Result<TxIn> {
let mut prev_tx = read_256(cur)?;
let prev_idx = read_u32(cur)?;
let script_len = read_var(cur)?;
let script_sig = read_vec(cur, script_len)?;
let sequence = read_u32(cur)?;
Ok(TxIn { prev_tx, prev_idx, script_len, script_sig, sequence })
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TxOut {
pub amount: u64,
pub script_len: u64,
pub script_pub: Box<[u8]>,
}
impl TxOut {
pub fn load(cur: &mut Cursor<Vec<u8>>) -> Result<TxOut> {
let amount = read_u64(cur)?;
let script_len = read_var(cur)?;
let script_pub = read_vec(cur, script_len)?;
Ok(TxOut { amount, script_len, script_pub })
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Tx {
pub txid: [u8; 32], pub segwit: bool, pub version: u32,
pub in_count: u64,
pub inputs: Vec<TxIn>,
pub out_count: u64,
pub outputs: Vec<TxOut>,
pub lock_time: u32,
}
impl Tx {
pub fn load(cur: &mut Cursor<Vec<u8>>) -> Result<Tx> {
let pos_beg = cur.position() as usize;
let version = read_u32(cur)?;
let mut flags = 0u8;
let mut in_count = read_var(cur)?;
if in_count == 0 {
flags = read_u8(cur)?;
in_count = read_var(cur)?;
}
let mut inputs = Vec::<TxIn>::with_capacity(in_count as usize);
for _ in 0..in_count {
inputs.push(TxIn::load(cur)?);
}
let out_count = read_var(cur)?;
let mut outputs = Vec::<TxOut>::with_capacity(out_count as usize);
for _ in 0..out_count {
outputs.push(TxOut::load(cur)?);
}
let pos_seg = cur.position() as usize;
let segwit = flags & 1 > 0;
if segwit {
for _ in 0..in_count {
let num_items = read_var(cur)?;
for _ in 0..num_items {
let item_len = read_var(cur)?;
if item_len > 0 {
let _ = read_vec(cur, item_len)?;
}
}
}
}
let lock_time = read_u32(cur)?;
let pos_end = cur.position() as usize;
let raw = cur.get_ref();
let mut txid = if segwit {
let io_size = pos_seg - pos_beg - 6;
let mut bin = vec![0u8; 4 + io_size + 4];
bin[0..4].copy_from_slice(&raw[pos_beg..pos_beg + 4]);
bin[4..4 + io_size].copy_from_slice(&raw[(pos_beg + 6)..(pos_beg + 6) + io_size]);
bin[(4 + io_size)..(4 + io_size + 4)].copy_from_slice(&raw[pos_end - 4..pos_end]);
sha256d(&bin)
} else {
let io_size = pos_end - pos_beg;
let mut bin = vec![0u8; io_size];
bin.copy_from_slice(&raw[pos_beg..pos_end]);
sha256d(&bin)
};
txid.reverse();
Ok(Tx { txid, segwit, version, in_count, inputs, out_count, outputs, lock_time })
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Block {
pub height: u32, pub block_hash: [u8; 32], pub version: u32,
pub prev_block: [u8; 32],
pub merkle_root: [u8; 32],
pub timestamp: u32,
pub bits: u32,
pub nonce: u32,
pub tx_count: u64,
pub txs: Vec<Tx>,
}
impl Block {
pub fn load(cur: &mut Cursor<Vec<u8>>) -> Result<Block> {
let version = read_u32(cur)?;
let prev_block = read_256(cur)?;
let merkle_root = read_256(cur)?;
let timestamp = read_u32(cur)?;
let bits = read_u32(cur)?;
let nonce = read_u32(cur)?;
let tx_count = read_var(cur)?;
let mut txs = Vec::<Tx>::with_capacity(tx_count as usize);
for i in 0..tx_count {
txs.push(Tx::load(cur)?);
}
Ok(Block {
version,
prev_block,
merkle_root,
timestamp,
bits,
nonce,
tx_count,
txs,
height: 0,
block_hash: [0u8; 32],
})
}
}