DLCのTransaction

# はじめに

Discreet Log Contracts（以下、DLC）は、Bitcoinにおける未来予測市場で使う事の出来る技術です。
2017年8月にTadgeによって発表されました、DLCはLightningとほぼ同じ仕組みで動きます。

https://adiabat.github.io/dlc.pdf

最近、Lightningが実用化されつつあり、ワークショップなども開催されているようです。
Lightningを理解していれば案外簡単に利用する事が可能であると思います。
ここでは、実際に使用可能なDLCのTransactionについて説明します。
また、実際にregtest環境で演習できるようにしてあります。

# 簡単な概要

アクターは、大きくユーザ（User）とオラクル（Oracle）が必要です。
ユーザ（User）は、アリス（Alice）とボブ（Bob）とします。
オラクル（Oracle）は、オリビア（Olivia）とします。

これらの、ユーザ同士のマッチングはすでにできているものとします。
（ただし、お互いの素性を知る必要はありません。）

オラクル（Oracle）はメッセージから契約Rポイント（Committed R-point）を計算可能にする為、オラクル自身の公開鍵（楕円曲線の点）と、未来の契約に対するナンス（Nonce、楕円曲線の点）を公開しています。
※：ナンスは、契約毎に異なる必要があります。

アリスとボブは、未来のメッセージに対して契約を行います。
ファンド（Fund Transaction）から、契約実行取引（Contract Execution Transactions , CET）をメッセージ数分作成して、それらの署名をお互いに交換します。
（CETは、アリスとボブとで非対称なTransactionになります。）

未来のメッセージが確定したら、オラクル（Oracle）が確定したメッセージに対して署名値を公開します。
アリスとボブのどちらかが、その署名値を使用して、メッセージに対応した契約実行取引（CET）を送信します。
さらに、契約実行取引（CET）から自身のアドレス（P2WPKH）に送って完了となります。

# 契約例（DLC Sample）

ここでの例として、オラクルは未来（N日後）の天気について、晴（Fine）か雨（Rain）に署名して公開します。
アリスとボブは、お互い`1BTC`づつ出しあい、晴（Fine）であればアリスが`1.5BTC`ボブが`0.5BTC`
雨（Rain）であれば、アリスが`0.5BTC`ボブが`1.5BTC`とする契約を結ぶ事とします。

# オラクル（Oracle）

オラクル（Oracle）は、公開鍵（自身の公開鍵と未来に対する公開鍵の２つ以上）を公開し
未来のメッセージが確定したら、署名値を公開します。
各ユーザは、公開されている公開鍵から各メッセージに対するナンスを計算します。

```math
\begin{align*}
P_o = x_oG & \quad \text{: Oracleの公開鍵} \\
R_n = k_nG & \quad \text{: 未来のナンス} \\
\{ m_{\text{Fine}} , m_{\text{Rain}} \} & \quad \text{: メッセージ}\\
\end{align*}
```

## 契約Rポイント（Committed R-point）の求め方

オラクルが公開している情報から、ユーザ（アリスとボブ）が作成し、契約に利用します

```math
\begin{align*}
& R_{\text{Fine}} =R_n + h(R_n\ ||\ m_{\text{Fine}})P_o \\
& R_{\text{Rain}} =R_n + h(R_n\ ||\ m_{\text{Rain}})P_o \\
\end{align*}
```

## 署名値の求め方

未来のメッセージが確定したら、以下のどちらかの署名値を計算して公開します。
(晴であれば上、雨であれば下、一方のみ公開）

```math
\begin{align*}
& s_{\text{Fine}} =k_n + h(R_n\ ||\ m_{\text{Fine}})x_o \\
& s_{\text{Rain}} =k_n + h(R_n\ ||\ m_{\text{Rain}})x_o \\
\end{align*}
```

# DLCの手順

アリスとボブの公開鍵を以下とします。

```math
\begin{align*}
P_a = x_aG & \quad \text{: アリスの秘密鍵と公開鍵} \\
P_b = x_bG & \quad \text{: ボブの秘密鍵と公開鍵} \\
\end{align*}
```


## ファンド

アリスとボブはファンドを作成します。
BitcoinのTransactionは以下のとおりです。
このTransactionは、署名値を設定する前に`txid`が決定されなければならないので、
`Inputs`に設定される`UTXO`はすべて、Segwitアドレスである必要があります。

```text:Fund_Transaction
Version  0x02000000
Inputs   <Alice's UTXO 1>
         <Alice's UTXO : (option)>
         <Alice's UTXO n (option)>}
         <Bob's UTXO 1>
         <Bob's UTXO : (option)>
         <Bob's UTXO m (option)>
Outputs  <Fund Script (P2WSH)>
         <Alice's change (P2WPKH : option)>
         <Bob's change (P2WPKH : option)>
Locktime 0x00000000
```

FundのScriptは以下のとおりです。

```text:Fund_Script
OP_2
  <Alice's public key>
  <Bob's public key>
OP_2
OP_CHECKMULTISIG
```

## 契約実行取引（Contract Execution Transactions , CET）

アリスとボブは、メッセージ分の署名値を作成しお互いに交換します。
今回の例だと、２つの署名値を交換します。
ここで、オリビアが公開している値から算出した契約Rポイントを使用します。

### アリスが署名し、署名値をボブに渡す為のTransaction

#### メッセージ：晴（アリス⇒ボブ）

```text:Contract_Execution_Transactions
Version  0x02000000
Input    <Fund Output (Fund Transaction : 0)>
Outputs  <CET Script (P2WSH)>                : 0.5 BTC
         <Alice's public key (P2WPKH)>       : 1.5 BTC
Locktime 0x00000000
```

```text:CET_Script
OP_1
OP_EQUAL
OP_IF
  <Bob's public key> + <R_{Fine}>
OP_ELSE
  144(Delay)
  OP_CHECKSEQUENCEVERIFY
  OP_DROP
  <Alice's public key>
OP_ENDIF
OP_CHECKSIG
```

#### メッセージ：雨（アリス⇒ボブ）

```text:Contract_Execution_Transactions
Version  0x02000000
Input    <Fund Output (Fund Transaction : 0)>
Outputs  <CET Script (P2WSH)>                : 1.5 BTC
         <Alice's public key (P2WPKH)>       : 0.5 BTC
Locktime 0x00000000
```

```text:CET_Script
OP_1
OP_EQUAL
OP_IF
  <Bob's public key> + <R_{Rain}>
OP_ELSE
  144(Delay)
  OP_CHECKSEQUENCEVERIFY
  OP_DROP
  <Alice's public key>
OP_ENDIF
OP_CHECKSIG
```

### ボブが署名し、署名値をボブに渡す為のTransaction

#### メッセージ：晴（ボブ⇒アリス）

```text:Contract_Execution_Transactions
Version  0x02000000
Input    <Fund Output (Fund Transaction : 0)>
Outputs  <CET Script (P2WSH)>                : 0.5 BTC
         <Bob's public key (P2WPKH)>         : 1.5 BTC
Locktime 0x00000000
```

```text:CET_Script
OP_1
OP_EQUAL
OP_IF
  <Alice's public key> + <R_{Fine}>
OP_ELSE
  144(Delay)
  OP_CHECKSEQUENCEVERIFY
  OP_DROP
  <Bob's public key>
OP_ENDIF
OP_CHECKSIG
```

#### メッセージ：雨（ボブ⇒アリス）

```text:Contract_Execution_Transactions
Version  0x02000000
Input    <Fund Output (Fund Transaction : 0)>
Outputs  <CET Script (P2WSH)>                : 1.5 BTC
         <Bob's public key (P2WPKH)>         : 0.5 BTC
Locktime 0x00000000
```

```text:CET_Script
OP_1
OP_EQUAL
OP_IF
  <Alice's public key> + <R_{Rain}>
OP_ELSE
  144(Delay)
  OP_CHECKSEQUENCEVERIFY
  OP_DROP
  <Bob's public key>
OP_ENDIF
OP_CHECKSIG
```

## 契約実行（Contract Execution）

未来のメッセージが晴（Fine）であったとします。
また、アリスが契約を実行する事とします。
アリスが送信するCETは以下のとおりです。

```text:Contract_Execution_Transactions
Version  0x02000000
Input    <Fund Output (Fund Transaction : 0)>
Outputs  <CET Script (P2WSH)>                : 0.5 BTC
         <Bob's public key (P2WPKH)>         : 1.5 BTC
Locktime 0x00000000
```

```text:CET_Script
OP_1
OP_EQUAL
OP_IF
  <Alice's public key> + <R_{Fine}>
OP_ELSE
  144(Delay)
  OP_CHECKSEQUENCEVERIFY
  OP_DROP
  <Bob's public key>
OP_ENDIF
OP_CHECKSIG
```

不正防止用にScriptが組まれているので、遅延（Delay）時間以内（ここでは、144ブロック）に
自身のアドレスに送る必要があります。

```text:Settlement_Transactions
Version  0x02000000
Input    <CET Output (Contract Execution Transactions : 0)>
Outputs  <Alice's public key (P2WPKH)>                      : 1.5-fee BTC
Locktime 0x00000000
```

合成された公開鍵に対応する、秘密鍵は秘密鍵の和で求めます。
したがって、ここでの秘密鍵は以下となります。

```math
\begin{align*}
x_{a+Fine} = x_a + s_{Fine}
\end{align*}
```

これによって、計算した署名値（`<signature>`）を使用して`witness`を設定します。

```text:witnesses
witness[0] <signature>
witness[1] 01
witness[2] <CET Script>
```

署名値は、合成された秘密鍵を使うので、遅延（Delay）はあまり重要ではありません。
決済取引（Settlement Transactions）が送信するまでの時間が稼げれば良いのです。


# 演習（Exercise）

Bitcoinをregtestで起動します。

```shell
bitcoind -regtest -printtoconsole
```

Transactionを作成する為に、[DLC Transaction](https://tnakagawa.github.io/education/dlctran/index.html)をブラウザで開いてください。

はじめてregtestで起動する場合、CSVを有効にする為、432ブロック進めてください。

```shell
bitcoin-cli -regtest generate 432
```

## ファンド

ファンドの`Input`は全てSegwitアドレスである必要がある為、「Preparation」のコマンドを実行してください。
`sendtoaddress`コマンドにより、txidが２つ出てくるので、voutがどちらか調べます。

```shell
bitcoin-cli -regtest getrawtransaction <txid of Alice> 1
bitcoin-cli -regtest getrawtransaction <txid of Bob> 1
```

txidの順番どおり、Alice、BobのUTXOとなります。
「UTXOs of Alice and Bob」に、`txid`と`idx`を設定します。

「ファンド作成」⇒「契約実行取引の署名交換」⇒「ファンド送信」の流れになります。

「Fund Transaction (with signature)」の`hexstring`は署名がついていますので確認してみてください。

```shell
bitcoin-cli -regtest decoderawtransaction <hexstring>
```

`outputs`の0番目にファンドの出力があります。
ファンドを送信します。

```shell
bitcoin-cli -regtest sendrawtransaction <hexstring>
bitcoin-cli -regtest generate 1
```

送信ができたら、`txid`が出力されます。
※：エラーが出る場合は、UTXOsの設定が間違っている可能性があるのでもう一度確認してみて下さい。

これがブロックに入ったら契約完了となり、Oliviaが署名値を出すまで待つ事になります。
AliceとBobのどちらがCETを送るか、またメッセージは、晴（Fine）と雨（Rain）のどっちであるかを選択します。
CETの`hexstring`がありますので、確認してみてください。

```shell
bitcoin-cli -regtest decoderawtransaction <hexstring>
```

`outputs`の0番目が「witness_v0_scripthash」、1番目が「witness_v0_keyhash」となります。
1番目は、相手側のアドレスになっています。
`inputs`はファンドだけですが、`txinwitness`の最後はScriptなので内容を確認してみます。
2-of-2のMultisigである事がわかります。

```shell
bitcoin-cli -regtest decodescript <hexstring of script>
```

CETを送信します。

```shell
bitcoin-cli -regtest sendrawtransaction <hexstring>
bitcoin-cli -regtest generate 1
```

次に、CETから自身のWallet送信します。


```shell
bitcoin-cli -regtest decoderawtransaction <hexstring>
```

`outputs`の0番目が「witness_v0_keyhash」で、自身側のアドレスになっています。
`inputs`はCETだけです、`txinwitness`の最後はScriptなので内容を確認してみます。
CET Scriptである事がわかります。

```shell
bitcoin-cli -regtest decodescript <hexstring of script>
```

送信します。

```shell
bitcoin-cli -regtest sendrawtransaction <hexstring>
bitcoin-cli -regtest generate 1
```

これで、DLCが完了します。

# 最後に

基本的なTransactionはこれで終わりですが、実際はOracleと連絡がとれなくなった場合を考慮して、ファンドからお互いに払戻（Refund）トランザクションが必要になります。
払戻トランザクションは、ファンドからお互いに払戻すトランザクションですが、`LockTime`をOracleが公表する時間より十分後に設定する必要があります。