メイン画像

Bitcoin ネットワークの参加とピア接続について

Bitcoin ネットワークの参加とピア接続について


この記事では、Bitcoin におけるネットワークへの参加方法とピア接続する仕組みについてまとめていく。(※この記事は bitcoind version 0.9.3 に基づいているため、最新バージョンとは挙動がことなるところがある)

Bitcoin におけるネットワークへ参加方法

ピアの見つけ方

  • DNS シードを使う
    DNS シードとは、Bitcoin ノードの IP アドレスリストを提供する DNS コンテンツサーバのこと。DNS シードは Bitcoin のコミュニティメンバーが管理しており、動的 DNS シードや静的 DNS シードを提供している。動的 DNS シードとは、自動的にクローラ等で集められたアクティブなノードらのリストの中からランダムに選んでクライアントに返すタイプのものである。静的 DNS ノードは手動でノードリストを更新するものである。どちらの場合でも、クライアントがデフォルトのポート番号(Mainnet:8333, Testnet:18333)を用いて DNS シードに接続した後、DNS シードはそのクライアントをノードリストに追加しておく。(しかし、DNS シードの結果は認証されたものではなく、悪意のあるシード管理者や中間者攻撃によって攻撃者らが制御しているノードの IP アドレスリストのみを返すことができる。従って、DNS シードのみを独占的に頼るべきではないとされている。)
  • ADDR メッセージを使う
    ADDR メッセージは最大 1000 個の IP アドレスとそれらのタイムスタンプを含んでおり、ピアからネットワーク情報を得る時に使用される。このメッセージを使って参加する時は、ハードコーディングされた信頼できる IP アドレスのリストから接続先ピアをランダムに選んで接続要求を出す。
  • IRC を使う
    2020 年時点ではすでに使われていない。

上記の3つがネットワークに参加する際に使われる(使われていた)方法である。しかし、初めてネットワークに参加する場合に限っては DNS シードを使用するケースが多い。

DNS シードについて

  • seed.bitcoin.sipa.be
  • dnsseed.bluematt.me
  • dnsseed.bitcoin.dashjr.org
  • seed.bitcoinstats.com
  • seed.bitcoin.jonasschnelli.ch
  • seed.btc.petertodd.org
  • seed.bitcoin.sprovoost.nl
  • dnsseed.emzy.de

メッセージタイプについて

  • VERACK メッセージ
    VERSION メッセージが受け取られたらその返信として送られるメッセージ。これはコマンド文字列の “verack” を含むメッセージヘッダーのみで構成されている。
  • ADDR メッセージ
    ネットワーク上の自分の知っているノードに関する情報を提供するためのメッセージ。広告されてこないノードは3時間後には忘れられる必要がある。ADDR メッセージは最大 1000 個の IP アドレスとそれらのタイムスタンプを含んでいる。ノードが ADDR メッセージを送るのは2つのパターンがある。1つ目は、自分のアドレスを入れた ADDR メッセージを定期的に各ピアに送る場合。定期的に自分の情報を広告することで、ネットワーク内で知られた存在を維持することができる。2つ目は、10 アドレス以下の ADDR メッセージを受け取ったノードはが、そのメッセージをランダムに選ばれた2つの接続ピアに中継する場合である。

ネットワーク情報の伝搬

ノード間の接続は TCP 上で行われており、パブリック IP のみ保存し伝搬させる。そのピアがパブリック IP かどうかは、IP パケットと Bitcoin の VERSION メッセージを比較することで確認できる。この章では、ノードがどのようにネットワーク情報を保存し伝搬しているかについて解説する。

ネットワーク情報は DNS シードと ADDR メッセージを通して Bitcoin ネットワークを伝搬する。DNS シードにクエリを送るのは2パターンある。1つ目は、新しいノードがネットワークに初めて参加する時である。そのノードはアクティブなノードのリストを DNS シードから得る。それ以外の場合は、約 600 の IP アドレスがハードコーディングされたリストにフェイルオーバーする。2つ目は、既存のノードがオフラインの状態からネットワークに復帰し新しいピアと再接続をしたい時である。ここで、DNS シードはそのノードが接続の確立を試みてから 11 秒が経過し、2つ未満の外部接続を持っている場合のみクエリされる。

ネットワーク情報の保存

# SK = random value chosen when node is born
# IP = the peer's IP address and port number
# Group = the peer's group
i = Hash(SK, IP) % 4
Bucket = Hash(SK, Group, i) % 64
return Bucket

あるノードがあるピアに接続が成功した場合、そのピアのアドレスは適切な tried バケットに挿入される。もしそのバケットが満杯の場合、bitcoin eviction が使用され、4つのアドレスをそのバケットからランダムに選び、tried テーブルから最も古いピアを新しいピアに置き換えて、new テーブルに挿入する。そのピアのアドレスがすでにバケットに入っている場合、そのピアの IP アドレスに関連したタイムスタンプを更新する。タイムスタンプはアクティブに接続されたいるピアが VERSION, ADDR, INVENTORY, GETDATA, PING メッセージを送った時や最後の更新から 20 分以上経過した場合にも更新される。

new テーブルは 256 個のバケットでできており、それぞれにノードがまだ正常な接続を開始していないピアの最大64個のアドレスを保持できます。ノードは DNS シードもしくは ADDR メッセージから情報を得たことによって new テーブルに現れる。new テーブルに挿入されたすべてのアドレス aa はそのアドレスの group と、接続されたピアの IP アドレスもしくはアドレス aa を教えてくれた DNS シードが含まれているグループ(source group)に属しているところに挿入される。バケットは以下のように選ばれる。

# SK = random value chosen when node is born
# Group = /16 containing IP to be inserted
# Src_Group = /16 containing IP of peer sending IP
i = Hash(Sk, Src_Group, Group) % 32
Bucket = Hash(SK, Src_Group, i) % 256
return Bucket

各(group, source group)ペアは各 group が new テーブルに最大 32 個のバケットを選びながら、単一の new バケットにハッシュする。各バケットは一意のアドレスを持つ。もしバケットが満杯の場合、isTerrable と呼ばれる関数がバケット内のすべての 64 個のアドレスに対して実行される。もし、アドレスが terrible な場合(30 日以上たっている、もしくは接続失敗が多すぎた)、その時にそのアドレスは取り除く。そうでなければ bitcoin eviction を実行し、そのアドレスが破棄される小さな変更で済む。

接続ピアの選択

(1). tried, new どちらのテーブルから新しいピアを選択するか決定する。以下の式が tried から選ぶ確率である。ρ は tried と new テーブルに入ったアドレスの数の比率である。

(2). より新しいタイムスタンプに偏ってテーブルからアドレスを選択する。(i)そのテーブルから空でないバケットをランダムに選ぶ。(ii)そのバケットからピックアップする位置をランダムに選ぶ。もしその位置にアドレスが存在していればそのアドレスを以下の確率で返す。

そうでなければ、そのアドレスを拒否し(i)に戻る。受理確率 p(r,τ) は r と τ の関数であり、r は拒否されたアドレスの数を表し、τ はアドレスのタイムスタンプと現在の時間との違い(10分ごとに計測する)を示している。

(3). アドレスに接続する。接続に失敗したら(1)に戻りやり直し。

まとめ

今回は Bitcoin ノードがどのようにネットワークに参加するか、どのように接続相手を選択しているかについてまとめた。この記事では bitcoind version 0.9.3 に基づいて書いているが、Eclipse Attack の影響緩和のため現在のバージョンでは一部が変更されているはずである。Eclipse Attack についての記事と、その後の変更点については次回以降の記事でまとめる。


アカウントを作成 して、もっと沢山の記事を読みませんか?


この記事が気に入ったら しゅま さんを応援しませんか?
メッセージを添えてチップを送ることができます。


この記事にコメントをしてみませんか?


はじめまして、しゅまです。気ままに記事を投稿していきたいと思います。
・Python
・ブロックチェーン
・ゲーム関連