ブロックチェーンは、ビットコインが構築される技術です。 数年前にすべての名声が暗号通貨になった場合、今日では「ビットコインを忘れて、Long Live Blockchain」のような大胆なフレーズを聞くことができます。 Ethereum、IPFS、またはOverstockなどのプラットフォームは活発に開発されており、ブロックチェーンをさらに別の支払いシステムを作成するためのツールとしてではなく、インターネットを除いてイノベーションに匹敵する完全に独立したテクノロジーと見なしています。
この章では、Bitcoinブロックチェーンのすべてについて説明します。 イーサリアムと比較しても、これはひどい時代錯誤です。しかし、より複雑なプロジェクトを扱うことに決めた場合、その動作の原理を理解することは大いに役立ちます。
本
- ビットコインの概要-暗号化
- ビットコインの概要-トランザクション
- ビットコインの概要-プロトコル
- 一言で言えばビットコイン-ブロックチェーン
- ビットコインの概要-マイニング
目次
- ダミーのブロックチェーン
- 構造
- マークルツリー
- タイムスタンプ
- 生ブロック
- リンク集
ダミーのブロックチェーン
ブロックチェーン自体は非常に単純なものです。 Bitcoinネットワーク内のすべてのトランザクションを記録する会計帳簿の例で説明するのが最も簡単です。 さらに、ネットワークの各メンバーにはそのような本があります。つまり、必要に応じて誰でもこの取引またはその取引が本物かどうかを確認できます。
また、ブロックチェーン全体が本である場合、個々のブロックは、トランザクションが「記録」されるページとして表すことができます。 各ブロックは、前のブロックを「参照」し、最初のブロック( geneis block )まで続きます。 これが、不変性などのブロックチェーンの興味深い機能を作成するものです。 誰も気付かないように、ブロック番号123を変更することはできません。 ブロックチェーンは、ブロック#124、次に#125などを最上部に変更するように設計されているためです。
構造
通常の手の動きで、プロトコル仕様を開き、ブロックの構造を調べます。
- バージョン -ブロックバージョン
- prev_block-前のブロックのハッシュ( 親ブロック )
- merkle_root-簡略化されている場合、これはブロック内のすべてのトランザクションのハッシュです
- タイムスタンプ-ブロック作成の日付と時刻
- bits 、 nonce-これらのパラメーターについては、 ビットコインの概要-マイニングの章で詳しく説明します
- txn_count 、 txns-ブロック内のトランザクションの数とそのリスト
最初の6つのパラメーター( txn_countおよびtxnsを除くすべて)は、ブロックのヘッダーを形成します。 ブロックハッシュと呼ばれるのはヘッダーハッシュです。つまり、トランザクション自体は直接ハッシュに参加しません。
代わりに、それらは特別な構造- マークルツリーに記録されます。これについては以下で説明します。
マークルツリー
技術面
マークルツリーは、バイナリハッシュツリーとも呼ばれるデータ構造です。 ビットコインの場合、次のように構築されます。
まず、
hash_A = SHA256(SHA256(A))
ブロック内のすべてのトランザクションのハッシュが考慮されます
トランザクションのハッシュの合計からのハッシュは、
hash_AB = SHA256(SHA256(hash_A + hash_B))
同様に、結果のハッシュの合計からハッシュを計算します
hash_ABCD = SHA256(SHA256(hash_AB + hash_CD))
そして再帰的に。 叙情的余談-ツリーはバイナリであるため、各ステップで偶数個の要素が存在する必要があります。 したがって、たとえば、トランザクションが3つしかない場合、最後のトランザクションは単に複製されます。
- このプロセスは、1つのハッシュが取得されるまで続きます-merkle_root (ブロックのヘッダーの 3番目のフィールド)と呼ばれます
以下は、マークルツリーの実装です。ブロックで確認できます。
import hashlib # Hash pairs of items recursively until a single value is obtained def merkle(hashList): if len(hashList) == 1: return hashList[0] newHashList = [] # Process pairs. For odd length, the last is skipped for i in range(0, len(hashList)-1, 2): newHashList.append(hash2(hashList[i], hashList[i+1])) if len(hashList) % 2 == 1: # odd, hash last item twice newHashList.append(hash2(hashList[-1], hashList[-1])) return merkle(newHashList) def hash2(a, b): # Reverse inputs before and after hashing # due to big-endian / little-endian nonsense a1 = a.decode('hex')[::-1] b1 = b.decode('hex')[::-1] h = hashlib.sha256(hashlib.sha256(a1 + b1).digest()).digest() return h[::-1].encode('hex')
不変性
さて、これがビットコインで必要な理由について。 少なくとも1つのトランザクションを変更すると、 merkle_rootも変更されることを理解していると思います。 したがって、このようなデータ構造により、ブロック内のトランザクションの「不変性」を確保できます。 つまり、次の状況は発生しません。
鉱夫の一人が新しいブロックを見つけて、ネットワーク上に散らし始めました。 この時点で、攻撃者はブロックを傍受し、たとえば、ブロックからトランザクションを削除した後、既に変更されたブロックを配布します。
確認するには、自分でmerkle_rootを計算し、ブロックのヘッダーに記述されているものと比較するだけで十分です。
SPV
しかし、ここでは、まず、そのような困難はまったく役に立たないと主張することができます。 txns_hash = SHA256(SHA256(sum(txns)))
ブロック内のすべてのトランザクションの合計からハッシュを計算するだけですtxns_hash = SHA256(SHA256(sum(txns)))
-トランザクション操作後にも変更されます。 そして第二に、ブロック内の攻撃者がmerkle_rootを置き換えることを防ぐものは何ですか? 2番目の質問にすぐにお答えします。実際、ブロックはすぐに無効になるため、ブロック内で何も変更することはできません( ビットコインの次の章-マイニングを読んだ後、これを理解できます)。
また、 SPVノードを作成できるようにするには、Merkleツリーが実際に必要です(簡易支払い検証)。 このようなノードは、トランザクション自体ではなく、ブロックヘッダーのみを同期します。 その結果、ブロックチェーンは1桁少ないスペースを取ります(美しさのために、500,000ブロックの高さを取りましょう、ヘッダーサイズは固定です-80バイト):
500.000 * 80/1024/1024≈40 Mb
そのようなブロックチェーンは、すでに携帯電話、タブレット、または何らかのIoTに簡単に適合することができます。 長い目で見れば、より多くの分散化、ネットワークセキュリティなどが得られるはずです。
単純化された支払い確認の本質は次のとおりです。SPVノードを用意します。 私はブロックチェーン全体を持っているので、何らかのトランザクションが実際にあったことを説明する必要があります(図ではトランザクションKです )。 この場合、 H_L, H_IJ, H_MNOP, H_ABCDEFGH
複数のハッシュを提供する必要があります。これらは認証パスとも呼ばれます 。
その後、最初にH_K = SHA256(SHA256(K))
をH_KL = SHA256(SHA256(H_K + H_L))
、次にH_KL = SHA256(SHA256(H_K + H_L))
をH_KL = SHA256(SHA256(H_K + H_L))
ます。 最終的に同じmerkle_rootを持つブロックを見つけた場合、トランザクションの存在の事実は確認済みと見なされます。
BTW Ralph Merkleは、特許US4309569 Aで証明されているように、彼のデータ構造の特許を取得しました。
タイムスタンプ
別の興味深い質問。 ネットワークのどこかに新しいブロックが出現し、ノードがそれを相互に転送し始めると想像してください。 各ノードは、ブロックが正しいことを確認する必要があります。 これを行うために、彼女は:
- ブロックの構文と構造をチェックします
- ブロック内の各トランザクションの有効性をチェックします
- トランザクションをハッシュし、 マークル根を比較します
- マイニングに関連するいくつかの基準などをチェックします
しかし、どうすればタイムスタンプを確認できますか? 異なるコンピューター上の時間は異なる可能性があるため、新しいタイムスタンプブロックが現在の時間と1時間進んでいても、ブロックが「間違っている」ことを意味するのではなく、鉱山労働者が急いでいるだけかもしれません。
したがって、タイムスタンプの有効性をチェックするために2つの基準が考案されました。 まず、前の11ブロックのタイムスタンプの算術平均よりも大きい必要があります。 これは、ブロック#123が2011年3月12日にリリースされ、#124-1984年2月13日にリリースされないようにするためです。しかし、同時に、いくつかのエラーが許可されます。
第二に、タイムスタンプはネットワーク調整時間よりも小さくなければなりません。 つまり、ノードは、新しいブロックを受信すると、ネットワーク上の「隣人」の現在の時間に関心を持ち、算術平均を考慮し、ブロックのタイムスタンプが結果の値+ 2時間よりも小さい場合、すべてが正常です。
ご覧のとおり、新しいブロックのタイムスタンプは、以前のブロックのタイムスタンプよりもさらに小さい場合があります。 これは珍しいことではありません。たとえば、 #145045 、 #145046 、 #145047 。
145044: 2011-09-12 15:46:39 145045: 2011-09-12 16:05:07 145046: 2011-09-12 16:00:05 // ~5 minutes before prior block 145047: 2011-09-12 15:53:36 // ~7 & ~12 minutes before 2 prior blocks 145048: 2011-09-12 16:04:06 // after 2 prior blocks but still before 145045
生ブロック
ブロックの構造についてまだ質問がある場合は、それらを未加工の形式で見ることをお勧めします。 これを行う最も明白な方法は、 bitcoind --daemon
を数時間実行してから、既にダウンロードされているブロックを調べることです。 しかし、第一に、誰もがブロックチェーンを同期する時間/欲求があるわけではありません。 第二に、ビットコインでは、ブロックは非常に特殊なLevelDBデータベースにかなり奇妙な方法で保存されます。 また、この本は経験豊富な開発者のみを対象としているわけではないので、すでに実証された方法で元の形式でプロトコルを使用します。
ブロックを受信するには、 type : MSG_BLOCK
およびhash : 000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506
type : MSG_BLOCK
を示すtype : MSG_BLOCK
メッセージを送信します-これはブロック#100.000のハッシュです。 ここでコード全体を見ることができます 。
def getdataMessage(): block_hash = '000000000003ba27aa200b1cecaad478d2b00432346c3f1f3986da1afd33e506' count = struct.pack("<B", 1) inventory = struct.pack("<L", 2) # type : MSG_BLOCK inventory += block_hash.decode('hex')[::-1] return count + inventory