1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
//!
//! Add addresses, block_hash, tx_id to the bitcoin library format
//!
use crate::api::Block;
use crate::parser::script::{evaluate_script, Type};
use bitcoin::{Address, BlockHash, Transaction, TxMerkleNode, TxOut, Txid};
use serde::{Deserialize, Serialize};

///
/// Block in a `full` format.
///
/// A `FBlock` compared to a `Block` has the following more
/// attributes computed:
/// - `block hash`
/// - `transaction id`
/// - `output addresses`
/// - `output script types`
///
#[derive(Serialize, Deserialize)]
pub struct FBlock {
    pub header: FBlockHeader,
    pub txdata: Vec<FTransaction>,
}

impl From<Block> for FBlock {
    /// obtain addresses for each output of each transactions
    fn from(block: bitcoin::Block) -> FBlock {
        let block_hash = block.header.block_hash();
        FBlock {
            header: FBlockHeader::parse(block.header, block_hash),
            txdata: block.txdata.into_iter().map(|x| x.into()).collect(),
        }
    }
}

#[derive(Serialize, Deserialize)]
pub struct FBlockHeader {
    pub version: i32,
    pub block_hash: BlockHash,
    pub prev_blockhash: BlockHash,
    pub merkle_root: TxMerkleNode,
    pub time: u32,
    pub bits: u32,
    pub nonce: u32,
}

impl FBlockHeader {
    /// obtain addresses for each output
    pub fn parse(b: bitcoin::BlockHeader, block_hash: BlockHash) -> FBlockHeader {
        FBlockHeader {
            version: b.version,
            block_hash,
            prev_blockhash: b.prev_blockhash,
            merkle_root: b.merkle_root,
            time: b.time,
            bits: b.bits,
            nonce: b.nonce,
        }
    }
}

/// `FTransaction` compared to `Transaction` has the following
/// precomputed:
/// - `transaction ID`
/// - `output script type`
/// - `output addresses`
#[derive(Serialize, Deserialize)]
pub struct FTransaction {
    pub version: i32,
    pub lock_time: u32,
    pub txid: Txid,
    /// List of inputs
    pub input: Vec<bitcoin::TxIn>,
    /// List of outputs
    pub output: Vec<FTxOut>,
}

impl From<Transaction> for FTransaction {
    /// obtain addresses for each output
    fn from(tx: Transaction) -> FTransaction {
        FTransaction {
            version: tx.version,
            lock_time: tx.lock_time,
            txid: tx.txid(),
            input: tx.input,
            output: tx.output.into_iter().map(FTxOut::from).collect(),
        }
    }
}

#[derive(Serialize, Deserialize, Clone)]
pub struct FTxOut {
    pub value: u64,
    pub script_pubkey: bitcoin::Script,
    pub script_type: Type,
    pub addresses: Box<[Address]>,
}

impl From<TxOut> for FTxOut {
    fn from(out: bitcoin::TxOut) -> FTxOut {
        let eval = evaluate_script(&out.script_pubkey, bitcoin::Network::Bitcoin);
        FTxOut {
            value: out.value,
            script_pubkey: out.script_pubkey,
            script_type: eval.pattern,
            addresses: eval.addresses.into_boxed_slice(),
        }
    }
}