-
Notifications
You must be signed in to change notification settings - Fork 59
/
Copy pathapi.rs
234 lines (217 loc) · 7.62 KB
/
api.rs
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
//! Structs from the Esplora API
//!
//! See: <https://github.com/Blockstream/esplora/blob/master/API.md>
pub use bitcoin::consensus::{deserialize, serialize};
pub use bitcoin::hex::FromHex;
use bitcoin::Weight;
pub use bitcoin::{
transaction, Amount, BlockHash, OutPoint, ScriptBuf, Transaction, TxIn, TxOut, Txid, Witness,
};
use serde::Deserialize;
/// It contains the value and scriptpubkey of a
/// previous transaction output that a transaction
/// input can reference.
#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct PrevOut {
pub value: u64,
pub scriptpubkey: ScriptBuf,
}
/// Represents the transaction input containing
/// a Previous output (or none if coinbase) and includes
/// the unlocking script, witness data, sequence number,
/// and a flag indicating if it is a coinbase input.
#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct Vin {
pub txid: Txid,
pub vout: u32,
// None if coinbase
pub prevout: Option<PrevOut>,
pub scriptsig: ScriptBuf,
#[serde(deserialize_with = "deserialize_witness", default)]
pub witness: Vec<Vec<u8>>,
pub sequence: u32,
pub is_coinbase: bool,
}
/// Represents the transaction output containing a value and
/// a scriptpubkey.
#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct Vout {
pub value: u64,
pub scriptpubkey: ScriptBuf,
}
/// Represents Transaction Status.
#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct TxStatus {
pub confirmed: bool,
pub block_height: Option<u32>,
pub block_hash: Option<BlockHash>,
pub block_time: Option<u64>,
}
/// It holds the block height, a Merkle path of
/// transaction IDs, and the position of the
/// transaction in the tree to verify its inclusion
/// in a block.
#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct MerkleProof {
pub block_height: u32,
pub merkle: Vec<Txid>,
pub pos: usize,
}
/// Struct that contains the status of an output in a transaction.
#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct OutputStatus {
pub spent: bool,
pub txid: Option<Txid>,
pub vin: Option<u64>,
pub status: Option<TxStatus>,
}
/// This Struct represents the status of a block in the blockchain.
/// `in_best_chain` - a boolean that shows whether the block is part of the main chain.
/// `height` - Optional field that shows the height of the block if block is in main chain.
/// `next_best` - Optional field that contains `BlockHash` of the next block that may represent
/// the next block in the best chain.
#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct BlockStatus {
pub in_best_chain: bool,
pub height: Option<u32>,
pub next_best: Option<BlockHash>,
}
/// Structure represents a complete transaction
#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct Tx {
pub txid: Txid,
pub version: i32,
pub locktime: u32,
pub vin: Vec<Vin>,
pub vout: Vec<Vout>,
/// Transaction size in raw bytes (NOT virtual bytes).
pub size: usize,
/// Transaction weight units.
pub weight: u64,
pub status: TxStatus,
pub fee: u64,
}
/// Returns timing information of a Block
/// containg `timestamp` and `height` of block
#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct BlockTime {
pub timestamp: u64,
pub height: u32,
}
/// Provides a Summary of a Bitcoin block which includes
/// `BlockHash`, `BlockTime`, `previousblockhash`, `merkle_root`.
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
pub struct BlockSummary {
pub id: BlockHash,
#[serde(flatten)]
pub time: BlockTime,
/// Hash of the previous block, will be `None` for the genesis block.
pub previousblockhash: Option<bitcoin::BlockHash>,
pub merkle_root: bitcoin::hash_types::TxMerkleNode,
}
/// Address statistics, includes the address, and the utxo information for the address.
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
pub struct AddressStats {
/// The address.
pub address: String,
/// The summary of transactions for this address, already on chain.
pub chain_stats: AddressTxsSummary,
/// The summary of transactions for this address, currently in the mempool.
pub mempool_stats: AddressTxsSummary,
}
/// Contains a summary of the transactions for an address.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Deserialize)]
pub struct AddressTxsSummary {
/// The number of funded transaction outputs.
pub funded_txo_count: u32,
/// The sum of the funded transaction outputs, in satoshis.
pub funded_txo_sum: u64,
/// The number of spent transaction outputs.
pub spent_txo_count: u32,
/// The sum of the spent transaction outputs, in satoshis.
pub spent_txo_sum: u64,
/// The total number of transactions.
pub tx_count: u32,
}
impl Tx {
/// Converts a transaction into a standard `Bitcoin transaction`.
pub fn to_tx(&self) -> Transaction {
Transaction {
version: transaction::Version::non_standard(self.version),
lock_time: bitcoin::absolute::LockTime::from_consensus(self.locktime),
input: self
.vin
.iter()
.cloned()
.map(|vin| TxIn {
previous_output: OutPoint {
txid: vin.txid,
vout: vin.vout,
},
script_sig: vin.scriptsig,
sequence: bitcoin::Sequence(vin.sequence),
witness: Witness::from_slice(&vin.witness),
})
.collect(),
output: self
.vout
.iter()
.cloned()
.map(|vout| TxOut {
value: Amount::from_sat(vout.value),
script_pubkey: vout.scriptpubkey,
})
.collect(),
}
}
/// Checks Transaction status, returns a `BlockTime` struct contaning
/// `height` and `timestamp` if transaction has been confirmed or
/// `None` otherwise.
pub fn confirmation_time(&self) -> Option<BlockTime> {
match self.status {
TxStatus {
confirmed: true,
block_height: Some(height),
block_time: Some(timestamp),
..
} => Some(BlockTime { timestamp, height }),
_ => None,
}
}
/// Takes Transaction as input
/// iterates through all the inputs present in the transaction
/// and checks for prevout field and creates a `TxOut` Struct for each input if it exists
/// then returns all optional TxOut values as a vector.
pub fn previous_outputs(&self) -> Vec<Option<TxOut>> {
self.vin
.iter()
.cloned()
.map(|vin| {
vin.prevout.map(|po| TxOut {
script_pubkey: po.scriptpubkey,
value: Amount::from_sat(po.value),
})
})
.collect()
}
/// Takes Transaction as input and returns
/// the `Weight instance` of the weight present in Transaction.
pub fn weight(&self) -> Weight {
Weight::from_wu(self.weight)
}
/// Takes Transaction as input and returns
/// the `Amount instance` of the satoshis present in Transaction.
pub fn fee(&self) -> Amount {
Amount::from_sat(self.fee)
}
}
fn deserialize_witness<'de, D>(d: D) -> Result<Vec<Vec<u8>>, D::Error>
where
D: serde::de::Deserializer<'de>,
{
let list = Vec::<String>::deserialize(d)?;
list.into_iter()
.map(|hex_str| Vec::<u8>::from_hex(&hex_str))
.collect::<Result<Vec<Vec<u8>>, _>>()
.map_err(serde::de::Error::custom)
}