Updated the PR to include deposits
Includes https://github.com/ethereum/eth2.0-specs/issues/71#issuecomment-435837594
This commit is contained in:
parent
2fedaf0824
commit
20358f8d18
|
@ -42,6 +42,7 @@ The primary source of load on the beacon chain are "attestations". Attestations
|
||||||
| `RANDAO_SLOTS_PER_LAYER` | 2**12 (= 4096) | slots | ~18 hours |
|
| `RANDAO_SLOTS_PER_LAYER` | 2**12 (= 4096) | slots | ~18 hours |
|
||||||
| `SQRT_E_DROP_TIME` | 2**16 (= 65,536) | slots | ~12 days |
|
| `SQRT_E_DROP_TIME` | 2**16 (= 65,536) | slots | ~12 days |
|
||||||
| `WITHDRAWAL_PERIOD` | 2**19 (= 524,288) | slots | ~97 days |
|
| `WITHDRAWAL_PERIOD` | 2**19 (= 524,288) | slots | ~97 days |
|
||||||
|
| `DELETION_PERIOD` | 2**21 (= 2,097,152) | slots | ~1.06 years |
|
||||||
| `BASE_REWARD_QUOTIENT` | 2**15 (= 32,768) | — |
|
| `BASE_REWARD_QUOTIENT` | 2**15 (= 32,768) | — |
|
||||||
| `MAX_VALIDATOR_CHURN_QUOTIENT` | 2**5 (= 32) | — |
|
| `MAX_VALIDATOR_CHURN_QUOTIENT` | 2**5 (= 32) | — |
|
||||||
| `POW_HASH_VOTING_PERIOD` | 2**10 (=1024) | - |
|
| `POW_HASH_VOTING_PERIOD` | 2**10 (=1024) | - |
|
||||||
|
@ -98,8 +99,8 @@ A `BeaconBlock` has the following fields:
|
||||||
'slot': 'uint64',
|
'slot': 'uint64',
|
||||||
# Proposer RANDAO reveal
|
# Proposer RANDAO reveal
|
||||||
'randao_reveal': 'hash32',
|
'randao_reveal': 'hash32',
|
||||||
# Recent PoW chain reference (block hash)
|
# Recent PoW chain reference (receipt root)
|
||||||
'candidate_pow_hash_chain_tip': 'hash32',
|
'candidate_pow_receipt_root': 'hash32',
|
||||||
# Skip list of previous beacon block hashes
|
# Skip list of previous beacon block hashes
|
||||||
# i'th item is the most recent ancestor who's slot is a multiple of 2**i for i = 0, ..., 31
|
# i'th item is the most recent ancestor who's slot is a multiple of 2**i for i = 0, ..., 31
|
||||||
'ancestor_hashes': ['hash32'],
|
'ancestor_hashes': ['hash32'],
|
||||||
|
@ -213,10 +214,9 @@ The `CrystallizedState` has the following fields:
|
||||||
# Genesis time
|
# Genesis time
|
||||||
'genesis_time': 'hash32',
|
'genesis_time': 'hash32',
|
||||||
# PoW chain reference
|
# PoW chain reference
|
||||||
'known_pow_hash_chain_tip': 'hash32',
|
'known_pow_receipt_root': 'hash32',
|
||||||
'processed_pow_hash_chain_tip': 'hash32',
|
'candidate_pow_receipt_root': 'hash32',
|
||||||
'candidate_pow_hash_chain_tip': 'hash32',
|
'candidate_pow_receipt_root_votes': 'uint64',
|
||||||
'candidate_pow_hash_chain_tip_votes': 'uint64',
|
|
||||||
# Parameters relevant to hard forks / versioning.
|
# Parameters relevant to hard forks / versioning.
|
||||||
# Should be updated only by hard forks.
|
# Should be updated only by hard forks.
|
||||||
'pre_fork_version': 'uint32',
|
'pre_fork_version': 'uint32',
|
||||||
|
@ -498,23 +498,32 @@ def int_sqrt(n: int) -> int:
|
||||||
The beacon chain is initialized when a condition is met inside a contract on the existing PoW chain. This contract's code in Vyper is as follows:
|
The beacon chain is initialized when a condition is met inside a contract on the existing PoW chain. This contract's code in Vyper is as follows:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
HashChainValue: event({prev_tip: bytes32, data: bytes[2048], value: wei_value, total_deposit_count: int128})
|
HashChainValue: event({prev_tip: bytes32, data: bytes[2048], value: wei_value, time: timestamp, total_deposit_count: int128})
|
||||||
ChainStart: event({hash_chain_tip: bytes32, time: timestamp})
|
ChainStart: event({hash_chain_tip: bytes32, time: timestamp})
|
||||||
|
|
||||||
hash_chain_tip: public(bytes32)
|
receipt_tree: bytes32[int128]
|
||||||
total_deposit_count: int128
|
total_deposit_count: int128
|
||||||
|
|
||||||
@payable
|
@payable
|
||||||
@public
|
@public
|
||||||
def deposit(data: bytes[2048]):
|
def deposit(data: bytes[2048]):
|
||||||
log.HashChainValue(self.hash_chain_tip, data, msg.value, self.total_deposit_count)
|
log.HashChainValue(self.receipt_tree[1], data, msg.value, block.timestamp, self.total_deposit_count)
|
||||||
|
index:int128 = self.total_deposit_count + 2**32
|
||||||
|
self.receipt_tree[index] = sha3(concat(data, as_bytes32(msg.value), as_bytes32(block.timestamp))
|
||||||
|
for i in range(32):
|
||||||
|
index //= 2
|
||||||
|
self.receipt_tree[index] = sha3(concat(self.receipt_tree[index * 2], self.receipt_tree[index * 2 + 1]))
|
||||||
self.total_deposit_count += 1
|
self.total_deposit_count += 1
|
||||||
self.hash_chain_tip = sha3(concat(self.hash_chain_tip, data, as_bytes32(msg.value), as_bytes32(self.total_deposit_count)))
|
|
||||||
if self.total_deposit_count == 16384:
|
if self.total_deposit_count == 16384:
|
||||||
log.ChainStart(self.hash_chain_tip, block.timestamp)
|
log.ChainStart(self.receipt_tree[1], block.timestamp)
|
||||||
|
|
||||||
|
@public
|
||||||
|
@constant
|
||||||
|
def get_receipt_root() -> bytes32:
|
||||||
|
return self.receipt_tree[1]
|
||||||
```
|
```
|
||||||
|
|
||||||
The contract is at address `DEPOSIT_CONTRACT_ADDRESS`. When a user wishes to move their ETH from the 1.0 chain to the 2.0 chain, they should call the `deposit` function, sending along 32 ETH and providing as `data` a SimpleSerialize'd object of the form:
|
The contract is at address `DEPOSIT_CONTRACT_ADDRESS`. When a user wishes to move their ETH from the 1.0 chain to the 2.0 chain, they should call the `deposit` function, sending along 32 ETH and providing as `data` a SimpleSerialize'd `DepositParams` object of the form:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
{
|
{
|
||||||
|
@ -627,8 +636,9 @@ def add_validator(validators: List[ValidatorRecord],
|
||||||
current_slot: int) -> int:
|
current_slot: int) -> int:
|
||||||
# if following assert fails, validator induction failed
|
# if following assert fails, validator induction failed
|
||||||
# move on to next validator registration log
|
# move on to next validator registration log
|
||||||
|
signed_message = as_bytes32(pubkey) + as_bytes2(withdrawal_shard) + withdrawal_address + randao_commitment
|
||||||
assert BLSVerify(pub=pubkey,
|
assert BLSVerify(pub=pubkey,
|
||||||
msg=hash(pubkey),
|
msg=hash(signed_message),
|
||||||
sig=proof_of_possession)
|
sig=proof_of_possession)
|
||||||
rec = ValidatorRecord(
|
rec = ValidatorRecord(
|
||||||
pubkey=pubkey,
|
pubkey=pubkey,
|
||||||
|
@ -780,6 +790,7 @@ For each `SpecialRecord` `obj` in `active_state.pending_specials`:
|
||||||
* **[covers logouts]**: If `obj.kind == LOGOUT`, interpret `data[0]` as a validator index as an `uint32` and `data[1]` as a signature. If `BLSVerify(pubkey=validators[data[0]].pubkey, msg=hash(LOGOUT_MESSAGE + bytes8(fork_version)), sig=data[1])`, where `fork_version = pre_fork_version if slot < fork_slot_number else post_fork_version`, and `validators[i].status == ACTIVE`, run `exit_validator(data[0], crystallized_state, penalize=False, current_slot=block.slot)`
|
* **[covers logouts]**: If `obj.kind == LOGOUT`, interpret `data[0]` as a validator index as an `uint32` and `data[1]` as a signature. If `BLSVerify(pubkey=validators[data[0]].pubkey, msg=hash(LOGOUT_MESSAGE + bytes8(fork_version)), sig=data[1])`, where `fork_version = pre_fork_version if slot < fork_slot_number else post_fork_version`, 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 `uint32` 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 `NO_DBL_VOTE`, `NO_SURROUND`, `NO_DBL_PROPOSE` slashing conditions]:** If `obj.kind == CASPER_SLASHING`, interpret `data[0]` as a list of concatenated `uint32` 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]`.
|
* **[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]`.
|
||||||
|
* **[covers deposits]**: If `obj.kind == DEPOSIT_PROOF`, interpret `data[0]` as being a Merkle branch from a deposit object to the `known_pow_receipt_root` (hashes in order lower to higher, concatenated), `data[1]` as being the index in the tree, and `data[2]` as being the deposit object itself, having the format `concat(data, as_bytes32(msg.value), as_bytes32(block.timestamp)` where `data` itself is a `DepositParams` object. Run `add_validator(validators, data.pubkey, data.proof_of_possession, data.withdrawal_shard, data.withdrawal_address, data.randao_commitment, PENDING_ACTIVATION, block.slot)`.
|
||||||
|
|
||||||
#### Finally...
|
#### Finally...
|
||||||
|
|
||||||
|
@ -811,7 +822,7 @@ A validator set change can happen after a state recalculation if all of the foll
|
||||||
Then, run the following algorithm to update the validator set:
|
Then, run the following algorithm to update the validator set:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def change_validators(validators: List[ValidatorRecord]) -> None:
|
def change_validators(validators: List[ValidatorRecord], current_slot) -> None:
|
||||||
# The active validator set
|
# The active validator set
|
||||||
active_validators = get_active_validator_indices(validators)
|
active_validators = get_active_validator_indices(validators)
|
||||||
# The total balance of active validators
|
# The total balance of active validators
|
||||||
|
@ -855,15 +866,22 @@ def change_validators(validators: List[ValidatorRecord]) -> None:
|
||||||
)
|
)
|
||||||
# Separate loop to withdraw validators that have been logged out for long enough, and
|
# Separate loop to withdraw validators that have been logged out for long enough, and
|
||||||
# calculate their penalties if they were slashed
|
# calculate their penalties if they were slashed
|
||||||
for i in range(len(validators)):
|
i = 0
|
||||||
|
while i < len(validators):
|
||||||
if validators[i].status in (PENDING_WITHDRAW, PENALIZED) and current_slot >= validators[i].exit_slot + WITHDRAWAL_PERIOD:
|
if validators[i].status in (PENDING_WITHDRAW, PENALIZED) and current_slot >= validators[i].exit_slot + WITHDRAWAL_PERIOD:
|
||||||
if validators[i].status == PENALIZED:
|
if validators[i].status == PENALIZED:
|
||||||
validators[i].balance -= validators[i].balance * min(total_penalties * 3, total_balance) // total_balance
|
validators[i].balance -= validators[i].balance * min(total_penalties * 3, total_balance) // total_balance
|
||||||
validators[i].status = WITHDRAWN
|
validators[i].status = WITHDRAWN
|
||||||
|
validators[i].exit_slot = current_slot
|
||||||
|
|
||||||
withdraw_amount = validators[i].balance
|
withdraw_amount = validators[i].balance
|
||||||
...
|
...
|
||||||
# STUB: withdraw to shard chain
|
# STUB: withdraw to shard chain
|
||||||
|
if validators[i].status == WITHDRAWN and current_slot >= validators[i].exit_slot + DELETION_PERIOD:
|
||||||
|
validators.pop(i)
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Finally:
|
Finally:
|
||||||
|
|
Loading…
Reference in New Issue