Skip to content

Commit

Permalink
Add notes on transaction signing
Browse files Browse the repository at this point in the history
Add notes on transaction signing with Dogecoin 1.21 experimental.
  • Loading branch information
rnicoll committed Dec 29, 2022
1 parent 853fffb commit ab73323
Showing 1 changed file with 159 additions and 0 deletions.
159 changes: 159 additions & 0 deletions docs/signing_notes_dogecoin_core_1_21_experimental.md
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.

0 comments on commit ab73323

Please sign in to comment.