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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use crate::parser::script::evaluate_script;
use bitcoin::{Address, Block, BlockHash, Transaction, TxIn, TxOut, Txid};
use serde::{Deserialize, Serialize};

///
/// Block in a `simple` format.
///
/// A `SBlock` compared to a `Block` has the following more
/// attributes precomputed:
/// - `block hash`
/// - `transaction id`
/// - `output addresses`
/// - `output script types`
///
/// But is has the following attributes removed:
/// - `nounce`
/// - `previous block hash`
/// - `merkle root`
/// - `bits`
/// - `input witness`
/// - `output public script key hash`
///
/// `SBlock` reduces the amount of data memorized or transferred.
///
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
pub struct SBlock {
    pub header: SBlockHeader,
    pub txdata: Vec<STransaction>,
}

impl From<Block> for SBlock {
    ///
    /// Add addresses, block_hash, tx_id to the bitcoin library format,
    /// and also simplify the format.
    ///
    fn from(block: Block) -> SBlock {
        let block_hash = block.header.block_hash();
        SBlock {
            header: SBlockHeader::parse(block.header, block_hash),
            txdata: block.txdata.into_iter().map(|x| x.into()).collect(),
        }
    }
}

#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
pub struct SBlockHeader {
    pub block_hash: BlockHash,
    pub time: u32,
}

impl SBlockHeader {
    pub fn parse(blk: bitcoin::BlockHeader, block_hash: BlockHash) -> SBlockHeader {
        SBlockHeader {
            block_hash,
            time: blk.time,
        }
    }
}

/// `STransaction` compared to `Transaction` has the following
/// precomputed:
/// - `transaction ID`
/// - `output script type`
/// - `output addresses`
///
/// It has the following removed:
/// - `input witness`
/// - `output public script key hash`
///
/// It reduces the amount of data memorized or transferred (to python).
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
pub struct STransaction {
    pub txid: Txid,
    /// List of inputs
    pub input: Vec<STxIn>,
    /// List of outputs
    pub output: Vec<STxOut>,
}

impl From<Transaction> for STransaction {
    fn from(tx: Transaction) -> STransaction {
        let is_coinbase = tx.is_coin_base();
        let txid = tx.txid();
        let input = if is_coinbase {
            Vec::new()
        } else {
            tx.input.into_iter().map(|x| x.into()).collect()
        };
        STransaction {
            txid,
            input,
            output: tx.output.into_iter().map(|x| x.into()).collect(),
        }
    }
}

#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
pub struct STxIn {
    pub txid: Txid,
    pub vout: u32,
}

impl From<TxIn> for STxIn {
    fn from(tx_in: TxIn) -> STxIn {
        STxIn {
            txid: tx_in.previous_output.txid,
            vout: tx_in.previous_output.vout,
        }
    }
}

#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Debug)]
pub struct STxOut {
    pub value: u64,
    pub addresses: Box<[Address]>,
}

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