アルゴリズムとかオーダーとか

仕事で勉強したことなどをまとめてます

gethのsyncingについてのソース解析メモ その2

前回の続きとして、今回は特にReceiptsの取得処理周りを見ていく。Receiptの取得処理はfast syncの時に呼ばれ、full syncでは呼ばれないというコメントがあるが、そこの動きがよくわかっていないので、該当コードがどうなっているかを解析する。

ReceiptsPacket パケット受け取ってから

ReceiptsPacketを受け取ると以下を経て、最終的にchannelに対して配信される。
https://github.com/ethereum/go-ethereum/blob/v1.10.2/eth/downloader/downloader.go#L1964-L1967
https://github.com/ethereum/go-ethereum/blob/97d11b0187b4695ccf44e3b71b54155fe405a36f/eth/downloader/downloader.go#L2000-L2022

で、この後は非同期な処理になるためコードジャンプで追えない。なので、receiptChからメッセージを受け取っている部分を探してみると、どうやら以下のあたりで処理を行っているぽい。

https://github.com/ethereum/go-ethereum/blob/97d11b0187b4695ccf44e3b71b54155fe405a36f/eth/downloader/downloader.go#L1298-L1322
で、結局戻ってくるが、どうやらこの中のd.queue.DeliverReceipts(pack.peerID, pack.receipts)が受け取ったReceiptsパケットを保存している処理っぽい。

func (d *Downloader) fetchParts について

同Downloader内のfetch処理の以下の3つから呼ばれている。

リモートピアからデータを受け取るためには、どのブロックのデータが欲しいのか?応答が正常化?タイムアウトしていないか?ユーザがキャンセルしていないか?などなどを処理しないといけない。
それらの処理を共通化しているのが、このfetchParts関数の様だ。

実際のデータパケットを受け取った時にそれをqueueにためておくのが、deliver func(dataPack) (int, error) となる。そのため、上記3つについて、それぞれこのdeliverに指定されている関数を見ていけば、具体的に何のデータを受け取って保存しているかがわかる。

が、今回はfull syncの場合にReceiptsの取得が呼ばれない仕組みを調べたいのでその部分を探す。

Receipts要求メッセージを送っている部分

Downloader#fetchReceiptsからコードを辿っていくと、Receiptsの要求メッセージを送っている部分は、以下の関数の部分となる。
https://github.com/ethereum/go-ethereum/blob/v1.10.2/eth/downloader/peer.go#L178-L196
最終的には、以下が呼ばれる。が、ここにはsyncModeによる切り替え処理は見当たらない。
https://github.com/ethereum/go-ethereum/blob/v1.10.2/eth/protocols/eth/peer.go#L500-L510


ということで、戻って、Downloader#fetchPartsの処理を詳しく見ていく。

func (d *Downloader) fetchParts のfetchReceipts処理

FetchRecipts関数はfetchPartsのfetch引数として話されている。なので、fetchが呼ばれている箇所を探すと以下となる。
https://github.com/ethereum/go-ethereum/blob/v1.10.2/eth/downloader/downloader.go#L1502
で、その少しうえで、requestがnullの場合はfetchが呼ばれてないことがわかる。
https://github.com/ethereum/go-ethereum/blob/v1.10.2/eth/downloader/downloader.go#L1490-L1492


では、そのrequestをどうやって取得しているのかというと、そのまた少しうえで、reserveから取得していることがわかる。
https://github.com/ethereum/go-ethereum/blob/v1.10.2/eth/downloader/downloader.go#L1482
また、このreserverが何者こについては、FetchReceiptsを見ると、d.queue.ReserveReceiptsであることがわかる。
https://github.com/ethereum/go-ethereum/blob/v1.10.2/eth/downloader/downloader.go#L1316-L1318

ReserveReceiptsの実態

d.queue.ReserveReceiptsからコードを追っていくと、最終的に、func (q *queue) reserveHeadersに行き着く。
で、この関数の中で*fetchRequestでnilを返している箇所を探すと以下の3つが見つかる。
https://github.com/ethereum/go-ethereum/blob/v1.10.2/eth/downloader/queue.go#L487-L489
https://github.com/ethereum/go-ethereum/blob/v1.10.2/eth/downloader/queue.go#L490-L492
https://github.com/ethereum/go-ethereum/blob/v1.10.2/eth/downloader/queue.go#L557-L559

三番目のsendについては、taskQueueのうち、以前に取得失敗した分を取り除いたリストなので、いずれにしてもtaskQueueのサイズが関係していることがわかった。このtaskQueueとはつまり、q.receiptTaskQueueのことなので、Queue#receiptTaskQueueに値を詰めている箇所を探す。

q.receiptTaskQueueにitemをpushしている箇所

receiptTaskQueueを探してみると以下の箇所が見つかった。
https://github.com/ethereum/go-ethereum/blob/97d11b0187b4695ccf44e3b71b54155fe405a36f/eth/downloader/queue.go#L320-L328
コードにある様に、syncModeがFastSyncの場合だけreceiptTaskQueueにセットしているのでここで正解っぽい。

なお、もう一つpushしている箇所が見つかったが、Revoke関数なのでここは関係ないと思う。
https://github.com/ethereum/go-ethereum/blob/v1.10.2/eth/downloader/queue.go#L618

まとめ

FastSyncの時だけ、Receiptsの取得処理が走るのは、そもそもReceiptsを要求するメッセージを送るための、receiptTaskQueueが他のモードの場合は常に空になっているから。

gethのsyncingについてのソース解析メモ その1

Ethereumのfull/fast/snap syncの違いについてより詳しく調べいたと思い、gethのソースを読み始めた。
が、なかなかにボリュームがあるのと、同期処理についてかなり複雑だったので、頭の整理のために解析中の内容をメモとして残しておく。

  • full/fast syncのプロセスについて
  • Block headerのrequest部分
  • response受け取り部分
続きを読む

Apollo Client(React)のGetting Startedを動かすまで

つい最近、社内ハッカソンでGraphQLのライブラリである、ApolloApollo Client(React版)を触ってみた。その時に、公式のGetting Startedを動かすのに少し手間取ったので、ここに手順をまとめておく。
最後に、GraphQLを触ってみたときの所感を簡単にまとめる。

公式のGetting Startedの記事は以下を参照。
www.apollographql.com

  • 環境
  • 1. Reactのインストール
  • 2. graphqlとApollo Clientのインストール
  • 3. コンソール上で実行するClientの作成
  • 4. Apollo ClientをReact Appに組み込む
  • 5. まとめ
続きを読む

StreamによるState管理のすすめ

つい最近、社内ハッカソンでFlutterを用いたアプリ開発を行いました。その時に、FlutterやReactなどにおける、State ManagementやApplication Architecture(というか設計手法?)について色々と議論しました。

その中で、Flutterでよく使われているBlocパターンと、自分が昔経験したReactive MVVMが非常に似ており、Blocパターンが採用しているStreamを用いたState管理について良さを説明してくださいといわれたけど、うまく説明できませんでした。

ということで、今回の記事ではStreamを用いたstate管理の利点をまとめたいと思います。

  • はじめに
  • アプリケーション設計の基本
  • Streamを使う利点
  • オセロゲームはその入力を受け付けるべきか?
  • ネットワーク対戦型オセロゲームでも、シングルプレイでもBusiness Logicのinputは同じ
  • その入力は同期処理?非同期処理?
  • まとめと欠点
続きを読む

truffleでminer.stopなテストの書き方

Truffleでちょっと特殊(?)なテストを書こうとしたら思ったよりもハマってしまったので、備忘録的に残しておきます。

  • miner.stopしたら動かないテスト
  • miner.stopするとsendTransactionでフリーズする理由
  • miner.stopでフリーズしないテスト
  • まとめ
続きを読む

Solidity v0.6.5で追加されたImmutable keywordについて

今回は、Solidityのv0.6.5で追加されたImmutable keywordについて紹介します。
なお、v0.6.5は2020/04/06にリリースされております。執筆時点での最新バージョンはv0.6.8となっています。

Immutable keywordについての公式の説明はこちらのブログを参照ください。
solidity.ethereum.org

  • Immutable Keywordについて
  • constantとimmutableの比較
  • immutableの動作概要
    • 基本的な流れ
    • デバッガーを使って確認してみる
    • コントラクトの初期化フェーズ時の動作
    • immutable変数を参照するときの動作
  • まとめ
続きを読む

web3.jsのmock方法

今回の記事では、DappsのUnit Testでweb3.jsをmockする方法について紹介します。
sinon.jsを用いた方法と、jestを用いた方法の2パターンを紹介します。

本記事で紹介している内容のサンプルプロジェクトも作りましたので参考にしてください。
github.com

  • テスト対象となるDapps
  • Unit Testのサンプル
  • web3.js のmocking方法
    • sinon.jsを使った方法
      • 利点
      • 欠点
    • jestを使った方法
      • 利点
      • 欠点
  • まとめ
続きを読む