use bitcoin::consensus::encode::Encodable;
use bitcoin::BlockHash;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use subcoin_primitives::runtime::Coin;
pub fn tx_out_ser(outpoint: bitcoin::OutPoint, coin: &Coin) -> bitcoin::io::Result<Vec<u8>> {
let mut data = Vec::new();
outpoint.consensus_encode(&mut data)?;
let height_and_coinbase = (coin.height << 1) | (coin.is_coinbase as u32);
height_and_coinbase.consensus_encode(&mut data)?;
let txout = bitcoin::TxOut {
value: bitcoin::Amount::from_sat(coin.amount),
script_pubkey: bitcoin::ScriptBuf::from_bytes(coin.script_pubkey.clone()),
};
txout.consensus_encode(&mut data)?;
Ok(data)
}
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct Utxo {
pub txid: bitcoin::Txid,
pub vout: u32,
pub coin: Coin,
}
pub struct UtxoSnapshotGenerator {
output_filepath: PathBuf,
output_file: File,
}
impl UtxoSnapshotGenerator {
pub fn new(output_filepath: PathBuf, output_file: File) -> Self {
Self {
output_filepath,
output_file,
}
}
pub fn path(&self) -> &Path {
&self.output_filepath
}
pub fn write_utxo_entry(
&mut self,
txid: bitcoin::Txid,
vout: u32,
coin: Coin,
) -> std::io::Result<()> {
let Coin {
is_coinbase,
amount,
height,
script_pubkey,
} = coin;
let outpoint = bitcoin::OutPoint { txid, vout };
let mut data = Vec::new();
let amount = txoutset::Amount::new(amount);
let code = txoutset::Code {
height,
is_coinbase,
};
let script = txoutset::Script::from_bytes(script_pubkey);
outpoint.consensus_encode(&mut data)?;
code.consensus_encode(&mut data)?;
amount.consensus_encode(&mut data)?;
script.consensus_encode(&mut data)?;
let _ = self.output_file.write(data.as_slice())?;
Ok(())
}
pub fn write_snapshot_metadata(
&mut self,
bitcoin_block_hash: BlockHash,
coins_count: u64,
) -> std::io::Result<()> {
let mut data = Vec::new();
bitcoin_block_hash
.consensus_encode(&mut data)
.expect("Failed to encode");
coins_count
.consensus_encode(&mut data)
.expect("Failed to write utxo set size");
let _ = self.output_file.write(data.as_slice())?;
Ok(())
}
pub fn write_utxo_snapshot(
&mut self,
bitcoin_block_hash: BlockHash,
utxos_count: u64,
utxos: impl IntoIterator<Item = Utxo>,
) -> std::io::Result<()> {
self.write_snapshot_metadata(bitcoin_block_hash, utxos_count)?;
for Utxo { txid, vout, coin } in utxos {
self.write_utxo_entry(txid, vout, coin)?;
}
Ok(())
}
}