Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 81 additions & 1 deletion protocol/0064-VALP-validator_performance_based_rewards.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
# Validator performance based rewards

## Network Parameters

1. `bridge_heartbeat_periods[]`: This parameter defines how many events on the chain hosting the a bridge (e.g., Ethereum) need to pass (in average) for a validator to have to forward a heartbeat event. If it is set to 0, heartbeats are deactivated. As Vega supports several bridges, this parameter is an array.
To assure that there is a clear limk between bridge identity and its parameter, the parameter takes the form
<string> bridge_id_1, <int> period_1,
<string> bridge_id_2, <int> period_2,
...
Valid range for the period is any integer >= 0
The initial value is "Ethereum_Mainnet", 128.

If a new bridge is added, this parameter can be extended without a governance vote to accomodate the new bridge.

1. `read_heartbeat_periods[]`: This parameter defines how many chain events need to pass (in average) for a validator to have to forward a heartbeat event for read events, e.g., oracle access.. If it is set to 0, heartbeats are deactivated. This parameter also is an array.
To assure that there is a clear limk between bridge identity and its parameter, the parameter takes the form
<string> read_id_1, <int> period_1,
<string> read_id_2, <int> period_2,
...
Valid range is any integer >= 0
The initial value is "Ethereum_Mainnet_Read_Access",128.

If a new oracle/chain is added, this parameter can be extended without a governance vote to accomodate the new chain.

1. `performance_weights` is a vector containing n+2 integer values w0,w1,w2,w3...,wn, where n is the number of performace attributes. This parameter defines the weights of the different performance measurements that impact the reward. The weight formula (given performance values p1, p2 and p3) is w0*p1*p2*p3 + w1*p1+w2*p2+w3*p3).
If more performance measurements are added later, this vector is expanded correspondingly.

At the moment, we measure three attributes (Tendermint, Bridge Observation, Ethereum Read access, in that order).

Legal values are all floats that sum up to 1. The initial value is (0,1,0,0), i.e., only tendermint performance has any impact on the rewards.

## Adjusting Validator Rewards Based on Performance

The Vega chain is a delegated proof-of-stake based chain where validators are rewarded from fees generated or from on-chain treasury.
Expand All @@ -13,7 +42,7 @@ The purpose of the specification is to define how the validator rewards will be

### Tendermint validators

Goal: Detect how long a validator is offline and punish them
Goal 1: Detect how long a validator is offline and punish them
Detection: Validator does not act as a leader

For each block tendermint provides information about who is the proposer. The selection of the proposer is deterministic and is proportional roughly to the voting power of the validator. Therefore we can calculate the performance of a validator in the following way:
Expand All @@ -36,6 +65,56 @@ be modified and set to neutral defaults (i.e., 0)

Then `validator_performance = max(0.05, min((p'/expected, 1))`

Goal 2: Detect un-forwarded Ethereum events and lack or read access and punish the validator that does not forward them
Detection: Events forwarded by some validators are not forwarded by others.

#### Ethereum Heartbeat

For the each Bridge Heartbeat, we use the network parameter `bridge_heartbeat_period`. This parameter should be either 0 or a value bigger than the number of validators; the recommended initial value is 128 on Ethereum, which would create a heartbeat per validator about every 20 minutes (i.e., about 120 heartbeats per validator per epoch); chains with a different speed should adapt the parameter correspondingly. Legal values are all integers larger or equal to 0.

For every block on the target chain, if the hash of this block mod `bridge_heartbeat_period` equals the identity of the a validator (taken mod bridge_heartbeat_period)+1, then this validator has to forward this as an event. This event is confirmed by other validators just like any other event, but then ignored. If that block also contains a valid Vega event that requires an action, this is forwarded independently by the normal event forwarding mechanisms. The heartbeat also does contain the block hash of the corresponding block.
If the parameter is set to 0, the heartbeats are effectively turned off.

If a validator forwards a heartbeat, all other validators have to validate its correctness by checking if the hashes work out.

#### Read Access Heartbeat

For each measured chain defined in read_ethereum_period[], the following is done

For every block on the measured chain, if the hash of [The balance of the key that initiated the first transaction on the block / the random value of that block] mod `read_heartbeat_period` equals the identity of the a validator (taken mod ethereum_read_heartbeat_period)+1, then this validator has to forward this as an event. This event is confirmed by other validators just like any other Ethereum event, but otherwise ignored. If that block also contains a valid Vega event that requires an action, this is forwarded independently by the normal event forwarding mechanisms.

#### Performance Measurements

t the end of each epoch, it is counted how many Ethereum events have been forwarded by each validator; this is (number_of_ethereum_blocks_per_epoch)/`ethereum_heartbeat_period`)+number_of_ethereum_events_per_validator

Let `expected_f` be the maximum number of Ethereum events forwarded by any Validator given above conditions (i.e. the best validator defines the expectation), and `f` be the number of blocks a given validator has forwarded. If `expected_f` equals zero, then all scores are set to 1.
Let `low_volume_correction` be `abs(3-expected_f)`.

[Comment: expected_f is not calculated using statistics, as that would mean that an issue with the Ethereum chain would cause punishment for the validators. A more precise estimate (all validators counting what all others should forward) is also possible, but unnecessarily complex).


Else, validator_ethereum_performance = `(min((f+low_volume_correction)/(expected_f)*1.1, 1)))`,

The exact same calculation is used to compute validator_ethereum_read_performance.

Explanation: low_volume_correction handle the case that the number of events is very low, and a validator might just by bad luck never get anything to forward (which also would only happen if the heartbeat is deactivated). Thus, if a validator is expected to forward 2 or less events, it is not penalised if it didn't forward any.
The multiplication with 1.1 is adding preventing a validator to get penalised if they got slightly less than others (which always can happen due to the random distribution). Thus, a validator that forwards 95% of the events that others do is not penalised. We could get more precision here (differentiating between the heartbeat and the expected real events etc), but that'd be overthinking.
In the end, we make sure no score is bigger than 1 (which might happen due to the multiplicative bonus).

### Total Performance

As we have several performance measurements, they need to be combined to a total score. To this end, we have a system variable `performance_weights`,
which has n+1 parameters (weight_0,.. weight_n) for n measurements (currently 2, the tendermint-performance and the ethereum-performance. Weights are normalised, so the sum of all weights needs to be 1. Also, all individual performance measurements are normalised to be between 0 and 1.

the weight formula (given performance values p1, p2,... pn) is weight_0*p1*p2*...*pn + weight_1*p1+weight_2*p2+...+weight_n*pn).

Currently, we have 3 performance measurements, namely
p1 = tendermint performance
p2 = Ethereum Bridge Performance
p3 = Etherum Read Performance,

the weight formula (given performance values p1, p2 and p3) is weight_0*p1*p2*p3 + weight_1*p1+weight_2*p2+weight_3*p3).

### Ersatz and pending validators

For validators who [have submitted a transaction to become validators](./0069-VCBS-validators_chosen_by_stake.md) the `performance_score` is defined as follows: during each epoch
Expand Down Expand Up @@ -87,6 +166,7 @@ The performance score should be available on all the same API endpoints as the `
- Verify that, at the beginning of the next epoch, all performance scores are 0 and voting power for all is 1 but the network keeps producing blocks and no nodes were removed from Tendermint.
1. Scores are restored after a snapshot restart (<a name="0064-VALP-006" href="#0064-VALP-006">0064-VALP-006</a>):
- With a snapshot that was taken at a block-height that falls in the middle of an epoch, restart a node from that snapshot. Ensure that at the end of the epoch the node remains in consensus and has produced the correct performance scores.
1. Setting the performance weights to (0,0,1,0) and (0,0,0,1) penalises validators only based on missed ethereum events and missed read access, respectively (<a name="0064-VALP-007" href="#0064-VALP-007">0064-VALP-007</a>)

## Future Stuff (in here for discussion purposes, not yet to be implemented)

Expand Down