-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add notes on transaction signing with Dogecoin 1.21 experimental.
- Loading branch information
Showing
1 changed file
with
159 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
# Signing Notes | ||
|
||
Writing up my notes on the transaction creation and signing process so they're | ||
readily available to refer to later, and because they may be useful to others. | ||
|
||
All of this is tested on an experimental branch of Dogecoin 1.21; the theory is | ||
generally applicable | ||
but other tools will have different interfaces. | ||
|
||
## Pre-requisites | ||
|
||
In order to sign the output transaction, the PSBT needs to include the details | ||
of the input transaction(s). As nodes do not track transactions unless they're | ||
relevant to an address the node is watching, the address the transaction is to | ||
needs to be watched. | ||
|
||
This only needs to be done once, as the transaction creator can add these to | ||
the PSBT and then circulate the expanded PSBT. | ||
|
||
If this is done before the address receives any funds, you can avoid rescanning, | ||
but as the address now exists the node needs to rescan the blockchain, which | ||
takes around an hour. | ||
|
||
I ran the following to add the address: | ||
|
||
```shell | ||
$ dogecoin-cli importaddress 9xEP9voiNLw7Y7DS87M8QRqKM43r6r5KM5 "corefunds" true | ||
``` | ||
|
||
The following will then return a non-empty list: | ||
|
||
```shell | ||
$ dogecoin-cli listunspent 1 9999999 "[\"9xEP9voiNLw7Y7DS87M8QRqKM43r6r5KM5\"]" | ||
``` | ||
|
||
## Creating the transaction | ||
|
||
Creating the transaction involves defining its inputs, and the amounts to send. | ||
This generates a very bare PSBT which isn't very useful until it's processed | ||
by a node with a wallet. | ||
|
||
The following consumes input #1 (the second) of transaction | ||
169a73cf972fbc1ff9d480474e5de7db03d63c243f4b57d25cdd09ba56ff2738, which was 10 Doge, | ||
and sends 9.9 Doge back to 9xEP9voiNLw7Y7DS87M8QRqKM43r6r5KM5. The remaining 0.1 Doge | ||
is burnt as a (high) transaction fee. | ||
|
||
```shell | ||
dogecoin-cli "[{\"txid\":\"169a73cf972fbc1ff9d480474e5de7db03d63c243f4b57d25cdd09ba56ff2738\",\"vout\":1}]" "[{\"9xEP9voiNLw7Y7DS87M8QRqKM43r6r5KM5\":9.9}]" | ||
``` | ||
|
||
This creates the following PSBT, which you'll see as inputs to later examples: | ||
|
||
``` | ||
cHNidP8BAFMCAAAAATgn/1a6Cd1c0ldLPyQ81gPb511OR4DU+R+8L5fPc5oWAQAAAAD/////AYAzAjsAAAAAF6kUP5EutQN3mspXxZVmYkhcTKkTMK2HAAAAAAAAAA== | ||
``` | ||
|
||
I can decode the resulting PSBT to check its contents: | ||
|
||
```shell | ||
$ dogecoin-cli decodepsbt cHNidP8BAFMCAAAAATgn/1a6Cd1c0ldLPyQ81gPb511OR4DU+R+8L5fPc5oWAQAAAAD/////AYAzAjsAAAAAF6kUP5EutQN3mspXxZVmYkhcTKkTMK2HAAAAAAAAAA== | ||
``` | ||
|
||
## Wallet Processing the Transaction | ||
|
||
The next step is to add the required details to the PSBT can be signed. | ||
|
||
``` | ||
$ dogecoin-cli -datadir=/data/dogecoin walletprocesspsbt cHNidP8BAFMCAAAAATgn/1a6Cd1c0ldLPyQ81gPb511OR4DU+R+8L5fPc5oWAQAAAAD/////AYAzAjsAAAAAF6kUP5EutQN3mspXxZVmYkhcTKkTMK2HAAAAAAAAAA== | ||
``` | ||
|
||
If this has worked correctly, decoding the resulting PSBT should show it | ||
includes the transaction inputs (i.e. pipe it to `| jq .inputs`). | ||
|
||
If this is done on a wallet with an available signing key, by default | ||
it will add a signature to the PSBT too. The process I follow involves | ||
a node which does not have the key, and then moving the PSBT to an isolated | ||
machine for signing. | ||
|
||
## Signing the Transaction | ||
|
||
Signing the transaction is identical to wallet processing, except performed | ||
on a node with one of the signing keys present. It will then update the | ||
PSBT with the signature from that signing key. | ||
|
||
Before signing, it's important to `decodepsbt` the PSBT to check what is | ||
being signed. This produces an output such as that below (note this is | ||
trimmed to focus on just the "tx" and "fee"): | ||
|
||
``` | ||
$ dogecoin-cli decodepsbt <psbt after wallet processing> | ||
{ | ||
"tx": { | ||
"txid": "e80a06fb189acef79e98ffd86ceea78ff7504e434f4aea0a86c50373327ddd98", | ||
"hash": "e80a06fb189acef79e98ffd86ceea78ff7504e434f4aea0a86c50373327ddd98", | ||
"version": 2, | ||
"size": 83, | ||
"vsize": 83, | ||
"weight": 332, | ||
"locktime": 0, | ||
"vin": [ | ||
{ | ||
"txid": "169a73cf972fbc1ff9d480474e5de7db03d63c243f4b57d25cdd09ba56ff2738", | ||
"vout": 1, | ||
"scriptSig": { | ||
"asm": "", | ||
"hex": "" | ||
}, | ||
"sequence": 4294967295 | ||
} | ||
], | ||
"vout": [ | ||
{ | ||
"value": 9.90000000, | ||
"n": 0, | ||
"scriptPubKey": { | ||
"asm": "OP_HASH160 3f912eb503779aca57c5956662485c4ca91330ad OP_EQUAL", | ||
"hex": "a9143f912eb503779aca57c5956662485c4ca91330ad87", | ||
"reqSigs": 1, | ||
"type": "scripthash", | ||
"addresses": [ | ||
"9xEP9voiNLw7Y7DS87M8QRqKM43r6r5KM5" | ||
] | ||
} | ||
} | ||
] | ||
}, | ||
... | ||
"fee": 0.10000000 | ||
} | ||
``` | ||
|
||
The "tx" is the transaction being built. Within it, "vin" is the inputs (what | ||
is being spent) and "vout" is the outputs. Here you can see it has a single | ||
output of 9.9 Dogecoins being sent to `9xEP9voiNLw7Y7DS87M8QRqKM43r6r5KM5`. | ||
The fee is then calculated based on the total input value, minus the total | ||
output value, and in this case is 0.1 Dogecoins. | ||
|
||
## Finalizing the Transaction | ||
|
||
Once you have enough signatures, you can assemble the transaction. Note | ||
"can" doesn not mean "should" - getting a signature from every signer | ||
is definitely preferable. That said, conventionally only sufficient | ||
signatures to meet the threshold are relayed, so the other signatures | ||
should be kept for audit purposes elsewhere. | ||
|
||
Depending how the signing has happened, if each person has passed the | ||
PSBT along to the next in turn, you should be able to call `finalizepsbt` | ||
directly. Alternatively, if they were signed independently then the | ||
signatures need assembling, `combinepsbt` can put the PSBTs together | ||
and return the assembled set ready to pass to `finalizepsbt`. | ||
|
||
`finalizepsbt` returns a fully signed transaction, but does not relay it. | ||
Before relaying, it's a good idea to `decoderawtransaction` the transaction | ||
to verify it is correct. | ||
|
||
## Relaying the Transaction | ||
|
||
Once the finalized transaction is verified, it can be relayed with | ||
`sendrawtransaction`, which will relay it to the P2P network for mining. |