概要
Tezosも含めたBitcoinやEthereumなどのブロックチェーンにおいては、口座間の送金やスマートコントラクト呼び出しなどの現在のブロックチェーンの状態に対する差分操作がブロックとして表現されます。
この記事では、Tezosのプロトコル(バージョン 010 Granada)において、どのようにしてブロック検証が行われているかを、Tezosのコードを追うことによって解説していきます。実装が日々改善されているシェルのコードに関しては、執筆時点で最新の安定バージョンであるv10.2のコードに基づきます。
シェルにおけるブロック検証と生成
Validatorによるブロック検証
Validator(tezos-validator
)は、ノード(tezos-node
)を起動すると裏で別プロセスとして立ち上がり、ノードに送られてきたブロックに対して、そのブロックが実際に正しいブロックであるかどうかを検証します1。 Tezosにおけるvalidatorはドキュメントにあるように様々な役目があるのですが、このうち特にblock validatorによってブロックの正しさが確かめられています。
ソースコード上においては、validatorバイナリを起動するとbin_validator/
のValidator.main
が呼び出され、ここからlib_validation
のapply
が呼び出されます。この関数では、以下の手順でブロックが検証されます。
- 現在のブロックチェーン状態(context)上に保存されている現在のプロトコルハッシュから、対応するプロトコルのモジュールを取得
- プロトコルのモジュールから
Block_validation
モジュールを作り、contextに対してBlock_validation.apply
を呼び出し、新しい状態を含むブロック生成結果を返す
この手順中に何かしらエラーが発生したり、得られた新状態のハッシュがブロックが主張する新状態のハッシュと異なる場合は、ブロックは不正であると判断されます。
Block_validation.apply
の定義は lib_validation
のBlock_validation.Make()
中 に存在します。この関数では
- 現在のcontextに対するoperation列の適用
Proto.begin_application
で現在のcontextから状態stateを生成- stateに対して
Proto.apply_operation
を繰り返し各operationについて適用 Proto.finalize_block
を用いてstateから新たなcontextやcontextに対する操作内容であるブロックを生成
- (必要なら)新プロトコル/新protocol environmentへの切り替えを行う
などが行われています。
Proto
モジュール以下の関数は現在のプロトコル固有の関数であり、具体的なブロック生成検証は各プロトコルによって異なります。
Bakeによるブロック生成
tezos-client
で起動できるサブコマンド2の中に、
Commands related to delegate operations.:
bake for <baker> [オプション省略]
Forge and inject block using the delegate rights.
<baker>: name of the delegate owning the baking right
があります。このサブコマンドは、コード上では各プロトコルにおけるlib_delegate/delegate_commands.ml
中のdelegate_commands
において定義され、lib_delegate/delegate_commands_registeration.ml
中でClient_commands.register
を呼び出すことによってtezos-client
のコマンドとして登録されています。
このコマンドにおけるoperationの扱いを追って行くと、lib_delegate/client_baking_forge.ml
中のfilter_and_apply_operations
にたどり着きます。この関数の中で、前セクションで紹介したBlock_validation.apply
と同様に、Client_baking_simulator.add_operation
の各operationについての繰り返し適用が行われています。add_operation
は内部的にProto.apply_operation
を呼び出しており、これより内部の処理はvalidatorにおける処理と共通になっています。
Bakerは選んだoperationを適用し、新状態を得、その情報(ハッシュ等)を使ってブロックを生成します。
プロトコルにおけるoperation適用
以降では、特にGranadaプロトコルにおいて、apply_operation
の内部の処理を追っていきます。この関数では、種々のoperation(命令)の適用が行われます。各operationを適用した結果の残高の遷移は、関数の返すreceiptの内容からわかります。
各operationは、tezos-client
やtezos-baker
、tezos-accuser
などを用いて生成されます。たとえば./tezos-client transfer
コマンドを叩くことでTransaction
operationを生成することができます。
Operationの中には、スマートコントラクト実行中にMichelson命令によって生成されるものがあります。たとえば、Transaction
operationはMichelsonのTRANSFER_TOKENS
が実行されることでも生成されます。
Operationに関しては、既存の記事 The Lifecycle of an Operation in Tezos でも説明されています。この記事の公開日時は2019年5月と昔ではありますが、この記事で紹介されている11個のoperationは以下で紹介するGranadaにおけるoperationと対応しています。
Tezosでは送金など、一般の tz* アカウントが行える操作のことを “manager operation” と呼び、内部的にはmanagerではないoperationとは別の関数で処理を行います。Manager以外の operation はブロックの承認やオンチェーン・ガバナンス投票関連など、roll を持つ baker が発行する命令です。
Manager operation
Manager operationは Apply.apply_manager_operation_content
において処理されます。
Managerであるoperationは以下の4種類です。すべてlib_protocol/operation_repr.ml
で定義されています。
Transaction {amount; parameters; destination; entrypoint}
- コントラクト間の送金を行う命令です。
amount
は送金額、destination
は送金先アドレスです。受け取り側のコントラクトがスマートコントラクト(originated account)である場合、entrypoint
に従ったエントリポイントに対して、parameters
を引数としたスマートコントラクト呼び出しが行われます。 tezos-client transfer
コマンドや、MichelsonのTRANSFER_TOKENS
命令を使うことで生成されます。
- コントラクト間の送金を行う命令です。
Origination {delegate; script; preorigination; credit}
- 新しくスマートコントラクトを作る命令です。
script
をコードとして持つスマートコントラクトアカウントが作られます。 - Michelsonでは
CREATE_CONTRACT
命令を使うことで生成されます。
- 新しくスマートコントラクトを作る命令です。
Reveal pk
- この命令のsourceアカウントが公開鍵(public key)をまだ公開していなかった場合、そのpublic keyを公開します。スマートコントラクトのmanagerのkey状態には2種類あり、最初はpublic keyのhashだけが分かっている状態(
Hash
)ですが、この命令を用いることで具体的な公開鍵が分かっている状態(Public_key
)になります。 - アカウントが発行した operation はそのアカウントの秘密鍵によって電子署名されます。第三者がこの operation の正当性を確認するためにはアカウントの公開鍵が必要で、これをブロックチェーンに登録するのが
Reveal
です。 tezos-client
を用いてmanager operation列を発行した場合、内部的にはlib_client
のinject_manager_operation
によってtezos-node
への送信が行われます。この際、もし送信元が公開鍵をrevealしていなかった場合、自動的にReveal
命令がmanager operation列の先頭に付け加えられます。なお、tezos-client reveal key for ..
を使って明示的に生成することもできます。- このmanager operationを明示的に生成する Michelson の命令はありません。
- この命令のsourceアカウントが公開鍵(public key)をまだ公開していなかった場合、そのpublic keyを公開します。スマートコントラクトのmanagerのkey状態には2種類あり、最初はpublic keyのhashだけが分かっている状態(
Delegation delegate
- 口座残高から生じるbaking権やendorsing権をdelegate(移譲)するための命令です。
delegate
はoption型であり、Some
の場合はdelegateの設定を、None
の場合はdelegateの解除を行います。 - Michelsonの
SET_DELEGATE
命令によって生成されます。
- 口座残高から生じるbaking権やendorsing権をdelegate(移譲)するための命令です。
lib_protocol/script_interpreter.ml
のstep
関数内を読むことで、各Michelson命令の実行時にどのようにしてmanager operationが生成されるかが分かります。
Manager ではない operation
Managerではないoperationはapply_contents_list
関数において処理されます。
Managerではないoperationは以下の7種類です。manager operationと同様、すべてlib_protocol/operation_repr.ml
で定義されています。
最初の2命令(Endorsement_with_slot
, Seed_nonce_revelation
)は報酬を貰うための命令です。
Endorsement_with_slot {endorsement={shell={branch}}; slot}
- ブロック
branch
に対するendorsement(裏書)を行う命令です。branch
が直前のブロックであるかやendorsement権slot
が未使用であるかなどが確認され、そうである場合、残高からendorsement depositを一時的にfrozen_depositに移し、endorsement報酬がfrozen_rewardsへ追加されます。 - この報酬は権利
slot
をもつdelegateに対して入ります。
- ブロック
Seed_nonce_revelation {level; nonce}
- 過去のlevelのnonceを明らかにして報酬をもらう命令です。
level
は1つ前のcycleに属している必要があります。 - この報酬はbakerに対して入ります。
- 過去のlevelのnonceを明らかにして報酬をもらう命令です。
次の2命令(Double_endorsement_evidence
, Double_baking_evidence
)は二重に報酬を貰おうとする行為を報告し、報酬をもらうための命令です。
Double_endorsement_evidence {op1; op2; slot}
- Double endorsementの証拠を持ってきて報酬をもらう命令です。
op1
とop2
がどちらも権利slot
によって行われたEndorsement
命令3である場合、Delegate.punish
によって権利slot
を持つdelegateのfrozen_balance
(frozen_deposit
とfrozen_fees
とfrozen_rewards
)から残高が没収されます。 - 報告報酬はbakerに入ります。
- Double endorsementの証拠を持ってきて報酬をもらう命令です。
Double_baking_evidence {bh1; bh2}
- Double bakingの証拠を持ってきて報酬をもらう命令です。
bh1
とbh2
がどちらも同じdelegateによって生成されて、かつ古すぎず新しすぎないlevelの場合、Double_endorsement_evidence
と同様にDelegate.punish
によって残高が没収されます。 - 報告報酬はbakerに入ります。
- Double bakingの証拠を持ってきて報酬をもらう命令です。
次の命令(Activate_account
)はICOアカウントを有効化するための命令です。テストネットでのfausetアカウントの有効化にも使われます。
Activate_account {id; activation_code}
- ICOアカウントを有効化するための命令です。
- テストネットの場合、たとえば、https://faucet.tzalpha.net/を用いるとfausetアカウントが得られますが、これをactivate accountコマンドによって有効化すると、内部的には
lib_client
のactivate_account
が呼ばれ、この中でActivate_account
命令が発行されます。
最後の2命令(Proposals
, Ballot
)はオンチェーン・ガバナンスのための命令であり、https://tezos.gitlab.io/active/voting.htmlに詳しい説明が記載されています。
Proposals {source; period; proposals}
source
から送られてきたプロトコル提案(proposals
)を記録する命令です。受信時点でのvoting periodがProposalである必要があり、加えてperiod
が現在のvoting periodのindexと一致している必要があります。各delegateが一度に何個のproposalを提案できるかはlib_protocol/constants_repr.ml
に記載されており、たとえばGranadaの場合は20個です。- Proposal期間に送られてきたproposalsを総計して、一番得票数の多いprotocolが現在の提案protocolになり、次のvoting periodであるExploration期間に移行します。
Ballot {source; period; proposal; ballot}
source
から送られてきた投票を記録する命令です。受信時点でのvoting periodがExplorationもしくはPromotionである(投票フェイズである)必要があります。加えて、period
が現在のvoting periodのindexに、proposal
が現在の提案proposalのprotocol hashに一致している必要があります。ballot
はtype ballot = Yay | Nay | Pass
型を持ち、それぞれ現在のプロトコルに対する賛成/反対/棄権を表します。
-
tezos-validator
はBlock_validator_process..start_process
で起動されます。 ↩︎ -
どのようなサブコマンドがあるかは、
./tezos-client --endpoint https://rpc.tzstats.com man
などで確認できます。 ↩︎ -
Endorsement
命令は、この記事で紹介した11の命令とは別に、Endorsement_with_slot
命令やDouble_endorsement_evidence
命令に包まれた内部的な命令としてのみ現れる命令です。 ↩︎