2017年4月1日土曜日

"Programming The Blockchain in C# 日本語"のトランザクションパートで実際に送金してみた

前回に引き続きこちらのサイトで練習。

今回はサイトの情報を元に自身のハードウォレットのアドレス-今回作成したアドレス間でのBTCのやりとりを実践した。以下はそのイメージ。


以下の流れで振り返る。
コードの中に書いてある赤字は疑問点。解消された時に覚えてれば書き換える。

前準備

  • 今回ハードウォレットからBTCを受け取るアドレスの生成
       //今回取引先として使うアドレスの生成
            var network = Network.Main;
            var privateKey = new Key();
                    //単なるオブジェクト生成?
            var bitcoinPrivateKey = privateKey.GetWif(network);
            //秘密鍵生成、Wallet Important Format、ネットワーク情報を含む
            var address = bitcoinPrivateKey.GetAddress();//
            Console.WriteLine(privateKey);
            Console.WriteLine(bitcoinPrivateKey);
            //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(生成される秘密鍵)
            Console.WriteLine(address);
                    //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(秘密鍵から生成されるアドレス)
  • ネットワークはメインネットを選択
  • privateKeyオブジェクトを生成
  • privateKeyオブジェクトにネットワーク情報を含むWIFの秘密鍵を定義する
  • 秘密鍵からアドレスを生成する
  • 生成したアドレスの記録
            //先ほど作成した秘密鍵とアドレスを別の変数に定義
            var bitcoinPrivateKey1 = new BitcoinSecret
                ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
             //秘密鍵をByte文字列に変換?
            var network1 = bitcoinPrivateKey1.Network;
            var address1 = bitcoinPrivateKey1.GetAddress();
             //改めて定義する必要は秘密鍵をByte文字列に変えたからか?
            Console.WriteLine(network1);
            Console.WriteLine(address1);
  • 秘密鍵をByte文字列に変換
  • ネットワークがメインかテストか秘密鍵から判断(この変数は以降使わない)
  • 秘密鍵よりアドレスを生成
  • ハードウォレットから生成したアドレスに対して送金する
ここは各自で対応する
  • 送金によって発生したトランザクションIDを取得する

            //取引を行ったトランザクションのIDを取得
            var client = new QBitNinjaClient(network);
            var transactionId = uint256.Parse
                ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
            var transactionResponse = client.GetTransaction(transactionId).Result;
            Console.WriteLine(transactionResponse.TransactionId);
            Console.WriteLine(transactionResponse.Block.Confirmations);

  • トランザクションIDのハッシュ化
    • uintの中身はこちら
    • SipHashという衝突回避のための関数を使っているらしい
  • トランザクション情報の取得
    • どんな情報が入っているかはblockchain.infoなどからも見られる

新しいトランザクションの作成そして伝搬

  • receivedCoins、つまりUTXOを定義する
var receivedCoins = transactionResponse.ReceivedCoins;
            OutPoint outPointToSpend = null;//OutPointの空オブジェクトを作成

            foreach(var coin in receivedCoins)
            {
                if (coin.TxOut.ScriptPubKey == bitcoinPrivateKey1.ScriptPubKey)
                {
                    outPointToSpend = coin.Outpoint;
                }
            }
  • receivedCoins、つまりUTXOをトランザクションレスポンスから取得する
  • 空のアウトポイントオブジェクトを定義する
  • receivedCoins内に含まれるUTXOの数だけ繰り返し処理をする宣言
  • もしトランザクションアウトプット内のScriptPubKeyが秘密鍵に含まれるScriptPubKeyと同じかどうかの分岐処理を宣言
  • もしif文がTrueならばアウトポイントはUTXO内のアウトポイントとする
  • アウトポイントnullに対するエラー対策
//アウトポイントがnullの場合、エラー対策と認識している
            if (outPointToSpend == null)
                throw new Exception
                    ("error:どのトランザクションアウトプットもScriptPubkeyを持っていない");
            Console.WriteLine("{0}番目のアウトポイントを使いたい。",outPointToSpend.N + 1);
  • outPointToSpendがnullの場合、つまり正しいOutPointかどうかの見極めをしている
  • 新しいトランザクションインプットの作成
//トランザクションのOutPointをPrevOutとし、そのPrevOutをインプットトランザクションとする
            var transaction = new Transaction();
            transaction.Inputs.Add(new TxIn()
            {
                PrevOut = outPointToSpend
            });

  • transactionOutpointが今回作成するtransactionのPrevOutであると定義する
//BTCを自分のアドレスに送り返すためのInputトランザクションを作る
            var myAddress1 = BitcoinAddress.Create("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
            transaction.Inputs[0].ScriptSig = address1.ScriptPubKey;
            transaction.Sign(bitcoinPrivateKey1false);

  • BitcoinAddressを生成する
  • トランザクションのインプットに含めるScriptSigをアドレスとScriptPubKeyから生成する
  • トランザクションの署名欄に秘密鍵から署名を作る

  • 新しいトランザクションアウトプットの作成
//受け取ったアドレスから送ったアドレスにBTCを送り返すためのOutputsトランザクションを作成
            var myAddress = new BitcoinPubKeyAddress
                         ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
            TxOut myTxOut = new TxOut()
            {
                Value = new Money((decimal)0.0004MoneyUnit.BTC),
                ScriptPubKey = myAddress.ScriptPubKey
            };

            transaction.Outputs.Add(myTxOut);
  • 公開鍵からアドレスを生成する
  • 送金する額を指定する
  • ScriptPubKeyをアドレスから生成する
  • ここで定義したトランザクションアウトプットをアウトポイント

  • メッセージの作成
//メッセージ送信
            var message = "Thanks";
            var bytes = Encoding.UTF8.GetBytes(message);
            transaction.Outputs.Add(new TxOut()
            {
                Value = Money.Zero,
                ScriptPubKey = TxNullDataTemplate.Instance.GenerateScriptPubKey(bytes)
                      //ここでScriptPubKeyを生成する意味は??
            });
  • トランザクションに添えるメッセージを定義する
  • メッセージをバイト文字列にエンコーディングする
  • このメッセージもトランザクションアウトプットの一つとされるがBTCを含まないものとしたいので金額を0とする

  • 新しいトランザクションの伝搬


//トランザクションを伝播させる
            BroadcastResponse broadcastResponse = client.Broadcast(transaction).Result;

            if (!broadcastResponse.Success)
            {
                Console.WriteLine("ErrorCode: " + broadcastResponse.Error.ErrorCode);
                Console.WriteLine(transaction.GetHash());
                       //なんのために取得するのか?
            }

  • BroadcastResponseという型のオブジェクトを用意する。これにはクライアント(自分)からブロードキャストしたトランザクションに対する結果を含めるとする
  • もしブロードキャストが成功しない場合の条件分岐
  • エラーコードを出力する
  • トランザクションハッシュを取得する

  • まとめ
トランザクション生成からブロードキャストに到るまでの大まかな流れは理解できなかったがScriptPubKeyの使い方がところどころ不明だったのは理解が不十分なところだと思うので何かしらの復習をしよう。

0 件のコメント:

コメントを投稿