From 0cd41bc5784f0443e637834cdde259839bccef85 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Thu, 11 Oct 2018 14:14:48 -0400 Subject: [PATCH 1/3] Rework validator exiting, add min balance clause --- specs/beacon-chain.md | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/specs/beacon-chain.md b/specs/beacon-chain.md index d5ca0c648..1113bc991 100644 --- a/specs/beacon-chain.md +++ b/specs/beacon-chain.md @@ -43,6 +43,7 @@ The primary source of load on the beacon chain are "attestations". Attestations | `BASE_REWARD_QUOTIENT` | 2**15 (= 32,768) | — | | `MAX_VALIDATOR_CHURN_QUOTIENT` | 2**5 (= 32) | — | | `LOGOUT_MESSAGE` | `"LOGOUT"` | — | +| `MIN_ONLINE_DEPOSIT_SIZE` | 2**4 (= 16) | ETH | **Notes** @@ -560,6 +561,20 @@ def add_validator(validators: List[ValidatorRecord], return index ``` +## Routine for removing a validator + +```python +def exit_validator(index, crystallized_state, penalize, current_slot): + v = crystallized_state.validators[index] + v.exit_slot = current_slot + if penalize: + v.status = PENALIZED + crystallized_state.deposits_penalized_in_period[current_slot // WITHDRAWAL_PERIOD] += v.balance + else: + v.status = PENDING_EXIT + add_validator_set_change_record(crystallized_state, index, v.pubkey, EXIT) +``` + ### Per-block processing This procedure should be carried out every block. @@ -664,18 +679,14 @@ In addition, validators with `status == PENALIZED` lose `B // reward_quotient + For each `SpecialRecord` `obj` in `active_state.pending_specials`: -* **[covers logouts]**: If `obj.kind == LOGOUT`, interpret `data[0]` as a validator index as an `int32` and `data[1]` as a signature. If `BLSVerify(pubkey=validators[data[0]].pubkey, msg=hash(LOGOUT_MESSAGE), sig=data[1])`, and `validators[i].status == ACTIVE`, set `validators[i].status = PENDING_EXIT` and `validators[i].exit_slot = current_slot` -* **[covers `NO_DBL_VOTE`, `NO_SURROUND`, `NO_DBL_PROPOSE` slashing conditions]:** If `obj.kind == CASPER_SLASHING`, interpret `data[0]` as a list of concatenated `int32` values where each value represents an index into `validators`, `data[1]` as the data being signed and `data[2]` as an aggregate signature. Interpret `data[3:6]` similarly. Verify that both signatures are valid, that the two signatures are signing distinct data, and that they are either signing the same slot number, or that one surrounds the other (ie. `source1 < source2 < target2 < target1`). Let `indices` be the list of indices in both signatures; verify that its length is at least 1. For each validator index `v` in `indices`, if its `status` does not equal `PENALIZED`, then: - -1. Set its `exit_slot` to equal the current `slot` -2. Set its `status` to `PENALIZED` -3. Set `crystallized_state.deposits_penalized_in_period[slot // WITHDRAWAL_PERIOD] += validators[v].balance`, extending the array if needed -4. Run `add_validator_set_change_record(crystallized_state, v, validators[v].pubkey, EXIT)` +* **[covers logouts]**: If `obj.kind == LOGOUT`, interpret `data[0]` as a validator index as an `int32` and `data[1]` as a signature. If `BLSVerify(pubkey=validators[data[0]].pubkey, msg=hash(LOGOUT_MESSAGE), sig=data[1])`, and `validators[i].status == ACTIVE`, run `exit_validator(data[0], crystallized_state, penalize=False, current_slot=current_slot)` +* **[covers `NO_DBL_VOTE`, `NO_SURROUND`, `NO_DBL_PROPOSE` slashing conditions]:** If `obj.kind == CASPER_SLASHING`, interpret `data[0]` as a list of concatenated `int32` values where each value represents an index into `validators`, `data[1]` as the data being signed and `data[2]` as an aggregate signature. Interpret `data[3:6]` similarly. Verify that both signatures are valid, that the two signatures are signing distinct data, and that they are either signing the same slot number, or that one surrounds the other (ie. `source1 < source2 < target2 < target1`). Let `indices` be the list of indices in both signatures; verify that its length is at least 1. For each validator index `v` in `indices`, if its `status` does not equal `PENALIZED`, then run `exit_validator(v, crystallized_state, penalize=True, current_slot=current_slot)` * **[covers RANDAO updates]**: If `obj.kind == RANDAO_REVEAL`, interpret `data[0]` as an integer and `data[1]` as a hash32. Set `validators[data[0]].randao_commitment = data[1]`. #### Finally... +* If the balance of any validator with index `v` is less than `MIN_ONLINE_DEPOSIT_SIZE`, then run `exit_validator(v, crystallized_state, penalize=False, current_slot=current_slot)` * Set `crystallized_state.last_state_recalculation_slot += CYCLE_LENGTH` * Remove all attestation records older than slot `crystallized_state.last_state_recalculation_slot` * Empty the `active_state.pending_specials` list From aacaefbd2bc06629ada2d03cc70bb72ea183abc7 Mon Sep 17 00:00:00 2001 From: vbuterin Date: Sun, 14 Oct 2018 22:51:51 -0400 Subject: [PATCH 2/3] Update to make @djrtwo happy --- specs/beacon-chain.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/specs/beacon-chain.md b/specs/beacon-chain.md index 1113bc991..32a5e1126 100644 --- a/specs/beacon-chain.md +++ b/specs/beacon-chain.md @@ -565,14 +565,14 @@ def add_validator(validators: List[ValidatorRecord], ```python def exit_validator(index, crystallized_state, penalize, current_slot): - v = crystallized_state.validators[index] - v.exit_slot = current_slot + validator = crystallized_state.validators[index] + validator.exit_slot = current_slot if penalize: - v.status = PENALIZED - crystallized_state.deposits_penalized_in_period[current_slot // WITHDRAWAL_PERIOD] += v.balance + validator.status = PENALIZED + crystallized_state.deposits_penalized_in_period[current_slot // WITHDRAWAL_PERIOD] += validator.balance else: - v.status = PENDING_EXIT - add_validator_set_change_record(crystallized_state, index, v.pubkey, EXIT) + validator.status = PENDING_EXIT + add_validator_set_change_record(crystallized_state, index, validator.pubkey, EXIT) ``` ### Per-block processing @@ -679,14 +679,14 @@ In addition, validators with `status == PENALIZED` lose `B // reward_quotient + For each `SpecialRecord` `obj` in `active_state.pending_specials`: -* **[covers logouts]**: If `obj.kind == LOGOUT`, interpret `data[0]` as a validator index as an `int32` and `data[1]` as a signature. If `BLSVerify(pubkey=validators[data[0]].pubkey, msg=hash(LOGOUT_MESSAGE), sig=data[1])`, and `validators[i].status == ACTIVE`, run `exit_validator(data[0], crystallized_state, penalize=False, current_slot=current_slot)` -* **[covers `NO_DBL_VOTE`, `NO_SURROUND`, `NO_DBL_PROPOSE` slashing conditions]:** If `obj.kind == CASPER_SLASHING`, interpret `data[0]` as a list of concatenated `int32` values where each value represents an index into `validators`, `data[1]` as the data being signed and `data[2]` as an aggregate signature. Interpret `data[3:6]` similarly. Verify that both signatures are valid, that the two signatures are signing distinct data, and that they are either signing the same slot number, or that one surrounds the other (ie. `source1 < source2 < target2 < target1`). Let `indices` be the list of indices in both signatures; verify that its length is at least 1. For each validator index `v` in `indices`, if its `status` does not equal `PENALIZED`, then run `exit_validator(v, crystallized_state, penalize=True, current_slot=current_slot)` +* **[covers logouts]**: If `obj.kind == LOGOUT`, interpret `data[0]` as a validator index as an `int32` and `data[1]` as a signature. If `BLSVerify(pubkey=validators[data[0]].pubkey, msg=hash(LOGOUT_MESSAGE), sig=data[1])`, and `validators[i].status == ACTIVE`, run `exit_validator(data[0], crystallized_state, penalize=False, current_slot=block.slot)` +* **[covers `NO_DBL_VOTE`, `NO_SURROUND`, `NO_DBL_PROPOSE` slashing conditions]:** If `obj.kind == CASPER_SLASHING`, interpret `data[0]` as a list of concatenated `int32` values where each value represents an index into `validators`, `data[1]` as the data being signed and `data[2]` as an aggregate signature. Interpret `data[3:6]` similarly. Verify that both signatures are valid, that the two signatures are signing distinct data, and that they are either signing the same slot number, or that one surrounds the other (ie. `source1 < source2 < target2 < target1`). Let `indices` be the list of indices in both signatures; verify that its length is at least 1. For each validator index `v` in `indices`, if its `status` does not equal `PENALIZED`, then run `exit_validator(v, crystallized_state, penalize=True, current_slot=block.slot)` * **[covers RANDAO updates]**: If `obj.kind == RANDAO_REVEAL`, interpret `data[0]` as an integer and `data[1]` as a hash32. Set `validators[data[0]].randao_commitment = data[1]`. #### Finally... -* If the balance of any validator with index `v` is less than `MIN_ONLINE_DEPOSIT_SIZE`, then run `exit_validator(v, crystallized_state, penalize=False, current_slot=current_slot)` +* For any validator with index `v` with balance is less than `MIN_ONLINE_DEPOSIT_SIZE` and status `ACTIVE`, run `exit_validator(v, crystallized_state, penalize=False, current_slot=block.slot)` * Set `crystallized_state.last_state_recalculation_slot += CYCLE_LENGTH` * Remove all attestation records older than slot `crystallized_state.last_state_recalculation_slot` * Empty the `active_state.pending_specials` list From 0e1c73325450b72adbe86d9ba4acecffa6d22bae Mon Sep 17 00:00:00 2001 From: Danny Ryan Date: Mon, 15 Oct 2018 10:22:29 -0500 Subject: [PATCH 3/3] small typo --- specs/beacon-chain.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/specs/beacon-chain.md b/specs/beacon-chain.md index 32a5e1126..197d14b2c 100644 --- a/specs/beacon-chain.md +++ b/specs/beacon-chain.md @@ -686,7 +686,7 @@ For each `SpecialRecord` `obj` in `active_state.pending_specials`: #### Finally... -* For any validator with index `v` with balance is less than `MIN_ONLINE_DEPOSIT_SIZE` and status `ACTIVE`, run `exit_validator(v, crystallized_state, penalize=False, current_slot=block.slot)` +* For any validator with index `v` with balance less than `MIN_ONLINE_DEPOSIT_SIZE` and status `ACTIVE`, run `exit_validator(v, crystallized_state, penalize=False, current_slot=block.slot)` * Set `crystallized_state.last_state_recalculation_slot += CYCLE_LENGTH` * Remove all attestation records older than slot `crystallized_state.last_state_recalculation_slot` * Empty the `active_state.pending_specials` list