mirror of
https://github.com/ChristopherA/Learning-Bitcoin-from-the-Command-Line.git
synced 2025-06-09 08:56:26 +00:00
Update 4_2__Interlude_Using_JQ.md
This commit is contained in:
parent
60640dd7a0
commit
34b839666a
@ -164,14 +164,14 @@ You can of course rename your new keys as you see fit:
|
||||
|
||||
The JQ lookups so far have been fairly simple: you use a key to lookup one or more key-values in a JSON Object or Array. But what if you instead want to lookup a key-value in an object ... by another key-value? This sort of indirect lookup has real applicability when you're working with transactions built on existing UTXOs. For example, what if you wanted to figure out the value of a UTXO we're using, something that we know is vitally important in raw transactions?
|
||||
|
||||
To start with, we have a raw transaction:
|
||||
To start with, we have a raw transaction. Note that this is a more complex raw transaction with two inputs and two outputs. We'll learn about making those in a few sections, but for now it'll serve as an example of how to pluck all of the information out of a transaction:
|
||||
```
|
||||
$ bitcoin-cli decoderawtransaction $rawtxhex
|
||||
{
|
||||
"txid": "f445f121085d98635f7302e641f815d1ca4ce70f0e1b03f144ad1661dc5e10e7",
|
||||
"hash": "f445f121085d98635f7302e641f815d1ca4ce70f0e1b03f144ad1661dc5e10e7",
|
||||
"size": 85,
|
||||
"vsize": 85,
|
||||
"txid": "959190d447589e4c0f6ad31459579a4e4f6945b8791eadc9e5f0e55fc6205317",
|
||||
"hash": "959190d447589e4c0f6ad31459579a4e4f6945b8791eadc9e5f0e55fc6205317",
|
||||
"size": 160,
|
||||
"vsize": 160,
|
||||
"version": 2,
|
||||
"locktime": 0,
|
||||
"vin": [
|
||||
@ -183,11 +183,20 @@ $ bitcoin-cli decoderawtransaction $rawtxhex
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
},
|
||||
{
|
||||
"txid": "ec0598918f6f5476cb90365651e8a2724ef26f949290bbf196f41ed96092a52f",
|
||||
"vout": 0,
|
||||
"scriptSig": {
|
||||
"asm": "",
|
||||
"hex": ""
|
||||
},
|
||||
"sequence": 4294967295
|
||||
}
|
||||
],
|
||||
"vout": [
|
||||
{
|
||||
"value": 0.75950000,
|
||||
"value": 0.65050000,
|
||||
"n": 0,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_DUP OP_HASH160 e7c1345fc8f87c68170b3aa798a956c2fe6a9eff OP_EQUALVERIFY OP_CHECKSIG",
|
||||
@ -198,21 +207,52 @@ $ bitcoin-cli decoderawtransaction $rawtxhex
|
||||
"n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"value": 4.00000000,
|
||||
"n": 1,
|
||||
"scriptPubKey": {
|
||||
"asm": "OP_DUP OP_HASH160 29193095edbef6378fbcd84a8ae7c8164e433ca7 OP_EQUALVERIFY OP_CHECKSIG",
|
||||
"hex": "76a91429193095edbef6378fbcd84a8ae7c8164e433ca788ac",
|
||||
"reqSigs": 1,
|
||||
"type": "pubkeyhash",
|
||||
"addresses": [
|
||||
"mjGGB8rSXAHSd9xGA1bLfqMpB41XWuDdSF"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
[[SHOULD REALLY REDO THIS TO LIST ALL TRANSACTIONS, OR INCLUDE IT AS A SECOND EXAMPLE.]]
|
||||
|
||||
To retrieve the 0th (and in this case only) txid, we need to `jq` to the .vin key-value, then to its 0th array, then to that array's .txid key-value. Easy:
|
||||
```
|
||||
$ usedtxid=$(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[0] | .txid')
|
||||
$ echo $usedtxid
|
||||
|
||||
### Retrieve the Value(s)
|
||||
|
||||
If we wanted to just retrieve the txid for the two UTXOs, we need to `jq` to the .vin key-value, then to its 0th array, then to that array's .txid key-value. Then do the same with the 1st. Easy:
|
||||
```
|
||||
$ usedtxid1=$(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[0] | .txid')
|
||||
$ echo $usedtxid1
|
||||
2b5f5798359e0e23e02764588166f222d4ce056419dec83c743b72aad171d708
|
||||
$ usedtxid2=$(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[1] | .txid')
|
||||
$ echo $usedtxid2
|
||||
ec0598918f6f5476cb90365651e8a2724ef26f949290bbf196f41ed96092a52f
|
||||
```
|
||||
A magic invocation of `select` and `contains`, used after a typical pipe through all the JSON objects, can then be used to look up the transaction in question:
|
||||
However, it'd be better to have a general case that _automatically_ saved all the txids of our UTXOs. Fortunately, bash lets you nest a set of `()`s to put your output into an array. Here's an example
|
||||
```
|
||||
$ bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'$usedtxid'"))'
|
||||
usedtxid=($(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[] | .txid'))
|
||||
$ echo ${usedtxid[0]}
|
||||
2b5f5798359e0e23e02764588166f222d4ce056419dec83c743b72aad171d708
|
||||
$ echo ${usedtxid[1]}
|
||||
ec0598918f6f5476cb90365651e8a2724ef26f949290bbf196f41ed96092a52f
|
||||
```
|
||||
|
||||
### Retrieve the Related Object(s)
|
||||
|
||||
We can now step back to `listunspent`. To find our transactions, we need to look through the entire JSON Array (`[]`). We can then choose (`select`) individual JSON objects that include (`contain`) our txids. (The `select` and `contain` arguments show off some of the complexity of JSON, but for now just know that this particular invocation will work.)
|
||||
|
||||
Here we are picking out our two UTXOs, one at a time:
|
||||
```
|
||||
$ bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'${usedtxid[0]}'"))'
|
||||
{
|
||||
"txid": "2b5f5798359e0e23e02764588166f222d4ce056419dec83c743b72aad171d708",
|
||||
"vout": 1,
|
||||
@ -220,31 +260,86 @@ $ bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'$usedtxid'")
|
||||
"account": "",
|
||||
"scriptPubKey": "76a9142fe70d51e886b9ef73b76c1743c5a2bb2894db8588ac",
|
||||
"amount": 0.76,
|
||||
"confirmations": 6617,
|
||||
"confirmations": 6689,
|
||||
"spendable": true,
|
||||
"solvable": true
|
||||
}
|
||||
$ bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'${usedtxid[1]}'"))'
|
||||
{
|
||||
"txid": "ec0598918f6f5476cb90365651e8a2724ef26f949290bbf196f41ed96092a52f",
|
||||
"vout": 0,
|
||||
"address": "mjtEqr4Fffd1XtpAkKoDkMBP54mMXJeQ3j",
|
||||
"account": "",
|
||||
"scriptPubKey": "76a9142fe70d51e886b9ef73b76c1743c5a2bb2894db8588ac",
|
||||
"amount": 3.9,
|
||||
"confirmations": 7191,
|
||||
"spendable": true,
|
||||
"solvable": true
|
||||
}
|
||||
```
|
||||
Which leaves us with a wonderful two-line script to determine how much money was in the first UTXO input for a transaction:
|
||||
A simple Bash for-loop can instead give you _all_ of your UTXOs:
|
||||
```
|
||||
$ usedtxid=$(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[0] | .txid')
|
||||
$ bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'$usedtxid'")) | .amount'
|
||||
for txid in ${usedtxid[@]}; do bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'$txid'"))'; done
|
||||
{
|
||||
"txid": "2b5f5798359e0e23e02764588166f222d4ce056419dec83c743b72aad171d708",
|
||||
"vout": 1,
|
||||
"address": "mjtEqr4Fffd1XtpAkKoDkMBP54mMXJeQ3j",
|
||||
"account": "",
|
||||
"scriptPubKey": "76a9142fe70d51e886b9ef73b76c1743c5a2bb2894db8588ac",
|
||||
"amount": 0.76,
|
||||
"confirmations": 6699,
|
||||
"spendable": true,
|
||||
"solvable": true
|
||||
}
|
||||
{
|
||||
"txid": "ec0598918f6f5476cb90365651e8a2724ef26f949290bbf196f41ed96092a52f",
|
||||
"vout": 0,
|
||||
"address": "mjtEqr4Fffd1XtpAkKoDkMBP54mMXJeQ3j",
|
||||
"account": "",
|
||||
"scriptPubKey": "76a9142fe70d51e886b9ef73b76c1743c5a2bb2894db8588ac",
|
||||
"amount": 3.9,
|
||||
"confirmations": 7202,
|
||||
"spendable": true,
|
||||
"solvable": true
|
||||
}
|
||||
```
|
||||
|
||||
## Use JSON for Simple Calculation by Key-Value
|
||||
|
||||
**Usage Example:** _Automatically calculate the value of the UTXOs used in a transaction._
|
||||
|
||||
You can now take one further step, and request the .amount (or any other JSON key-value) from the Objects you're retrieving:
|
||||
```
|
||||
$ usedtxid=($(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[] | .txid'))
|
||||
$ for txid in ${usedtxid[@]}; do bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'$txid'")) | .amount'; done
|
||||
0.76
|
||||
3.9
|
||||
```
|
||||
Using our earlier `awk` script, you can even add them up, to see how much money is in the UTXOs your transaction is spending:
|
||||
```
|
||||
$ usedtxid=($(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[] | .txid'))
|
||||
$ for txid in ${usedtxid[@]}; do bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'$txid'")) | .amount'; done | awk '{s+=$1} END {print s}'
|
||||
4.66
|
||||
```
|
||||
|
||||
For more JSON magic (and if any of this isn't clear), please read the [JSON Manual](https://stedolan.github.io/jq/manual/) and the [JSON Cookbook](https://github.com/stedolan/jq/wiki/Cookbook).
|
||||
|
||||
## Use JQ for Complex Calculations
|
||||
|
||||
**Usage Example:** _Calculate the fee for a simple one-input, one-output transaction._
|
||||
**Usage Example:** _Calculate the fee for a real transaction._
|
||||
|
||||
With this in hand, you can now use a few lines of code to see the transaction fee for the simple, one-input, one-output example raw transaction that we wrote in the previous section:
|
||||
```
|
||||
$ usedtxid=$(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[0] | .txid')
|
||||
$ btcin=$(bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'$usedtxid'")) | .amount')
|
||||
$ btcout=$(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vout [0] | .value')
|
||||
$ usedtxid=($(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vin | .[] | .txid'))
|
||||
$ btcin=$(for txid in ${usedtxid[@]}; do bitcoin-cli listunspent | jq -r '.[] | select (.txid | contains("'$txid'")) | .amount'; done | awk '{s+=$1} END {print s}')
|
||||
$ btcout=$(bitcoin-cli decoderawtransaction $rawtxhex | jq -r '.vout [] | .value' | awk '{s+=$1} END {print s}')
|
||||
$ echo "$btcin-$btcout"| /usr/bin/bc
|
||||
.0005
|
||||
.0095
|
||||
```
|
||||
And that's also a good example of why you double-check your fees: we'd intended to send a transaction fee of 5,000 satoshis, but sent 95,000 satoshis instead. Whoops!
|
||||
|
||||
If you'd like to have this JQ
|
||||
> **WARNING:** This script has not been robustly checked. If you are going to use it to verify real transaction fees you should only do it as a triple-check after you've already done all the math yourself.
|
||||
|
||||
### Use JQ to Calculate Transaction Fees for Real
|
||||
|
||||
@ -254,5 +349,31 @@ However, as we've noted, a real transaction may have more than one input and wil
|
||||
|
||||
> **WARNING:** This script has not been robustly checked. If you are going to use it to verify real transaction fees you should only do it as a triple-check after you've already done all the math yourself.
|
||||
|
||||
```
|
||||
file: txfee-calc.sh
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
if [ -z $1 ];
|
||||
then
|
||||
echo "You must include the raw transaction hex as an argument.";
|
||||
exit;
|
||||
fi
|
||||
|
||||
usedtxid=($(bitcoin-cli decoderawtransaction $1 | jq -r '.vin | .[] | .txid'))
|
||||
btcin=$(for txid in ${usedtxid[@]}; do bitcoin-cli listunspent | jq -r '.[] | s
|
||||
elect (.txid | contains("'$txid'")) | .amount'; done | awk '{s+=$1} END {print
|
||||
s}')
|
||||
btcout=$(bitcoin-cli decoderawtransaction $1 | jq -r '.vout [] | .value' | awk
|
||||
'{s+=$1} END {print s}')
|
||||
echo "$btcin-$btcout"| /usr/bin/bc
|
||||
|
||||
```
|
||||
You can then run it as follows:
|
||||
```
|
||||
$ ./txfee-calc.sh $rawtxhex
|
||||
.0095
|
||||
```
|
||||
|
||||
## Make Some New Aliases
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user