validation.h, validation.cpp
語彙
有効チェーン(chainActive): 現在有効なチェーン。つまり、実際の台帳としての効力を持っている唯一のチェーン。
最長フォーク(BestFork): チェーンアクティブからのフォークのうち、最も chainWork が強いもので、フォークの可能性があるとして追跡されているもの。
最長不正ブロック(BestInvalid): ステータスが BLOCK_FAILED_MASK である。または BLOCK_HAVE_DATA ではないブロックのうち、chainwork が最も大きいもの。平たく言うと、Bitcoinのコンセンサスに反しているもの、または実データがなくvalidかどうか検証できないものの中で最も chainwork が大きいブロック。 先端( Tip ): チェーンの先端(一番最新の)ブロックのこと。
CChainState
https://gyazo.com/16feeb529a9da0a4053de8ceb84499ac
Publicフィールド
CChain chainActive;
有効なチェーン。
CChainState で管理する全てのフォークのうち最もchainworkが大きく有効であると判断されているチェーン。
BlockMap mapBlockIndex;
有効(valid)なブロックをストアしているマップ。フォークにあり、chainActive に含まれないブロックも保持しているみたい。
std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
未確認
CBlockIndex *pindexBestInvalid = nullptr;
未確認
CheckForkWarningConditions (validation.cpp) 内でフォークの検出に使われている。ここから察するに、activeChainではないがその次点で有力なフォークの先端の blockIndex を保持するフィールドということかな。
private フィールド
std::set<CBlockIndex*, CBlockIndexWorkComparator> setBlockIndexCandidates;
BLOCK_VALID_TRANSACTIONSを満たす全てのCBlockIndexエントリの集合(それ自体およびすべての祖先について)で、現在のチップ以上のもの。エントリは失敗するかもしれません、そして、枝刈りノードはブロックのためのデータを失っているかもしれません。(The set of all CBlockIndex entries with BLOCK_VALID_TRANSACTIONS (for itself and all ancestors) and as good as our current tip or better. Entries may be failed, though, and pruning nodes may be missing the data for the block.) int32_t nBlockReverseSequenceId = -1;
Public メソッド
bool ActivateBestChain(
引数
CValidationState &state
const CChainParams& chainparams
std::shared_ptr<const CBlock> pblock)
bool CChainState::PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex)
PreciousBlockとは。
private メソッド
bool ActivateBestChainStep
引数
CValidationState& state
const CChainParams& chainparams
CBlockIndex* pindexMostWork
const std::shared_ptr<const CBlock>& pblock
bool& fInvalidFound
ConnectTrace& connectTrace
CBlockIndex* FindMostWorkChain();
チェーン内で最もchainwok が大きいもののうち、invalid ではない tip を返す。(しかし各自につに valid であるとは限らない)
BlockManager クラス
一番 ChainWorkが大きなチェーンを決めるときのために、ブロックのツリー構造を管理する。
extern 変数
mapBlockIndex
extern CBlockIndex *pindexBestHeader;
今まで見た中で最新のヘッダー(getheaders クエリを開始する場所として使われる)
Static 関数
static void CheckForkWarningConditions()
チェーンがフォークする予兆がある場合にログに Warning を出す処理です。
処理の内容
Initial Block Download(IBD) 中はフォークに関する動作はできないとみなし、ワーニングは出さない。
最長フォークのチップが有効チェーンよりも72ブロック以上遅れている場合、最長フォークではなくする。
最長フォークがあるまたは、最長不正ブロックが有効チェーンの先端よりも1時間(6ブロック)先行している場合、
新しくフォークの可能性があるブロックが見つかった時に以下の警告をだす。
Warning: Large-work fork detected, forking after block xxxxxxxxxxxxxxx(ブロックハッシュ)
追跡中のフォークの可能性があるブロックの状況について以下のログを出す。
code: log
CheckForkWarningConditions: Warning: Large valid fork found
Chain state database corruption likely.
または、フォークではないが、最長不正ブロックが少なくとも有効チェーンよりも6ブロック以上長い場合にも以下の警告を出す
code: log
CheckForWarningConditions: Warning: Found invalid chain at least ~6 blocks longer than our best chain.
Chain state database corruption likely.
不正なチェーンを監視して警告を出している理由
フォークの可能性があるチェーンについて警告を出すのはわかるが、不正なチェーンについても自身のチェーンよりも長いものがあれば警告を出す理由はなんだろうか?警告のメッセージには、「チェーンステートデータベースが破損考えられます」とある。想像するに、自分が持っている有効チェーンよりも長い不正(invalid)なチェーンが生まれる可能性はあまり考えにくい。わざわざそのようなチェーンを積み上げるインセンティブは無いので。なので、その場合自分が有効だと思っているチェーンに問題があると考えるべきということかもしれない。自分のデータベースの破損により、本来有効なはずのチェーンの検証に失敗して、不正とみなしてしまっている可能性を考慮して、データベースの再構成などにより正しいチェーンを扱う状態に復帰することを促していると考えられる。
過去のディスカッションを紐解けばこれについてヒントがあるかもしれない。
static void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)
処理の内容
引数にフォークチェーンの先端ブロックを受け取る。
フォークチェーンが、有効チェーンのどこから枝分かれしているか探す。
監視している最長フォークが無い場合は、引数で受け取ったフォークの先端を pindexBestForkTip (最長フォークの先端) に、枝分かれしてている根本のブロックを pindexBestForkBase (最長フォークのフォーク元)にセットする。
監視している最長フォークがある場合も、
現在監視しているものよりも引数で受け取ったものが
ブロック高が高いこと
フォークがある程度の chainWork を使って生成されていること
具体的には7ブロック分程度の chainWork を持っている事をチェックしています。それよりも小さい chainWork しか持たない場合は、有力なフォークとしては扱わないようです。
有効チェーンの先端までの高さの差が 24時間(72ブロック)より小さいこと(古すぎないこと)