Merge pull request #162 from ethereum/vbuterin-patch-7

Only increment total_deposit_count for 32 ETH deposits from PoW chain
This commit is contained in:
Danny Ryan 2018-11-27 13:52:55 -06:00 committed by GitHub
commit 3253936517
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -34,9 +34,11 @@ The primary source of load on the beacon chain are "attestations". Attestations
| --- | --- | :---: | - | | --- | --- | :---: | - |
| `SHARD_COUNT` | 2**10 (= 1,024)| shards | | `SHARD_COUNT` | 2**10 (= 1,024)| shards |
| `DEPOSIT_SIZE` | 2**5 (= 32) | ETH | | `DEPOSIT_SIZE` | 2**5 (= 32) | ETH |
| `MIN_TOPUP_SIZE` | 1 | ETH |
| `MIN_ONLINE_DEPOSIT_SIZE` | 2**4 (= 16) | ETH | | `MIN_ONLINE_DEPOSIT_SIZE` | 2**4 (= 16) | ETH |
| `GWEI_PER_ETH` | 10**9 | Gwei/ETH | | `GWEI_PER_ETH` | 10**9 | Gwei/ETH |
| `DEPOSIT_CONTRACT_ADDRESS` | **TBD** | - | | `DEPOSIT_CONTRACT_ADDRESS` | **TBD** | - |
| `DEPOSITS_FOR_CHAIN_START` | 2**14 (= 16,384) | deposits |
| `TARGET_COMMITTEE_SIZE` | 2**8 (= 256) | validators | | `TARGET_COMMITTEE_SIZE` | 2**8 (= 256) | validators |
| `SLOT_DURATION` | 6 | seconds | | `SLOT_DURATION` | 6 | seconds |
| `CYCLE_LENGTH` | 2**6 (= 64) | slots | ~6 minutes | | `CYCLE_LENGTH` | 2**6 (= 64) | slots | ~6 minutes |
@ -624,31 +626,39 @@ 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
DEPOSITS_FOR_CHAIN_START: constant(uint256) = 2**14
DEPOSIT_SIZE: constant(uint256) = 32 # ETH
MIN_TOPUP_SIZE: constant(uint256) = 1 # ETH
GWEI_PER_ETH: constant(uint256) = 10**9
POW_CONTRACT_MERKLE_TREE_DEPTH: constant(uint256) = 32
SECONDS_PER_DAY: constant(uint256) = 86400 SECONDS_PER_DAY: constant(uint256) = 86400
POW_CONTRACT_MERKLE_TREE_DEPTH: constant(int128) = 32
HashChainValue: event({previous_receipt_root: bytes32, data: bytes[2064], total_deposit_count: int128}) HashChainValue: event({previous_receipt_root: bytes32, data: bytes[2064], total_deposit_count: uint256})
ChainStart: event({receipt_root: bytes32, time: bytes[8]}) ChainStart: event({receipt_root: bytes32, time: bytes[8]})
receipt_tree: bytes32[int128] receipt_tree: bytes32[uint256]
total_deposit_count: int128 total_deposit_count: uint256
@payable @payable
@public @public
def deposit(deposit_params: bytes[2048]): def deposit(deposit_params: bytes[2048]):
index:int128 = self.total_deposit_count + 2**POW_CONTRACT_MERKLE_TREE_DEPTH index: uint256 = self.total_deposit_count + 2**POW_CONTRACT_MERKLE_TREE_DEPTH
msg_gwei_bytes8: bytes[8] = slice(concat("", convert(msg.value / 10**9, bytes32)), start=24, len=8) msg_gwei_bytes8: bytes[8] = slice(concat("", convert(msg.value / GWEI_PER_ETH, bytes32)), start=24, len=8)
timestamp_bytes8: bytes[8] = slice(concat("", convert(block.timestamp, bytes32)), start=24, len=8) timestamp_bytes8: bytes[8] = slice(concat("", convert(block.timestamp, bytes32)), start=24, len=8)
deposit_data: bytes[2064] = concat(deposit_params, msg_gwei_bytes8, timestamp_bytes8) deposit_data: bytes[2064] = concat(msg_gwei_bytes8, timestamp_bytes8, deposit_params)
log.HashChainValue(self.receipt_tree[1], deposit_data, self.total_deposit_count) log.HashChainValue(self.receipt_tree[1], deposit_data, self.total_deposit_count)
self.receipt_tree[index] = sha3(deposit_data) self.receipt_tree[index] = sha3(deposit_data)
for i in range(POW_CONTRACT_MERKLE_TREE_DEPTH): for i in range(32): # POW_CONTRACT_MERKLE_TREE_DEPTH (range of constant var not yet supported)
index /= 2 index /= 2
self.receipt_tree[index] = sha3(concat(self.receipt_tree[index * 2], self.receipt_tree[index * 2 + 1])) self.receipt_tree[index] = sha3(concat(self.receipt_tree[index * 2], self.receipt_tree[index * 2 + 1]))
assert msg.value >= as_wei_value(MIN_TOPUP_SIZE, "ether")
assert msg.value <= as_wei_value(DEPOSIT_SIZE, "ether")
if msg.value == as_wei_value(DEPOSIT_SIZE, "ether"):
self.total_deposit_count += 1 self.total_deposit_count += 1
if self.total_deposit_count == 16384: if self.total_deposit_count == DEPOSITS_FOR_CHAIN_START:
timestamp_day_boundary: uint256 = as_unitless_number(block.timestamp) - as_unitless_number(block.timestamp) % SECONDS_PER_DAY + SECONDS_PER_DAY timestamp_day_boundary: uint256 = as_unitless_number(block.timestamp) - as_unitless_number(block.timestamp) % SECONDS_PER_DAY + SECONDS_PER_DAY
timestamp_day_boundary_bytes8: bytes[8] = slice(concat("", convert(timestamp_day_boundary, bytes32)), start=24, len=8) timestamp_day_boundary_bytes8: bytes[8] = slice(concat("", convert(timestamp_day_boundary, bytes32)), start=24, len=8)
log.ChainStart(self.receipt_tree[1], timestamp_day_boundary_bytes8) log.ChainStart(self.receipt_tree[1], timestamp_day_boundary_bytes8)
@ -657,9 +667,10 @@ def deposit(deposit_params: bytes[2048]):
@constant @constant
def get_receipt_root() -> bytes32: def get_receipt_root() -> bytes32:
return self.receipt_tree[1] return self.receipt_tree[1]
``` ```
The contract is at address `DEPOSIT_CONTRACT_ADDRESS`. When a user wishes to become a validator by moving 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 `deposit_params` a SimpleSerialize'd `DepositParams` object of the form: The contract is at address `DEPOSIT_CONTRACT_ADDRESS`. When a user wishes to become a validator by moving their ETH from the 1.0 chain to the 2.0 chain, they should call the `deposit` function, sending along `DEPOSIT_SIZE` ETH and providing as `deposit_params` a SimpleSerialize'd `DepositParams` object of the form:
```python ```python
{ {
@ -703,7 +714,7 @@ def on_startup(current_validators: List[ValidatorRecord],
processed_pow_receipt_root: Hash32) -> BeaconState: processed_pow_receipt_root: Hash32) -> BeaconState:
# Induct validators # Induct validators
validators = [] validators = []
for pubkey, proof_of_possession, withdrawal_credentials, \ for pubkey, deposit_size, proof_of_possession, withdrawal_credentials, \
randao_commitment in initial_validator_entries: randao_commitment in initial_validator_entries:
validators, _ = get_new_validators( validators, _ = get_new_validators(
current_validators=validators, current_validators=validators,
@ -713,6 +724,7 @@ def on_startup(current_validators: List[ValidatorRecord],
fork_slot_number=2**64 - 1, fork_slot_number=2**64 - 1,
), ),
pubkey=pubkey, pubkey=pubkey,
deposit_size=deposit_size,
proof_of_possession=proof_of_possession, proof_of_possession=proof_of_possession,
withdrawal_credentials=withdrawal_credentials, withdrawal_credentials=withdrawal_credentials,
randao_commitment=randao_commitment, randao_commitment=randao_commitment,
@ -759,7 +771,7 @@ def on_startup(current_validators: List[ValidatorRecord],
return state return state
``` ```
The `add_validator` routine is defined below. The `add_or_topup_validator` routine is defined below.
### Routine for adding a validator ### Routine for adding a validator
@ -795,13 +807,14 @@ def get_domain(fork_data: ForkData,
def get_new_validators(current_validators: List[ValidatorRecord], def get_new_validators(current_validators: List[ValidatorRecord],
fork_data: ForkData, fork_data: ForkData,
pubkey: int, pubkey: int,
deposit_size: int,
proof_of_possession: bytes, proof_of_possession: bytes,
withdrawal_credentials: Hash32, withdrawal_credentials: Hash32,
randao_commitment: Hash32, randao_commitment: Hash32,
status: int, status: int,
current_slot: int) -> Tuple[List[ValidatorRecord], int]: current_slot: int) -> Tuple[List[ValidatorRecord], int]:
# if following assert fails, validator induction failed # if any asserts fail, validator induction/topup failed
# move on to next validator registration log # move on to next validator deposit log
signed_message = bytes32(pubkey) + withdrawal_credentials + randao_commitment signed_message = bytes32(pubkey) + withdrawal_credentials + randao_commitment
assert BLSVerify( assert BLSVerify(
pub=pubkey, pub=pubkey,
@ -813,9 +826,13 @@ def get_new_validators(current_validators: List[ValidatorRecord],
DOMAIN_DEPOSIT DOMAIN_DEPOSIT
) )
) )
# Pubkey uniqueness
new_validators = copy.deepcopy(current_validators) new_validators = copy.deepcopy(current_validators)
assert pubkey not in [v.pubkey for v in current_validators] validator_pubkeys = [v.pubkey for v in new_validators]
# add new validator
if pubkey not in validator_pubkeys:
assert deposit_size == DEPOSIT_SIZE
rec = ValidatorRecord( rec = ValidatorRecord(
pubkey=pubkey, pubkey=pubkey,
withdrawal_credentials=withdrawal_credentials, withdrawal_credentials=withdrawal_credentials,
@ -826,22 +843,33 @@ def get_new_validators(current_validators: List[ValidatorRecord],
last_status_change_slot=current_slot, last_status_change_slot=current_slot,
exit_seq=0 exit_seq=0
) )
# Add the validator
index = min_empty_validator_index(current_validators) index = min_empty_validator(new_validators)
if index is None: if index is None:
new_validators.append(rec) new_validators.append(rec)
index = len(new_validators) - 1 index = len(new_validators) - 1
else: else:
new_validators[index] = rec new_validators[index] = rec
return new_validators, index
# topup existing validator
else:
index = validator_pubkeys.index(pubkey)
val = new_validators[index]
assert deposit_size >= MIN_TOPUP_SIZE
assert val.status != WITHDRAWN
assert val.withdrawal_credentials == withdrawal_credentials
val.balance += deposit_size
return new_validators, index return new_validators, index
``` ```
Now, to add a validator: Now, to add a validator or top up an existing validator's balance:
```python ```python
def add_validator(state: BeaconState, def add_or_topup_validator(state: BeaconState,
pubkey: int, pubkey: int,
deposit_size: int,
proof_of_possession: bytes, proof_of_possession: bytes,
withdrawal_credentials: Hash32, withdrawal_credentials: Hash32,
randao_commitment: Hash32, randao_commitment: Hash32,
@ -859,6 +887,7 @@ def add_validator(state: BeaconState,
fork_slot_number=state.fork_slot_number, fork_slot_number=state.fork_slot_number,
), ),
pubkey=pubkey, pubkey=pubkey,
deposit_size=deposit_size,
proof_of_possession=proof_of_possession, proof_of_possession=proof_of_possession,
withdrawal_credentials=withdrawal_credentials, withdrawal_credentials=withdrawal_credentials,
randao_commitment=randao_commitment, randao_commitment=randao_commitment,
@ -1068,9 +1097,9 @@ def verify_merkle_branch(leaf: Hash32, branch: [Hash32], depth: int, index: int,
return value == root return value == root
``` ```
Verify that `deposit_data.msg_value == DEPOSIT_SIZE` and `block.slot - (deposit_data.timestamp - state.genesis_time) // SLOT_DURATION < DELETION_PERIOD`. Verify that `block.slot - (deposit_data.timestamp - state.genesis_time) // SLOT_DURATION < DELETION_PERIOD`.
Run `add_validator(state, pubkey=deposit_data.deposit_params.pubkey, proof_of_possession=deposit_data.deposit_params.proof_of_possession, withdrawal_credentials=deposit_data.deposit_params.withdrawal_credentials, randao_commitment=deposit_data.deposit_params.randao_commitment, status=PENDING_ACTIVATION, current_slot=block.slot)`. Run `add_or_topup_validator(state, pupkey=deposit_data.deposit_params.pubkey, deposit_size=deposit_data.msg_value, proof_of_possession=deposit_data.deposit_params.proof_of_possession, withdrawal_credentials=deposit_data.deposit_params.withdrawal_credentials, randao_commitment=deposit_data.deposit_params.randao_commitment, status=PENDING_ACTIVATION, current_slot=block.slot)`.
## Cycle boundary processing ## Cycle boundary processing