villagerHの日記

勉強したことや苦労した事などを書き綴ります

ブロックチェーンフォーク

ブロックのマイニングを完了して各ノードに伝える場合に複数のブロックが同時に認証され
同様の親ブロックを参照しているフォーク状態が発生することがある。

その場合は各ノードは一旦先に到着した方をメインとし後から到着した方をセカンダリチェーンとして記録する。

その後のブロックを積み重ねた結果、高さの大きくなった方を今後のメインとして使用していく。
これにより各ノードのズレに関しては修正されていく。


ブロックXを親とするブロックAとブロックBが到着

ブロックAが先に来たためブロックAを一旦メインとし、ブロックB側をセカンダリチェーンとして所持

X-A(メイン)
L  B(セカンダリ)

次に来たCブロックがブロックAを親ブロックとして参照していた場合そのままA側チェーンをメインとして扱う

X-A-C(メイン)
L  B(セカンダリ)

CブロックがブロックBを親ブロックとして参照していた場合B側チェーンの方がチェーンとしての長さが長くなるため、B側をメインに変更し以降はB側チェーンをメインとして扱う

X-A(セカンダリ)
L  B-C(メイン)

マークルツリー構築サンプル表示のコードで詰まった話

ビットコインとブロックチェーン

ビットコインとブロックチェーン

こちらのサンプルコードで再び詰まったので解決のお話。

サンプルコードをそのまま打ち込んでmakeしたら以下のエラーが出ました。

merkle.cpp:27:22: error: no member named 'make_serializer' in namespace 'libbitcoin'
                        auto concat = bc::make_serializer(concat_data.begin());
                                      ~~~~^
merkle.cpp:42:28: error: no member named 'encode_hex' in namespace 'libbitcoin'; did you mean 'encode_hash'?
                        std::cout << " " << bc::encode_hex(hash) << std::endl;
                                            ~~~~^~~~~~~~~~
                                                encode_hash
/usr/local/Cellar/libbitcoin/3.5.0_4/include/bitcoin/bitcoin/formats/base_16.hpp:65:20: note: 'encode_hash' declared here
BC_API std::string encode_hash(hash_digest hash);
                   ^
merkle.cpp:60:33: error: no member named 'encode_hex' in namespace 'libbitcoin'; did you mean 'encode_hash'?
        std::cout << "Result: " << bc::encode_hex(merkle_root) << std::endl;
                                   ~~~~^~~~~~~~~~
                                       encode_hash
/usr/local/Cellar/libbitcoin/3.5.0_4/include/bitcoin/bitcoin/formats/base_16.hpp:65:20: note: 'encode_hash' declared here
BC_API std::string encode_hash(hash_digest hash);

どれも定義がないよと仰ってるご様子。

encode_hexは前のサンプルでも詰まっていた箇所なのでサクッと直しましょう。
villagerh.hatenablog.com

std::cout << " " << bc::encode_hex(hash) << std::endl;
以下に変更
std::cout << " " << bc::encode_base16(hash) << std::endl;

std::cout << "Result: " << bc::encode_hex(merkle_root) << std::endl;
以下に変更
std::cout << "Result: " << bc::encode_base16(merkle_root) << std::endl;

さて問題はmake_serializerです。
単純にエラー文でぐぐってもどう変化したのかが見当たらなかったので解決法を見つけるのに苦労しました…

参考コードを見つけたので以下の形に置き換えたら通りました!

auto concat = bc::make_serializer(concat_data.begin());
変更後
auto concat = bc::serializer<decltype(concat_data.begin())>(concat_data.begin());

serializerがクラス形式に変更になったようです。
さてこのままmakeを行ってもまだエラーが出ました。

merkle.cpp:30:18: error: no member named 'iterator' in 'libbitcoin::serializer<std::__1::__wrap_iter<unsigned char *> >'
                        assert(concat.iterator() == concat_data.end());

concatの持ち方が変わったことでiteratorがなくなったようです。

解決方法はと言うと…



どう変わったのか調べる時間がなかったのでassertなのでコメントアウトして誤魔化しました^^;;

該当箇所のassertをとりあえずコメントアウトするとついにmakeが通ります。やったー!

動かしてみます。

Current merkle hash list:
 0670d2c428dc9c49b87071394d42658b5d638817f80adb80438e41a049006532
 c44075eebca1af653e1b4e4a26c34ab8d55bcda18c39998bdcc80569b91d8630

あれー?表示されたハッシュ値が本の結果と全く違う???

今回はencodeをbase16でなくhashで行うのが正解のようです。

std::cout << " " << bc::encode_base16(hash) << std::endl;
以下に変更
std::cout << " " << bc::encode_hash(hash) << std::endl;

std::cout << "Result: " << bc::encode_base16(merkle_root) << std::endl;
以下に変更
std::cout << "Result: " << bc::encode_hash(merkle_root) << std::endl;

実行結果
Current merkle hash list:
 32650049a0418e4380db0af81788635d8b65424d397170b8499cdc28c4d27006
 30861db96905c8dc8b99398ca1cd5bd5b84ac3264a4e1b3e65afa1bcee7540c4

無事に望んでいた結果が表示されました!


というか…

merkle.cpp:42:28: error: no member named 'encode_hex' in namespace 'libbitcoin'; did you mean 'encode_hash'?
                        std::cout << " " << bc::encode_hex(hash) << std::endl;

encode_hexのエラー時にencode_hashじゃないの?ってエラーで教えてくれてるのに全く無視してました;;;;

ブロックチェーン

複数のトランザクションをまとめたものをブロックと呼び、
そのブロックとブロックを繋ぎ合わせることでチェーン(鎖)となる。

ブロックの情報には前のブロックのハッシュ値を含んだ上でハッシュ化される。

ブロックに含まれる親(前のブロック)情報は必ず1つ。

ただし自分を参照する子ブロック(後のブロック)はマイニングのタイミングによっては一時的に複数個できる場合がある。
その場合も最終的にはフォークが解消される。

ブロックのハッシュ値には親のハッシュ値が含まれているため
1つずつ前のブロックをたどっていくことで最終的にすべてのブロックを参照することが可能。

仮にどこかのブロックが書き換えにあった場合、そのブロックを参照している子ブロックの参照している親ブロックに矛盾が発生してしまうため子ブロックのハッシュ値も変更させなくてはいけなくなる。
子ブロックのハッシュ値が書き換えると孫ブロックが、孫ブロックを書き換えると曾孫ブロックが…といった形で特定のブロック以降のブロックすべてを書き換える必要が出てきてしまう。
全てのブロックを書き換えるのは膨大な時間がかかり非現実的なためブロックチェーンは安全性が保たれている。

転職の思考法

いまいち頭が動いていなくて集中できない日があったのでブロックチェーン関連はお休みして別の本を読みました。

このまま今の会社にいていいのか?と一度でも思ったら読む 転職の思考法

このまま今の会社にいていいのか?と一度でも思ったら読む 転職の思考法

こちらの本です。

今すぐ転職するからといった理由ではないのですが某youtuberさんの動画でオススメされていたので試しに読んでみました。
そのyoutuberさんの動画を開いたのも偶然だったために本当に偶然の偶然出会った感じです。

読んでみた感想ですがすごく良かったです。

内容は闇雲に転職活動するのでなく、どういう見方をし、転職先の企業を絞っていくとより良い会社に出会えるのか。
といった感じのおそらくよくあると思われる内容です。(転職関連の本を読んだのがこれが初めてだったため比較はできません…)

とにかく個人的に絶賛している部分としては非常に読みやすかったという部分です。

内容を説明するために架空の人物を登場させ物語形式で説明が進んでいきます。

わかりやすく説明するために例題として状況を説明したりすることは他の本でもよく見かけますが、
この本は最初の説明と最後のあとがき部分以外は全て物語で進行していきます。

なので小説を読んでいるような感じでスラスラと読めていきます。
ストーリーも意外と面白く、息抜きに読み始めた私は結局一晩で最後まで読み切ってしまいました。


お値段もそんなに高くありませんし個人的にすごくオススメの一冊です。

script

ビットコインクライアントはscriptを実行することでトランザクションの有効性をチェックしている。

scriptにはlocking scriptとunlocking scriptの2つがありその二つを実行し成功することで有効とみなされる。

scriptはScript言語でかかれており、このScript言語は最低限の処理しかできないことでセキュリティを保っている。

トランザクション手数料

関連
villagerh.hatenablog.com


トランザクションには送信者、受信者へのアウトプット(支払い料金とお釣り)とは別にトランザクション手数料が含まれている。

手数料はトランザクションをマイニングするマイナーへ報酬として支払われることとなる。
villagerh.hatenablog.com

手数料は
インプット - アウトプット
の差分として求められるため注意が必要。

1bitcoinの支払いに10bitcoinのインプットを使用した場合に9bitのお釣りとして自身へのアウトプットを記載し忘れてしまうと10 - 1 が手数料として認識されてしまう。


手数料の額はトランザクションのサイズによって決められている。
サイズはインプットやアウトプットの数が多くなればなるほど大きくなる。

イメージ
8000円のものを買うのに10000円札1枚で買うのと、100円玉800枚で買う場合の手間賃。

マイニング

マイニングとは
いくつかのトランザクションをブロックとして1つの塊にし、既にあるブロック同士の繋がり(ブロックチェーン)に新たにブロックを追加するために行う作業の1つ。

チェーンに追加するためにブロックのハッシュ値は決められたルール(頭N文字が0で始まる等)で生成されている必要がある。
任意の文字列をブロックの一部に追加することでハッシュ関数でハッシュ化した時のハッシュ値を変化させて決められたルールに乗っとったハッシュ値を見つけ出す作業をマイニングという。

およそ5分に1度の頻度で開催されており、開始と同時に世界中のマイナーがハッシュ値を探し始める。
マイニングに成功した最初の1人のみが報酬を受け取ることができる。

bitcoin等のメジャーな仮想通貨では既に多くのマイナーが参戦していることと
マシンスペックを上げるため専用のPCを組む必要がある、消費電力が膨大なため電気代が大量にかかる等の理由で個人での参戦は既に難しくなっている。