Add commitment metrics implementation to book (#5903)
* Add commitment metrics implementation to book
This commit is contained in:
parent
03d29a8311
commit
6ce115ec95
|
@ -0,0 +1,89 @@
|
|||
# Commitment
|
||||
|
||||
The commitment metric aims to give clients a measure of the network confirmation
|
||||
and stake levels on a particular block. Clients can then use this information to
|
||||
derive their own measures of confidence.
|
||||
|
||||
# Calculation RPC
|
||||
|
||||
Clients can request commitment metrics from a validator for a signature `s`
|
||||
through `get_block_commitment(s: Signature) -> BlockCommitment` over RPC. The
|
||||
`BlockCommitment` struct contains an array of u64 `[u64, MAX_CONFIRMATIONS]`. This
|
||||
array represents the commitment metric for the particular block `N` that
|
||||
contains the signature `s` as of the last block `M` that the validator voted on.
|
||||
|
||||
An entry `s` at index `i` in the `BlockCommitment` array implies that the
|
||||
validator observed `s` total stake in the cluster reaching `i` confirmations on
|
||||
block `N` as observed in some block `M`. There will be `MAX_CONFIRMATIONS` elements in
|
||||
this array, representing all the possible number of confirmations from 1 to
|
||||
`MAX_CONFIRMATIONS`.
|
||||
|
||||
# Computation of commitment metric
|
||||
|
||||
Building this `BlockCommitment` struct leverages the computations already being
|
||||
performed for building consensus. The `collect_vote_lockouts` function in
|
||||
`consensus.rs` builds a HashMap, where each entry is of the form `(b, s)`
|
||||
where `s` is a `StakeLockout` struct representing the amount of stake and
|
||||
lockout on a bank `b`.
|
||||
|
||||
This computation is performed on a votable candidate bank `b` as follows.
|
||||
|
||||
```
|
||||
let output: HashMap<b, StakeLockout> = HashMap::new();
|
||||
for vote_account in b.vote_accounts {
|
||||
for v in vote_account.vote_stack {
|
||||
for a in ancestors(v) {
|
||||
f(*output.get_mut(a), vote_account, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
where `f` is some accumulation function that modifies the `StakeLockout` entry
|
||||
for slot `a` with some data derivable from vote `v` and `vote_account`
|
||||
(stake, lockout, etc.). Note here that the `ancestors` here only includes
|
||||
slots that are present in the current status cache. Signatures for banks earlier
|
||||
than those present in the status cache would not be queryable anyway, so those
|
||||
banks are not included in the commitment calculations here.
|
||||
|
||||
Now we can naturally augment the above computation to also build a
|
||||
`BlockCommitment` array for every bank `b` by:
|
||||
1) Adding a `ForkCommitmentCache` to collect the `BlockCommitment` structs
|
||||
2) Replacing `f` with `f'` such that the above computation also builds this
|
||||
`BlockCommitment` for every bank `b`.
|
||||
|
||||
We will proceed with the details of 2) as 1) is trivial.
|
||||
|
||||
Before continuing, it is noteworthy that for some validator's vote account `a`,
|
||||
the number of local confirmations for that validator on slot `s` is
|
||||
`v.num_confirmations`, where `v` is the smallest vote in the stack of votes
|
||||
`a.votes` such that `v.slot >= s` (i.e. there is no need to look at any
|
||||
votes > v as the number of confirmations will be lower).
|
||||
|
||||
Now more specifically, we augment the above computation to:
|
||||
|
||||
```
|
||||
let output: HashMap<b, StakeLockout> = HashMap::new();
|
||||
let fork_commitment_cache = ForkCommitmentCache::default();
|
||||
for vote_account in b.vote_accounts {
|
||||
// vote stack is sorted from oldest vote to newest vote
|
||||
for (v1, v2) in vote_account.vote_stack.windows(2) {
|
||||
for a in ancestors(v1).difference(ancestors(v2)) {
|
||||
f'(*output.get_mut(a), *fork_commitment_cache.get_mut(a), vote_account, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
where `f'` is defined as:
|
||||
```
|
||||
fn f`(
|
||||
stake_lockout: &mut StakeLockout,
|
||||
some_ancestor: &mut BlockCommitment,
|
||||
vote_account: VoteAccount,
|
||||
v: Vote, total_stake: u64
|
||||
){
|
||||
f(stake_lockout, vote_account, v);
|
||||
*some_ancestor.commitment[v.num_confirmations] += vote_account.stake;
|
||||
}
|
||||
```
|
Loading…
Reference in New Issue