Blockchain in Go のメモ

by mmyoji

5 min read

Blockchain いい加減ちゃんと勉強しとくかということで、以前ちらっと目に入った Building Blockchain in Go. Part 1: Basic Prototype · Going the distance をやった。

前提知識

これをいきなりやったわけではなく、 Blockchain に関してはいくつか記事を読んだ。

最低限仕入れた知識としては、

  • BTC の文脈で言う Blockchain の Block は transaction 情報及び、その前の transaction の Hash 値を持ったもの
  • それが取引毎に連なっていく
  • 1つの取引を改竄した場合、それに連なる Block すべての Hash 値が変わっていくため不正がしづらい

ぐらい。非常にシンプル。

Proof of Work という単語が出たがあまりわかってない。

あと Blockchain の用途としては、 Bitcoin の transaction 以外にも、 identification などに使えそうってくらい。

食品の流通経路を Blockchain で管理・公開して安全性を保証したり、絵画が偽物じゃないことを保証したり。

詳しくは ブロックチェーンを応用した革新的サービス13選 | Tech2GO を。

以下先に挙げた記事に関するメモを残しておく。

Part1

Block, Blockchain 構造体の定義。

実際はもっと複雑な struct だけど、ここでは話を単純にするためにシンプルにしておくよ、とのこと。

Block

  • Timestamp: Block が生成された時点の timestamp
  • Data: BTC だとここに Transaction 情報が入ったりする。BTC に限定しているわけではないので雑に Data となっている。
  • PrevBlockHash: 前の Block の Hash 値
  • Hash: 自 Block の Hash 値。 Timestamp, Data, PrevBlockHash すべてを使って Hash 値を出す

Blockchain

単に Block の(ポインタの)配列。 Golang だと配列は ordered になっているのでとりあえず配列にしてる。

初期 Block は GenesisBlock と呼ぶらしい。 PrevBlockHash は当然持たない。

Part2

Proof-of-Work

adding new blocks is a hard work

新しい Block を追加するには新しい Hash を探す必要がある。それがマシンパワーを使って大変。

これが Work

Proof 自体は簡単

ここでの説明は抽象的過ぎてよくわからなかった。

ビットコインのProof of Workシステムとは何か - Genx Notes

【基礎】ビットコイン(bitcoin)のProof of Work(プルーフオブワーク)をわかりやすく解説 | moblock

ここらへんを読むともう少しわかるかも。

新しいブロック追加にはコストがかかり、これによって不正を防ぐ。というのが大事らしい

上記リンクには PoW の欠点など(51%問題)も書かれているがここでは省略する。

Hashcash

Hash 値を求める方法、っていう理解

特定のデータ + counter (初期値は 0) の組み合わせの Hash 値を計算して、それが条件に合うまで counter を increment -> Hash 値計算をしていく

条件の例としては「 Hash 値の最初の 20bits が0」のようなもの。

Bitcoin (もしくは Blockchain) の文脈では counternonce と呼ぶみたい。

Implementation

サンプルコード実行はそこそこ時間がかかって(多分10~15分くらい)、「これが PoW か...」と少し実感できた。

Part3

データの永続化と CLI 実装について

実際は分散システムだが、今回も単純化のためにそこは省略

Database Choice

なんでもいいけど、 Bitcoin では LevelDB が使われてる。

今回は Go で書かれてることもあり、 BoltDB を使う。

雑に説明すると BoltDB は Go 製でサーバーを起動する必要ない、最小限の機能を備えた KVS

昔ちょこっと試してみたことあるけど、割とよさげだった。詳しくは GitHub を見て

BoltDB の key と value はただの []byte なので、 encoding/gob で Go の構造体を serialize して格納する。

今回は gob 使うけど、別に JSON, XML, Protocol Buffer でもいいよ、とのこと

Database Structure

Bitconin Core では 2 つの buckets が使われてる

  1. blocks chain 内のすべての block の metadata
  2. chainstate 文字通り

Bitconin Core だとさらに各 bucket 毎に色々な rule で key-value を保存しているが、ここでも簡略化してある

Part4

Transaction について

Bitcoin Transaction

複数の入力、複数の出力がある。

入力は前の Transaction の出力。出力は「どこにコインが格納されるか」

Implmentation

この part では、誰から誰にいくら送ったかを記録できる transaction を実装した。

送金元や送金先 (address) はただの string で人の名前を直接指定するだけ。

1 Block に対して 1 transaction しか持てない実装

Part5

先の cheap な address ではなく、実際に bitcoin に実装されてるような address を実装してゆく〜

  • address は公開されている
  • identity は公開鍵 public key(pub-key) と秘密鍵 private key(prv-key) のペア
  • pub-key は human-readable な形で表示される
  • この鍵(実際は private key の方)に物理的に?アクセスされない限りは自分の coin が利用されることはない
  • prv-key で署名をして、 pub-key で検証をする
    • 署名するには「署名のためのデータ」「prv-key」が
    • 検証には「署名されたデータ」「署名」「pub-key」が必要
  • 生成された署名は Transaction の input に格納される
  • 署名は暗号ではないので、署名から元のデータを生成することはできない
    • 可逆暗号ではないってことかな?
  • Block に入る前に Transaction の検証が走る
    • TXInput が前の TXOutput を使う権限があるかどうか
    • 署名が正しいかどうか

Elliptic Curve Cryptography

他人の prv-key をたまたま生成できる、なんてことがあってはいけないので Bitcoin では prv-key の生成に Elliptic Curve というアルゴリズムを使っている。

詳細は省略

Bitcoin では transaction の署名に ECDSA(Elliptic Curve Digital Signature Algorithm) ってやつを使ってるらしい。

Base58

pub-key を human-readable にするために Base58 を使ってる。

アルゴリズム自体は Base64 に似てるけど、より短い?アルファベットしか使ってない。

紛らわしい 0, o, i, l なんかは使ってない。 + や / も使ってない

Bitcoin address 生成自体はもうすこし複雑。詳細はもとの記事を見ろ

Impl

  • Wallet 構造体は PublicKey と PrivateKey を持つ
  • prv-key -> pub-key の順に生成される
  • address の生成は複雑(ということだけ覚えておけばいいでしょ)
  • ここらへんの値を使って TXInput, TXOutput あたりを修正
  • ScriptPubKey -> PubKeyHash
  • ScriptSig -> Signature, PubKey

blog にはほんの一部しかコードが書いてないため、基本的に GitHub から写経するしかなく、結構つらかった。

Impl part が2つに分かれているが、 GitHub だけだとどこまで実装すれば前半パートが達成されるか把握しづらく結局ほぼすべて写経した

結構作業なので、概念理解だけでいいなら写経はしなくてもよさそう

Part6~

ここまでやって、 Bitcoin Core の話が頻繁に出てきて、当初の目的(Blockchain の理解をする)から少し逸れている感じがしてきたのでやめる。

決して写経がめんどくさくなったわけではない。本質厨なので

まとめ

写経しなくてよかったかも