We previously tried to convince @adlerjohn to have only one tree for both account state and validator set(s).
That means a light client downloading the validator set of a particular height would also need to request an inclusion proof per validator in that set (inclusion in the state smt that is).
As we plan to use optimized compact smts, the size of an inclusion proof varies depending on the actual entries in that tree. Assuming, that we have loads of actually used accounts in the tree, we quickly hit 500kb and upto 1MB of inclusion proof data only (additionally to the valset data).
If we instead track the valset in a different tree for validators only, the light client only needs the root of that tree (in the header) and it's leaves (the vals in the valset) to verify the valset matches the one signed a header (or will sign a future header).
Tendermint basically already does this by including ValidatorsHash
and NextValidatorsHash
fields in the header: https://github.com/tendermint/tendermint/blob/18d333c3927f3dce0d8d5970ee40e5ffcc33448b/types/block.go#L351-L353
(note in tendermint, these result from txs included in the previous block due to deferred execution)
Different from tendermint, we can't use the exact kind of simple tree as we want to enable compact fraud proofs (e.g. a compact smt instead of the simple merkle tree currently used: https://github.com/tendermint/tendermint/blob/18d333c3927f3dce0d8d5970ee40e5ffcc33448b/types/validator_set.go#L345-L356) and the app needs to track the tree changes as far as I understand (intermediate state roots for fraud proofs).
In any case, we should re-discuss on the state tree or trees.
With a dedicated tree for the valset, the light client now can downloads the valset and recompute the tree without downloading an inclusion proof per validator.
(to verify the root matches the state root in the header it actually needs the accounts root too but that should be it).