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}