TransactionBuilderを使ってみる

あなたにとって初めての P2SHマルチシグ のトランザクションに署名するときに TranasctionBuilder をどのように動かすか見てきた。

次はより複雑なトランザクションに対して署名するために、そのフルパワーをどのように活かすかを見てみよう。

TranactionBuilder を用いると以下ができるようになる。

  • 以下の支払いができる

    • P2PKP2PKH

    • マルチシグ

    • P2WPKP2WSH

  • 前章のようにredeem scriptにもとづいて、P2SH を支払いに使える

  • ステルスコイン を使える(ダークウォレット)

  • カラードコイン を発行し、移動できる(次の章で説明するオープンアセットのこと)

  • 部分的に署名されたトランザクション を結合できる

  • 署名されていないトランザクション の最終的な サイズ とそれにかかる 手数料 を計算できる

  • トランザクション十分に署名されたか を確認できる

TransactionBuilder のゴールはインプットとしての コイン を取得し、十分に または 部分的に署名されたトランザクション を生成することである。

TransactionBuilder だけで、どの コイン を使い、なにを署名すべきかを把握してくれる。

TransactionBuilderを使うためには4つのステップがある。

  • 使う コイン を集める

  • 持っている を集める

  • どの scriptPubKey に対していくら コインを 支払いたいかを数える

  • トランザクション を生成して署名する

  • オプション:誰かに トランザクション を送り、署名してもらうか生成を続けてもらう

さあ コイン を集めてみよう。まずそのコインを充足させるために見せかけの トランザクション を作ろう。 ここでは、その トランザクション には P2PKHP2PK と、ボブとアリスの マルチシグに コインがあることにしよう。

// Create a fake transaction
var bob = new Key();
var alice = new Key();
Script bobAlice =
PayToMultiSigTemplate.Instance.GenerateScriptPubKey(
2,
bob.PubKey, alice.PubKey);
var init = new Transaction();
init.Outputs.Add(new TxOut(Money.Coins(1m), bob.PubKey)); // P2PK
init.Outputs.Add(new TxOut(Money.Coins(1m), alice.PubKey.Hash)); // P2PKH
init.Outputs.Add(new TxOut(Money.Coins(1m), bobAlice));

さらにここではサトシに支払うためにこのトランザクションのcoinsを使いたいということにしよう。

var satoshi = new Key();

まずは コイン を集めなければならない。

Coin[] coins = init.Outputs.AsCoins().ToArray();
Coin bobCoin = coins[0];
Coin aliceCoin = coins[1];
Coin bobAliceCoin = coins[2];

ではbobは0.2BTC、aliceは0.3BTCを送り、さらに2人が0.5BTCを送るためにbobAliceを使うことに合意したとしよう。

var builder = new TransactionBuilder();
Transaction tx = builder
.AddCoins(bobCoin)
.AddKeys(bob)
.Send(satoshi, Money.Coins(0.2m))
.SetChange(bob)
.Then()
.AddCoins(aliceCoin)
.AddKeys(alice)
.Send(satoshi, Money.Coins(0.3m))
.SetChange(alice)
.Then()
.AddCoins(bobAliceCoin)
.AddKeys(bob, alice)
.Send(satoshi, Money.Coins(0.5m))
.SetChange(bobAlice)
.SendFees(Money.Coins(0.0001m))
.BuildTransaction(sign: true);

そしてトランザクションが十分に署名され、ネットワークに送る準備ができているかを確かめることができる。

Console.WriteLine(builder.Verify(tx)); // True

このモデルで素晴らしいのは、ScriptCoin を作る必要があることを除いて、P2SH、P2WSH、P2SH(P2WSH)とP2SH(P2PKH) に対して同じ方法で動かすことができるのだ。

init = new Transaction();
init.Outputs.Add(new TxOut(Money.Coins(1.0m), bobAlice.Hash));
coins = init.Outputs.AsCoins().ToArray();
ScriptCoin bobAliceScriptCoin = coins[0].ToScriptCoin(bobAlice);

署名はこのようにする。

builder = new TransactionBuilder();
tx = builder
.AddCoins(bobAliceScriptCoin)
.AddKeys(bob, alice)
.Send(satoshi, Money.Coins(0.9m))
.SetChange(bobAlice.Hash)
.SendFees(Money.Coins(0.0001m))
.BuildTransaction(true);
Console.WriteLine(builder.Verify(tx)); // True

ステルスコイン でも、基本的には同じだ。ただ、ダークウォレットについての紹介をもし覚えていたら、ステルスコイン を見るためには ScanKey が必要となると言ったが、それが異なる点となる。

以前の章と同じように、アリスとボブのマルチシグのステルスアドレスを作ってみよう。

Key scanKey = new Key();
BitcoinStealthAddress darkAliceBob =
new BitcoinStealthAddress
(
scanKey: scanKey.PubKey,
pubKeys: new[] { alice.PubKey, bob.PubKey },
signatureCount: 2,
bitfield: null,
network: Network.Main
);

誰かがこのトランザクションにコインを送ったとしよう。

//Someone sent to darkAliceBob
init = new Transaction();
darkAliceBob
.SendTo(init, Money.Coins(1.0m));

scanKeyを持っている人がこのステルスコインを発見できる。

//Get the stealth coin with the scanKey
StealthCoin stealthCoin
= StealthCoin.Find(init, darkAliceBob, scanKey);

それはボブとアリスに送られており、彼らが署名する。

//Spend it
tx = builder
.AddCoins(stealthCoin)
.AddKeys(bob, alice, scanKey)
.Send(satoshi, Money.Coins(0.9m))
.SetChange(bobAlice.Hash)
.SendFees(Money.Coins(0.0001m))
.BuildTransaction(true);
Console.WriteLine(builder.Verify(tx)); // True

注釈:ステルスコインを使うためにはscanKeyが必要だ。