bitcoind_request/command/get_raw_transaction.rs
1/*
2getrawtransaction "txid" ( verbose "blockhash" )
3
4Return the raw transaction data.
5
6By default this function only works for mempool transactions. When called with a blockhash
7argument, getrawtransaction will return the transaction if the specified block is available and
8the transaction is found in that block. When called without a blockhash argument, getrawtransaction
9will return the transaction if it is in the mempool, or if -txindex is enabled and the transaction
10is in a block in the blockchain.
11
12Hint: Use gettransaction for wallet transactions.
13
14If verbose is 'true', returns an Object with information about 'txid'.
15If verbose is 'false' or omitted, returns a string that is serialized, hex-encoded data for 'txid'.
16
17Arguments:
181. txid (string, required) The transaction id
192. verbose (boolean, optional, default=false) If false, return a string, otherwise return a json object
203. blockhash (string, optional) The block in which to look for the transaction
21
22Result (if verbose is not set or set to false):
23"str" (string) The serialized, hex-encoded data for 'txid'
24
25Result (if verbose is set to true):
26{ (json object)
27 "in_active_chain" : true|false, (boolean) Whether specified block is in the active chain or not (only present with explicit "blockhash" argument)
28 "hex" : "hex", (string) The serialized, hex-encoded data for 'txid'
29 "txid" : "hex", (string) The transaction id (same as provided)
30 "hash" : "hex", (string) The transaction hash (differs from txid for witness transactions)
31 "size" : n, (numeric) The serialized transaction size
32 "vsize" : n, (numeric) The virtual transaction size (differs from size for witness transactions)
33 "weight" : n, (numeric) The transaction's weight (between vsize*4-3 and vsize*4)
34 "version" : n, (numeric) The version
35 "locktime" : xxx, (numeric) The lock time
36 "vin" : [ (json array)
37 { (json object)
38 "txid" : "hex", (string) The transaction id
39 "vout" : n, (numeric) The output number
40 "scriptSig" : { (json object) The script
41 "asm" : "str", (string) asm
42 "hex" : "hex" (string) hex
43 },
44 "sequence" : n, (numeric) The script sequence number
45 "txinwitness" : [ (json array)
46 "hex", (string) hex-encoded witness data (if any)
47 ...
48 ]
49 },
50 ...
51 ],
52 "vout" : [ (json array)
53 { (json object)
54 "value" : n, (numeric) The value in BTC
55 "n" : n, (numeric) index
56 "scriptPubKey" : { (json object)
57 "asm" : "str", (string) the asm
58 "hex" : "str", (string) the hex
59 "reqSigs" : n, (numeric, optional) (DEPRECATED, returned only if config option -deprecatedrpc=addresses is passed) Number of required signatures
60 "type" : "str", (string) The type, eg 'pubkeyhash'
61 "address" : "str", (string, optional) bitcoin address (only if a well-defined address exists)
62 "addresses" : [ (json array, optional) (DEPRECATED, returned only if config option -deprecatedrpc=addresses is passed) Array of bitcoin addresses
63 "str", (string) bitcoin address
64 ...
65 ]
66 }
67 },
68 ...
69 ],
70 "blockhash" : "hex", (string) the block hash
71 "confirmations" : n, (numeric) The confirmations
72 "blocktime" : xxx, (numeric) The block time expressed in UNIX epoch time
73 "time" : n (numeric) Same as "blocktime"
74}
75
76Examples:
77> bitcoin-cli getrawtransaction "mytxid"
78> bitcoin-cli getrawtransaction "mytxid" true
79> curl --user myusername --data-binary '{"jsonrpc": "1.0", "id": "curltest", "method": "getrawtransaction", "params": ["mytxid", true]}' -H 'content-type: text/plain;' http://127.0.0.1:8332/
80> bitcoin-cli getrawtransaction "mytxid" false "myblockhash"
81> bitcoin-cli getrawtransaction "mytxid" true "myblockhash"
82
83*/
84use serde::{Deserialize, Serialize};
85use serde_json::value::to_raw_value;
86
87use crate::client::Client;
88use crate::{command::CallableCommand, Blockhash};
89
90use crate::command::request::request;
91
92type TxId = String;
93pub struct GetRawTransactionCommand {
94 txid: TxId,
95 is_verbose: bool,
96 blockhash: Option<Blockhash>,
97}
98
99impl GetRawTransactionCommand {
100 pub fn new(txid: TxId) -> Self {
101 GetRawTransactionCommand {
102 txid,
103 is_verbose: false,
104 blockhash: None,
105 }
106 }
107 pub fn verbose(&mut self, verbose: bool) -> &Self {
108 self.is_verbose = verbose;
109 self
110 }
111 pub fn blockhash(&mut self, blockhash: Blockhash) -> &Self {
112 self.blockhash = Some(blockhash);
113 self
114 }
115}
116
117#[derive(Serialize, Deserialize, Debug, Clone)]
118pub struct HexEncodedWitnessData(pub String);
119#[derive(Serialize, Deserialize, Debug, Clone)]
120pub struct BitcoinAddress(pub String);
121
122#[derive(Serialize, Deserialize, Debug, Clone)]
123#[serde(rename_all = "camelCase")]
124pub struct ScriptPubKey {
125 pub asm: String, // "asm", NOT A HEX
126 pub hex: String, // the hex
127 // deprecated
128 pub req_sigs: Option<u64>, // The required sigs
129 #[serde(alias = "type")]
130 pub type_: String, // The type, eg 'pubkeyhash'
131 pub address: Option<String>,
132 // deprecated
133 pub addresses: Option<Vec<String>>,
134}
135
136#[derive(Serialize, Deserialize, Debug, Clone)]
137#[serde(rename_all = "camelCase")]
138pub struct ScriptSig {
139 pub asm: String, // "asm", NOT A HEX
140 pub hex: String, // "hex", hex
141}
142
143#[derive(Serialize, Deserialize, Debug, Clone)]
144#[serde(rename_all = "camelCase")]
145#[serde(untagged)]
146pub enum Vin {
147 Coinbase(CoinbaseVin),
148 NonCoinbase(NonCoinbaseVin),
149}
150
151#[derive(Serialize, Deserialize, Debug, Clone)]
152#[serde(rename_all = "camelCase")]
153pub struct CoinbaseVin {
154 pub coinbase: String,
155 pub sequence: u64, // The script sequence number
156 pub txinwitness: Option<Vec<HexEncodedWitnessData>>, // hex-encoded witness data (if any)
157}
158
159#[derive(Serialize, Deserialize, Debug, Clone)]
160#[serde(rename_all = "camelCase")]
161pub struct NonCoinbaseVin {
162 pub txid: String, // "hex" The transaction id
163 pub vout: u64, // The output number
164 pub script_sig: ScriptSig,
165 pub sequence: u64, // The script sequence number
166 // TODO: Why is this optional?
167 pub txinwitness: Option<Vec<HexEncodedWitnessData>>,
168}
169
170#[derive(Serialize, Deserialize, Debug, Clone)]
171#[serde(rename_all = "camelCase")]
172pub struct Vout {
173 pub value: f64, // The value in BTC
174 pub n: u64, // index
175 pub script_pub_key: ScriptPubKey,
176 // Deprecated
177 pub req_sigs: Option<u64>,
178 pub address: Option<String>,
179 // Deprecated
180 pub addresses: Option<Vec<String>>,
181}
182#[derive(Serialize, Deserialize, Debug, Clone)]
183#[serde(rename_all = "camelCase")]
184pub struct Transaction {
185 pub in_active_chain: Option<bool>,
186 pub hex: String, // "hex" The serialized, hex-encoded data for 'txid'
187 pub txid: String, // "hex" The transaction id (same as provided)
188 pub hash: String, // "hex" The transaction hash (differs from txid for witness transactions)
189 pub size: u64, // The serialized transaction size
190 pub vsize: u64, // The virtual transaction size (differs from size for witness transactions)
191 pub weight: u64, // The transaction's weight (between vsize*4-3 and vsize*4)
192 pub version: u64, // The version
193 pub locktime: u64, // The lock time
194 pub vin: Vec<Vin>,
195 pub vout: Vec<Vout>,
196 pub blockhash: String, // "hex" the block hash
197 pub confirmations: u64, // "hex" The confirmations
198 pub blocktime: u64, // "unix time" The block time expressed in UNIX epoch time
199 pub time: u64, // "unix time" Same as "blocktime"
200}
201
202// TODO: I don't think this belongs in this package. We should focus on RPC request and responses
203// and abstract a better data layer into another package.
204impl Transaction {
205 pub fn is_coinbase_transaction(&self) -> bool {
206 match self.vin.first().unwrap() {
207 Vin::Coinbase(_x) => true,
208 Vin::NonCoinbase(_x) => false,
209 }
210 }
211}
212
213#[derive(Serialize, Deserialize, Debug)]
214#[serde(untagged)]
215pub enum GetRawTransactionCommandResponse {
216 SerializedHexEncodedData(String),
217 Transaction(Transaction),
218}
219
220// TODO: This will only work for GetBlockCommandVerbosity::BlockObjectWithoutTransactionInformation
221// because the json response has a different structure it returns for each verbosity option.
222// For example, GetBlockCommandVerbosity::BlockObjectWithTransactionInformation will return
223// an array for 'tx' field with full transaction structure, instead of only hashes for the
224// transaction. To accomplish this, we need to figure out how to have serde handle
225// conditional responses and map them to appropriate structs.
226impl CallableCommand for GetRawTransactionCommand {
227 type Response = GetRawTransactionCommandResponse;
228 fn call(&self, client: &Client) -> Result<Self::Response, jsonrpc::Error> {
229 let txid_arg = &self.txid;
230 let verbose_arg = &self.is_verbose;
231 // TODO: Add blockhas param!
232 //let blockhash_arg = &self.blockhash.0;
233 let txid_arg_raw_value = to_raw_value(&txid_arg).unwrap();
234 let verbose_arg_raw_value = to_raw_value(&verbose_arg).unwrap();
235 let command = "getrawtransaction";
236 let params = vec![txid_arg_raw_value, verbose_arg_raw_value];
237 let r = request(client, command, params);
238 let response: GetRawTransactionCommandResponse = r.result()?;
239 Ok(response)
240 }
241}