CasperFFG PR コードリーティング

CasperFFGのPRがで始めたので、ソースを読んでその知見をためていくチケットです。

最初に読むPRはこれ。

3 Likes

最初に読むべきはこっちか。

1 Like

そのethereum/casperのsimple_casper.v.pyですね。
validator_guide.mdとEIP1011を読むと世界観は掴みやすいです。
基本的には, Casper Contractが, ContractのあるNodeのブロックがfinalizeされたかどうかの情報を持っていて, gethとかparityのマイナーが, 都度そのContractに問い合わせてForkを選択する感じです。

1 Like

Parity


現状のValidator実装

CppEthereumに立ったCasperFFG impl issue

1 Like

を読んだ。ざっと流し読みした感じvote専用のtransactionを定義して、それの扱いについて整理しただけのPRっぽい。
vote処理とか自体は特にやってないっぽい。ただ、voteのtxとそれ以外のtxを分けて処理する様にしてるだけっぽい。
まぁFFGのvotingの実態はContractに実装されるので納得。
あと、気になったのはisVoteTxの識別がtx.from.isNullSenderなこと。
NullSenderAddr = 0xffffffffffffffffffffffffffffffffffffffff
なので、これだと投票者のETH保有量がわからないんじゃ。。。。?

投票者の識別はdepositするときのvalidation_addrにおいてあるvalidation contractとsignatureとvalidator_indexで識別するので問題ないですね。contractのvalidators変数に
この辺はvote txの内容を調べてくとわかります。


一切msg.senderとかで判別しないんですよね。。。
NullSenderなのは, voteするのにgasがかかりすぎてだれもvoteしなくなると困るからって話でした。
ただまだその辺は決まりきってなくて, spamが大量にくるからNullSenderやめたいって話も。

2 Likes

先にこれ読むべし。

このスライドでは主にvoteメソッドとそこにおける新たなコントラクトの考え方と, 一見難解に見えるraw_callまわりくらいしか言及できてないので, depositとslash, dynastyあたりをちゃんと読んでいきたいので, 暇を見つけて読みます。

validatorはdepositした時に、署名検証のみを持ったcontractをあらかじめdeployしといてそのaddressを渡す。
リンクをはっつけた関数ではそのcontractを使って署名検証を行っている。
なお、検証用のコードはserpentで書かれていて、pure function contractという検証の処理しかしもっていないcontractになっている。

ちなみに、Solidityでこれを実現しようとするとfunction idが必ず必要になるのでなんらかの工夫をしないといけない。。。。。

という内容は公式(?)のドキュメントのここに書いてた。

highest_justified_epoch
highest_finalized_epoch

Helper methods for client fork choice
って有るけど、なんでこのメソッドでfork choiceの参考になるのかわからない。
そもそもとして client fork choiceの意味もよくわからない。。。。

https://notes.ethereum.org/SCIg8AH5SA-O4C1G1LYZHQ?view

PoSといえど、そもそもblockchainが分散状態にあるっていう前提で考えると結局finalizeされたcheckpoinも場合によってはforkする。

(forkしてる場合基本的に長い間分断されたネットワークが2つあることになると思うが)forkしたfinalizeをもつ2つのネットワークが互いにつながった時に、果たしてどちらのcheckpointを有効かするかって問題が出てくる。

で、それを調べるための情報を得るのにこの2つのメソッドを使うってことか!

PoWのアルゴリズムと比較すると
difficulty = all deposited ETH.
block height = highest_justified( or highest_finalized)

と置き換えられる。
なので highest_justified epoch * all deposits が一番でかいcheckpointを優先するっていうアルゴリズムになってるのか。

withhold対策ってしてないぽいなぁ。

2/3以上のdepositが集まったか調べる時に、この辺の係数使うことで、withholdしてたら全体のdeposit量が徐々に減っていくことになるから、そのうち2/3超えるようになって〜っていう対策してると思ったけどそうじゃないのね。。。。

まだ実装途中か、それともwithdrawする時に取り分なくなるからそのうちみんな戻ってくるでしょ。で十分としてるのか。。。。

1 Like

一般的にステートマシンが保証すべきSafety(悪い状態にならないこと)とLiveness(最終的に良い状態で安定すること)プロパティについて

・同期プログラミングではSafetyもLivenessも補償するのは容易い(クリティカルセクションを同時に操作することがないし、エラーハンドリングを厳密にやればいい)
・非同期プログラミングでは「リソースを共有するのでクリティカルセクションがあり、不整合が起きうる(Safetyがない)」「メッセージがロストしてそれを検知できない(Livenessがない)」というのを慎重にケアする必要があると認識しています。

fork choice

Casper FFG WPにAccountable Safetyと呼ばれるものがあり、大意で「同じDynastyのcheckpointは存在できない」という定理だったと思うので、checkpointがforkするような状態遷移がないように作っていくものと思ってました。

withholding

WPにPlausible Livenessと呼ばれるものがあり、Tx(メッセージ)が無期限に処理されなくなると、ステートマシンはLivenessがないということになるので、何らかの方法で正常な状態に復帰できる方法を持っていないといけないのかなと思っています。

プロトコルのセキュリティを定理証明レベルでまず補償できていることを確認している人たちがいて、それを受けて安心して定理を実装に移すという工程を考えるなら、まだ実装できていない部分を埋めていかないといけないのかもですね。Plasmaもそんな感じです。

2 Likes

報酬のタイミングはvote時で、かつvoteの時に指定したsource_epochがjustifyされていた場合にもらえると。

報酬額はdeposit金額に応じて決まるから大量にdepositした方がより多くの報酬をもらえると。
casper FFGではvoteしてくれたvalidatorとvalidatorに選ばれたblockのminnerに報酬が支払われるので、確率的にstakerに報酬が支払われるようなシステムではない。みんな報酬自体はうけとれる。でもその比率はdepositの量に比例する。

1 Like

報酬のところ間違って理解してた内容が実は結構面白いアイデアかと思ったのでちょっとだけ整理してみる。

  1. validatorの1つ前のepochの投票を残しておく
validators[validator_index].prev_vote_epoch = target_epoch
  1. N+1のepoch投票時に前に投票したepochの値がjustifyされてたら追加報酬をえる
if validators[vlidator_index].prev_vote_epoch == self.expected_source_epoch:
    validators[vlidator_index].deposit += ex_reward

これだと、できるだけjustifyを受けれるblockを選ぼうとするし、かつ追加報酬をえるためには投票を継続指定かいないとけない。 というインセンティブが生まれるかな?と。
シビルアタックのインセンティブにもなっちゃうけど。。。

今のcasper FFGのコードとあわせた全体のコードのイメージはこんな感じ

if self.expected_source_epoch == source_epoch:
    reward: decimal(wei/sf) = self.validators[validator_index].deposit * self.reward_factor
    self.proc_reward(validator_index, reward)
    if validators[vlidator_index].prev_vote_epoch == self.expected_source_epoch:
        validators[vlidator_index].deposit += ex_reward
   validators[validator_index].prev_vote_epoch = target_epoch