-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add notes on transaction signing #18
Draft
rnicoll
wants to merge
3
commits into
dogecoinfoundation:main
Choose a base branch
from
rnicoll:signing-notes
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,165 @@ | ||
# 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 uses the [createpsbt](https://bitcoincore.org/en/doc/0.17.0/rpc/rawtransactions/createpsbt/) | ||
command to generate a new transaction which consumes input #1 (the second) of | ||
transaction | ||
`169a73cf972fbc1ff9d480474e5de7db03d63c243f4b57d25cdd09ba56ff2738`, which was | ||
10 Dogecoins, and sends 9.9 Dogecoins back to | ||
`9xEP9voiNLw7Y7DS87M8QRqKM43r6r5KM5`. The remaining 0.1 Dogecoins are burnt | ||
as a (somewhat high) transaction fee. | ||
|
||
```shell | ||
dogecoin-cli createpsbt "[{\"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== | ||
``` | ||
|
||
You can decode the resulting PSBT to check its contents, we'll discuss | ||
this in detail later. | ||
|
||
```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. For | ||
this we'll use [walletprocesspsbt](https://bitcoincore.org/en/doc/0.17.0/rpc/wallet/walletprocesspsbt/), as below: | ||
|
||
``` | ||
$ dogecoin-cli walletprocesspsbt cHNidP8BAFMCAAAAATgn/1a6Cd1c0ldLPyQ81gPb511OR4DU+R+8L5fPc5oWAQAAAAD/////AYAzAjsAAAAAF6kUP5EutQN3mspXxZVmYkhcTKkTMK2HAAAAAAAAAA== | ||
``` | ||
|
||
If the wallet has the address watched correctly, decoding the resulting PSBT | ||
will 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" does 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](https://bitcoincore.org/en/doc/0.17.0/rpc/rawtransactions/finalizepsbt/) | ||
directly. Alternatively, if they were signed independently then the | ||
signatures need assembling, [combinepsbt](https://bitcoincore.org/en/doc/0.17.0/rpc/rawtransactions/combinepsbt/) | ||
can put the PSBTs together and return the assembled set ready to pass in to | ||
finalizepsbt. | ||
|
||
finalizepsbt returns a fully signed transaction, but does not relay it. | ||
Before relaying, it's a good idea to [decoderawtransaction](https://bitcoincore.org/en/doc/0.17.0/rpc/rawtransactions/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. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can add
4532328
as the final param to start the rescan from the first block containing a transaction to this address.