Proposed v0 DLC TLV messages and Deterministic Fee Computation (#81)

* Specified DLC TLV messages and added happy-path test vectors

* Responded to Ben's review

* Updated test vectors to use correct Multisignature ordering and up-to-date BIP 340

* Responded to Tibo's review

* Attempted to specify funding inputs and funding signatures in a general way

* Regenerated test vectors as per the updated funding input and funding signature specification

* Specified generalized fee computation and fixed test vectors

* Added oracle signature and signed transactions to test vectors

* Responded to review from Tibo

* Fixed table of contents

* Clarified TLV vs. LN Message format, fixed off-by-one fee computation, updated test vectors for fees, have not yet updated test vectors for LN Message format

* Made offer, accept and sign conform with Lightning Message format

* Added a clarification

* Made contract_info a proper object

* Fixed test vector contract id hashes

* Made redeem script use compact size uint and removed test vectors from this PR
This commit is contained in:
Nadav Kohen
2020-09-29 10:33:18 -05:00
committed by GitHub
parent dfa2a46153
commit 22b23ebe39
3 changed files with 189 additions and 57 deletions

View File

@@ -12,6 +12,17 @@ All data fields are unsigned big-endian unless otherwise specified.
* [Connection Handling and Multiplexing](#connection-handling-and-multiplexing)
* [Message Format](#message-format)
* [Fundamental Types](#fundamental-types)
* [DLC Specific Types](#dlc-specific-types)
* [The `contract_info` Type](#the-contract_info-type)
* [Version 0 `contract_info`](#version-0-contract_info)
* [The `oracle_info` Type](#the-oracle_info-type)
* [Version 0 `oracle_info`](#version-0-oracle_info)
* [The `funding_input` Type](#the-funding_input-type)
* [Temporary `funding_input`](#temporary-funding_input)
* [The `cet_adaptor_signatures` Type](#the-cet_adaptor_signatures-type)
* [Version 0 `cet_adaptor_signatures`](#version-0-cet_adaptor_signatures)
* [The `funding_signatures` Type](#the-funding_signatures-type)
* [Version 0 `funding_signatures`](#version-0-funding_signatures)
* [Authors](#authors)
## Connection Handling and Multiplexing
@@ -20,7 +31,13 @@ Implementations MUST use a single connection per peer; contract messages (which
## Message Format
We reuse the [Lightning Message Format](https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md#lightning-message-format) and the [Type-Length-Value Format](https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md#type-length-value-format)
We reuse the [Lightning Message Format](https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md#lightning-message-format) and the [Type-Length-Value Format](https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md#type-length-value-format) (TLV).
To be clear, any encoded binary blob that can be sent over the wire will follow the Lightning Message Format
while all sub-types internal to these messages will follow the Type-Length-Value Format.
This means that types on outer-messages will be represented with `u16` integers (defined below) and their length
is omitted from their encoding because the transport layer has the length in a separate unencrypted field.
Meanwhile all typed sub-messages (which follow TLV format) will have their types represented using `bigsize` integers
(defined below) and their lengths (also `bigsize`) are included in their encodings.
## Fundamental Types
@@ -44,15 +61,109 @@ The following convenience types are also defined:
* `contract_id`: a 32-byte contract_id (see [Protocol Specification](Protocol.md))
* `sha256`: a 32-byte SHA2-256 hash
* `signature`: a 64-byte bitcoin Elliptic Curve signature
* `ecdsa_adaptor_signature`: a 65-byte ECDSA adaptor signature (TODO: link to doc once [#50](https://github.com/discreetlogcontracts/dlcspecs/issues/50) is done)
* `dleq_proof`: a 97-byte zero-knowledge proof of discrete log equality (TODO: link to doc once [#50](https://github.com/discreetlogcontracts/dlcspecs/issues/50) is done)
* `x_point`: a 32-byte x-only public key with implicit y-coordinate being even as in [BIP 340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki#design)
* `point`: a 33-byte Elliptic Curve point (compressed encoding as per [SEC 1 standard](http://www.secg.org/sec1-v2.pdf#subsubsection.2.3.3))
* `spk`: A bitcoin script public key encoded as ASM prefixed with a Bitcoin CompactSize unsigned integer
* `script_sig`: A bitcoin script signature encoded as ASM prefixed with a Bitcoin CompactSize unsigned integer
* `short_contract_id`: an 8 byte value identifying a contract funding transaction on-chain (see [BOLT #7](https://github.com/lightningnetwork/lightning-rfc/blob/master/07-routing-gossip.md#definition-of-short-channel-id))
* `bigsize`: a variable-length, unsigned integer similar to Bitcoin's CompactSize encoding, but big-endian. Described in [BigSize](https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md#appendix-a-bigsize-test-vectors).
* `contract_info`: ???
* `oracle_info`: ???
* `funding_input`: ???
* `cet_signatures`: ???
* `funding_signatures`: ???
## DLC Specific Types
The following DLC-specific types are used throughout the specification. All type numbers are placeholders subject to change both here and in [Protocol.md](Protocol.md).
### The `contract_info` Type
This type contains information about a contracts outcomes and their corresponding payouts. To save space, only one side's POV is included in this message as the other can be derived using `remote_payout = total_collateral - local_payout`.
#### Version 0 `contract_info`
1. type: 42768 (`contract_info_v0`)
2. data:
* [`sha256`:`outcome_1`]
* [`u64`:`outcome_1_local_payout`]
* ...
* [`sha256`:`outcome_n`]
* [`u64`:`outcome_n_local_payout`]
This type of contract info is a simple enumeration where the value `n` is omitted from being explicitly included as it can be derived from the length field of the TLV.
### The `oracle_info` Type
This type contains information about the oracle(s) to be used in executing a DLC, and possibly the outcomes possible if these are not specified in the corresponding `contract_info`.
#### Version 0 `oracle_info`
1. type: 42770 (`oracle_info_v0`)
2. data:
* [`x_point`:`oracle_public_key`]
* [`x_point`:`oracle_nonce`]
This type of oracle info is for single-oracle, single signature (and hence single nonce) events.
### The `funding_input` Type
This type contains information about a specific input to be used in a funding transaction, as well as its corresponding on-chain UTXO.
#### Version 0 `funding_input`
1. type: 42772 (`funding_input_v0`)
2. data:
* [`u16`:`prevtx_len`]
* [`prevtx_len*byte`:`prevtx`]
* [`u32`:`prevtx_vout`]
* [`u32`:`sequence`]
* [`u16`:`max_witness_len`]
* [`script_sig`:`redeemscript`]
`prevtx_tx` is the serialized transaction whose `prevtx_vout` output is being spent.
The transaction is used to validate this spent output's value and to validate that it is a SegWit output.
`max_witness_len` is the total serialized length of the witness data that will be supplied
(e.g. sizeof(varint) + sizeof(witness) for each) in `funding_signatures`.
`redeemscript` is the script signature field for the input. Only applicable for P2SH-wrapped inputs.
In all native Segwit inputs, `redeemscript` will be a `0` byte (from the `script_sig` size prefix).
### The `cet_adaptor_signatures` Type
This type contains CET signatures and any necessary information linking the signatures to their corresponding outcome.
#### Version 0 `cet_adaptor_signatures`
1. type: 42774 (`cet_adaptor_signatures_v0`)
2. data:
* [`ecdsa_adaptor_signature`:`signature_1`]
* [`dleq_proof`:`dleq_prf_1`]
* ...
* [`ecdsa_adaptor_signature`:`signature_n`]
* [`dleq_proof`:`dleq_prf_n`]
This type should be used with [`contract_info_v0`](#version-0-contract_info) where each indexed signature in the data corresponds to the outcome of the same index. As in [`contract_info_v0`](#version-0-contract_info), the number of signatures is omitted as it can be derived from the length field of the TLV.
### The `funding_signatures` Type
This type contains signatures of the funding transaction and any necessary information linking the signatures to their inputs.
#### Version 0 `funding_signatures`
1. type: 42776 (`funding_signatures_v0`)
2. data:
* [`u16`:`num_witnesses`]
* [`u16`:`num_witness_elems_1`]
* [`num_witness_elems_1*witness_element`:`witness_elements_1`]
* ...
* [`u16`:`num_witness_elems_num_witnesses`]
* [`num_witness_elems_num_witnesses*witness_element`:`witness_elements_num_witnesses`]
3. subtype: `witness_element`
4. data:
* [`u16`:`len`]
* [`len*byte`:`witness`]
`witness` is the data for a witness element in a witness stack. An empty `witness_stack` is an error,
as every input must be Segwit. Witness elements should *not* include their length as part of the witness data.
## Authors
@@ -60,4 +171,4 @@ Nadav Kohen <nadavk25@gmail.com>
![Creative Commons License](https://i.creativecommons.org/l/by/4.0/88x31.png "License CC-BY")
<br>
This work is licensed under a [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/).
This work is licensed under a [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/).

View File

@@ -63,7 +63,7 @@ This message contains information about a node and indicates its
desire to enter into a new contract. This is the first step toward creating
the funding transaction and CETs.
1. type: ??? (`offer_dlc`)
1. type: 42778 (`offer_dlc_v0`)
2. data:
* [`byte`:`contract_flags`]
* [`chain_hash`:`chain_hash`]
@@ -154,7 +154,7 @@ acceptance of the new DLC, as well as its CET and refund transaction
signatures. This is the second step toward creating the funding transaction
and closing transactions.
1. type: ??? (`accept_dlc`)
1. type: 42780 (`accept_dlc_v0`)
2. data:
* [`32*byte`:`temporary_contract_id`]
* [`u64`:`total_collateral_satoshis`]
@@ -163,7 +163,7 @@ and closing transactions.
* [`u16`:`num_funding_inputs`]
* [`num_funding_inputs*funding_input`:`funding_inputs`]
* [`spk`:`change_spk`]
* [`cet_signatures`:`cet_signatures`]
* [`cet_adaptor_signatures`:`cet_adaptor_signatures`]
* [`signature`:`refund_signature`]
#### Requirements
@@ -173,8 +173,8 @@ The `temporary_contract_id` MUST be the SHA256 hash of the `offer_dlc` message.
The sender MUST:
- set `total_collateral_satoshis` sufficiently large so that the sum of both parties' total collaterals is at least as large as the largest payout in the `offer_dlc`'s `contract_info`.
- set `cet_signatures` to valid adaptor signatures, using its `funding_pubkey` for each CET, as defined in the [transaction specification](Transactions.md#contract-execution-transaction) and using signature public keys computed using the `offer_dlc`'s `contract_info` and `oracle_info` as adaptor points.
- include an adaptor signature in `cet_signatures` for every event specified in the `offer_dlc`'s `contract_info`.
- set `cet_adaptor_signatures` to valid adaptor signatures, using its `funding_pubkey` for each CET, as defined in the [transaction specification](Transactions.md#contract-execution-transaction) and using signature public keys computed using the `offer_dlc`'s `contract_info` and `oracle_info` as adaptor points.
- include an adaptor signature in `cet_adaptor_signatures` for every event specified in the `offer_dlc`'s `contract_info`.
- set `refund_signature` to the valid signature, using its `funding_pubkey` for the refund transaction, as defined in the [transaction specification](Transactions.md#refund-transaction).
The sender SHOULD:
@@ -186,7 +186,7 @@ The receiver:
- if `total_collateral_satoshis` is not large enough:
- MAY reject the contract.
- if `cet_signatures` or `refund_signature` fail validation:
- if `cet_adaptor_signatures` or `refund_signature` fail validation:
- MUST reject the contract.
- if `funding_inputs` do not contribute at least `total_collateral_satohis` plus [fee payment](Transactions.md#fee-payment)
- MUST reject the contract.
@@ -201,10 +201,10 @@ all closing transactions.
This message introduces the [`contract_id`](#definition-of-contract_id) to identify the contract.
1. type: ??? (`sign_dlc`)
1. type: 42782 (`sign_dlc_v0`)
2. data:
* [`contract_id`:`contract_id`]
* [`cet_signatures`:`cet_signatures`]
* [`cet_adaptor_signatures`:`cet_adaptor_signatures`]
* [`signature`:`refund_signature`]
* [`funding_signatures`:`funding_signatures`]
@@ -213,16 +213,17 @@ This message introduces the [`contract_id`](#definition-of-contract_id) to ident
The sender MUST:
- set `contract_id` by exclusive-OR of the `funding_txid` and the `funding_output_index` from the `offer_dlc` and `accept_dlc` messages.
- set `cet_signatures` to valid adaptor signatures, using its `funding_pubkey` for each CET, as defined in the [transaction specification](Transactions.md#contract-execution-transaction) and using signature public keys computed using the `offer_dlc`'s `contract_info` and `oracle_info` as adaptor points.
- include an adaptor signature in `cet_signatures` for every event specified in the `offer_dlc`'s `contract_info`.
- set `cet_adaptor_signatures` to valid adaptor signatures, using its `funding_pubkey` for each CET, as defined in the [transaction specification](Transactions.md#contract-execution-transaction) and using signature public keys computed using the `offer_dlc`'s `contract_info` and `oracle_info` as adaptor points.
- include an adaptor signature in `cet_adaptor_signatures` for every event specified in the `offer_dlc`'s `contract_info`.
- set `refund_signature` to the valid signature, using its `funding_pubkey` for the refund transaction, as defined in the [transaction specification](Transactions.md#refund-transaction).
- set `funding_signatures` to valid input signatures.
- include a signature in `funding_signatures` for every funding input specified in the `offer_dlc` message.
- set `funding_signatures` to contain valid witnesses for every funding input specified in the `offer_dlc` message and in the same order.
The recipient:
- if any `signature` is incorrect:
- if any `signature` or `witness` is incorrect:
- MUST reject the contract.
- if any witness exceeds its corresponding `max_witness_len` from the `offer_dlc` message:
- MAY reject the contract.
- MUST NOT broadcast the funding transaction before receipt of a valid `sign_dlc`.
- on receipt of a valid `sign_dlc`:
- SHOULD broadcast the funding transaction.

View File

@@ -108,6 +108,7 @@ The actual and expected weights vary for several reasons:
* Bitcoin uses DER-encoded signatures, which vary in size.
* Bitcoin also uses variable-length integers, so a large number of outputs will take 3 bytes to encode rather than 1.
* Witnesses may be less than `max_witness_len`
* The offerer output may be below the dust limit.
* The accepter output may be below the dust limit.
@@ -115,45 +116,59 @@ Thus, a simplified formula for *expected weight* is used, which assumes:
* Signatures are 72 bytes long.
* There are a small number of outputs (thus 1 byte to count them).
* All witnesses are of size `max_witness_len`
This yields the following *expected weights* (details of the computation below):
```
Funding Transaction weight: 286 + 4 * total_change_length + 272 * num_inputs
CET/Refund Transaction weight: 500 + 4 * total_output_length
Funding Transaction weight: 214 + (72 + 4*total_change_length)
+ sum(164 + 4*script_sig_len + max_witness_len)
CET/Refund Transaction weight: 498 + 4 * total_output_length
```
### Fee Payment
The funding output's value is composed of the sum of both parties' `total_collateral` (from offer/accept messages) plus the `max_fee` of closing transactions. In this way all fees are paid for in the [Funding Transaction](#funding-transaction) so that the funding output's value is inflated and the outputs of CETs and the refund transaction are the exact amounts specified in the offer message's contract information (or total collateral specified in the offer and accept messages for the refund transaction) with no fees subtracted from closing transactions.
All fees are currently paid evenly between the two parties, though this will change in a future version.
Shared fields' fees are paid evenly between the two parties, while fields that belong to a specific party (i.e. funding inputs, change outputs, CET outputs) are paid by the contributing party. Specifically, a party's funding transaction and closing transaction weights are computed as (details of computation below):
Note that if an outcome occurs in which one party's output is below the dust limit of `1000 satoshis`, then the resulting fee rate will be larger than *expected*.
```
input_weight = sum(164 + 4*script_sig_len + max_witness_len) (over party's funding inputs)
output_weight = 36 + 4*change_spk_script length
total_funding_weight = 107 + output_weight + input_weight
cet_weight = 249 + 4*payout_spk length
```
These weights must be divided by `4` (rounding up) to get vbytes after which these numbers are multiplied by the fee rate. The resulting funding fee is subtracted in value from the change output while the CET fee is added to the funding output's value and also subtracted from this party's change output.
Note that if a CET occurs in which one party's output is below the dust limit of `1000 satoshis`, then the resulting fee rate will be larger than *expected*.
### Computation of `max_witness_len`
The `max_witness_len` should be computed to be an upper bound on the byte size of all elements on the witness stack (and no other data). For example, a P2WPKH funding input should have a `max_witness_len` of `108`:
```
p2wpkh witness: 108 bytes
- number_of_witness_elements: 1 byte
- sig_length: 1 byte
- sig: 72 bytes
- pub_key_length: 1 byte
- pub_key: 33 bytes
```
## Expected Weight of the Funding Transaction
The *expected weight* of a funding transaction is calculated as follows:
```
p2wpkh: 22 bytes
- OP_0: 1 byte
- OP_DATA: 1 byte (public_key_HASH160 length)
- public_key_HASH160: 20 bytes
p2wsh: 34 bytes
- OP_0: 1 byte
- OP_DATA: 1 byte (witness_script_SHA256 length)
- witness_script_SHA256: 32 bytes
funding_input: 41 bytes
funding_input: 41 + script_sig_len bytes
- previous_out_point: 36 bytes
- hash: 32 bytes
- index: 4 bytes
- var_int: 1 byte (script_sig length)
- script_sig: 0 bytes
- witness <---- "witness" is used instead of "script_sig" for
transaction validation; however, "witness" is stored
- script_sig: script_sig_len bytes
- witness <---- "witness" is stored
separately, and the cost for its size is smaller. So,
the calculation of ordinary data is separated
from the witness data.
@@ -163,13 +178,6 @@ witness_header: 2 bytes
- flag: 1 byte
- marker: 1 byte
witness: 108 bytes
- number_of_witness_elements: 1 byte
- sig_length: 1 byte
- sig: 72 bytes
- pub_key_length: 1 byte
- pub_key: 33 bytes
change_output: 9 + change_spk_script length bytes
- value: 8 bytes
- var_int: 1 byte (pk_script length)
@@ -180,14 +188,14 @@ funding_output: 43 bytes
- var_int: 1 byte (pk_script length)
- pk_script (p2wsh): 34 bytes
funding_transaction: 71 + offer_change_spk_script length + accept_change_spk_script length + 41 * num_inputs bytes
funding_transaction: 53 + (9 + offer_change_spk_script length) + (9 + accept_change_spk_script length) + sum(41 + script_sig_len) bytes
- version: 4 bytes
- witness_header <---- part of the witness data
- count_tx_in: 1 byte
- tx_in: 41 bytes * num_inputs
funding_input
- tx_in: sum(41 + script_sig_len) bytes
funding_inputs
- count_tx_out: 1 byte
- tx_out: 61 + offer_change_spk_script length + accept_change_spk_script length
- tx_out: 43 + (9 + offer_change_spk_script length) + (9 + accept_change_spk_script length) bytes
funding_ouptut (43 bytes),
change_output (9 + offer_change_spk_script length bytes),
change_output (9 + accept_change_spk_script length bytes)
@@ -198,13 +206,19 @@ Multiplying non-witness data by 4 results in a weight of:
```
// total_change_length = offer_change_spk_script length + accept_change_spk_script length
// 284 + 4 * total_change_length + 164 * num_inputs weight
// 212 + (72 + 4*total_change_length) + sum(164 + 4*script_sig_len) weight
funding_transaction_weight = 4 * funding_transaction
// 2 + 108 * num_inputs weight
// 2 + sum(offer_max_witness_len) + sum(accept_max_witness_len) weight
witness_weight = witness_header + witness * num_inputs
overall_funding_tx_weight = 286 + 4 * total_change_length + 272 * num_inputs weight
overall_funding_tx_weight = 214 + (72 + 4*total_change_length) + sum(164 + 4*script_sig_len + max_witness_len) weight
offer_funding_tx_weight = 107 + (36 + 4*offer_change_spk_script length) + sum(164 + 4*offer_script_sig_len + offer_max_witness_len) weight
offer_funding_tx_vbytes = Ceil(offer_funding_tx_weight / 4.0) vbytes
accept_funding_tx_weight = 107 + (36 + 4*accept_change_spk_script length) + sum(164 + 4*accept_script_sig_len + accept_max_witness_len) weight
accept_funding_tx_vbytes = Ceil(accept_funding_tx_weight / 4.0) vbytes
```
## Expected Weight of the Contract Execution or Refund Transaction
@@ -238,13 +252,13 @@ witness_header: 2 bytes
- flag: 1 byte
- marker: 1 byte
witness: 222 bytes
witness: 220 bytes
- number_of_witness_elements: 1 byte
- nil_length: 1 byte
- sig_offer_length: 1 byte
- sig_offer: 73 bytes
- sig_offer: 72 bytes
- sig_accept_length: 1 byte
- sig_accept: 73 bytes
- sig_accept: 72 bytes
- witness_script_length: 1 byte
- witness_script (multi_sig): 71 bytes
@@ -278,10 +292,16 @@ Multiplying non-witness data by 4 results in a weight of:
// 276 + 4 * total_output_length weight
cet_weight = 4 * cet
// 224 weight
// 222 weight
witness_weight = witness_header + witness
overall_cet_weight = overall_refund_tx_weight = 500 + 4 * total_output_length weight
overall_cet_weight = overall_refund_tx_weight = 498 + 4 * total_output_length weight
offer_cet_weight = 249 + 4 * offer_output_script_length weight
offer_cet_vbytes = Ceil(offer_cet_weight / 4.0) vbytes
accept_cet_weight = 249 + 4 * accept_output_script_length weight
accept_cet_vbytes = Ceil(accept_cet_weight / 4.0) vbytes
```
# Test Vectors