Remove eth2 genesis in favour of genesis trigger
This commit is contained in:
parent
6f82480df2
commit
d1e589f11f
File diff suppressed because one or more lines are too long
|
@ -1,8 +1,5 @@
|
|||
MIN_DEPOSIT_AMOUNT: constant(uint256) = 1000000000 # Gwei
|
||||
FULL_DEPOSIT_AMOUNT: constant(uint256) = 32000000000 # Gwei
|
||||
CHAIN_START_FULL_DEPOSIT_THRESHOLD: constant(uint256) = 65536 # 2**16
|
||||
DEPOSIT_CONTRACT_TREE_DEPTH: constant(uint256) = 32
|
||||
SECONDS_PER_DAY: constant(uint256) = 86400
|
||||
MAX_64_BIT_VALUE: constant(uint256) = 18446744073709551615 # 2**64 - 1
|
||||
PUBKEY_LENGTH: constant(uint256) = 48 # bytes
|
||||
WITHDRAWAL_CREDENTIALS_LENGTH: constant(uint256) = 32 # bytes
|
||||
|
@ -16,13 +13,10 @@ Deposit: event({
|
|||
signature: bytes[96],
|
||||
merkle_tree_index: bytes[8],
|
||||
})
|
||||
Eth2Genesis: event({deposit_root: bytes32, deposit_count: bytes[8], time: bytes[8]})
|
||||
|
||||
zerohashes: bytes32[DEPOSIT_CONTRACT_TREE_DEPTH]
|
||||
branch: bytes32[DEPOSIT_CONTRACT_TREE_DEPTH]
|
||||
deposit_count: uint256
|
||||
full_deposit_count: uint256
|
||||
chainStarted: public(bool)
|
||||
|
||||
|
||||
@public
|
||||
|
@ -30,7 +24,6 @@ def __init__():
|
|||
for i in range(DEPOSIT_CONTRACT_TREE_DEPTH - 1):
|
||||
self.zerohashes[i+1] = sha256(concat(self.zerohashes[i], self.zerohashes[i]))
|
||||
|
||||
|
||||
@public
|
||||
@constant
|
||||
def to_little_endian_64(value: uint256) -> bytes[8]:
|
||||
|
@ -47,7 +40,6 @@ def to_little_endian_64(value: uint256) -> bytes[8]:
|
|||
|
||||
return slice(convert(y, bytes32), start=24, len=8)
|
||||
|
||||
|
||||
@public
|
||||
@constant
|
||||
def get_deposit_root() -> bytes32:
|
||||
|
@ -124,17 +116,3 @@ def deposit(pubkey: bytes[PUBKEY_LENGTH],
|
|||
signature,
|
||||
self.to_little_endian_64(index),
|
||||
)
|
||||
|
||||
if deposit_amount >= FULL_DEPOSIT_AMOUNT:
|
||||
self.full_deposit_count += 1
|
||||
if self.full_deposit_count == CHAIN_START_FULL_DEPOSIT_THRESHOLD:
|
||||
timestamp_day_boundary: uint256 = (
|
||||
as_unitless_number(block.timestamp) -
|
||||
as_unitless_number(block.timestamp) % SECONDS_PER_DAY +
|
||||
2 * SECONDS_PER_DAY
|
||||
)
|
||||
new_deposit_root: bytes32 = self.get_deposit_root()
|
||||
log.Eth2Genesis(new_deposit_root,
|
||||
self.to_little_endian_64(self.deposit_count),
|
||||
self.to_little_endian_64(timestamp_day_boundary))
|
||||
self.chainStarted = True
|
||||
|
|
|
@ -26,7 +26,6 @@ from .utils import (
|
|||
# Constants
|
||||
MIN_DEPOSIT_AMOUNT = 1000000000 # Gwei
|
||||
FULL_DEPOSIT_AMOUNT = 32000000000 # Gwei
|
||||
CHAIN_START_FULL_DEPOSIT_THRESHOLD = 65536 # 2**16
|
||||
DEPOSIT_CONTRACT_TREE_DEPTH = 32
|
||||
TWO_TO_POWER_OF_TREE_DEPTH = 2**DEPOSIT_CONTRACT_TREE_DEPTH
|
||||
|
||||
|
@ -63,28 +62,14 @@ def registration_contract(w3, tester):
|
|||
return registration_deployed
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def chain_start_full_deposit_thresholds():
|
||||
return [randint(1, 5), randint(6, 10), randint(11, 15)]
|
||||
|
||||
|
||||
@pytest.fixture(params=[0, 1, 2])
|
||||
def modified_registration_contract(
|
||||
request,
|
||||
w3,
|
||||
tester,
|
||||
chain_start_full_deposit_thresholds):
|
||||
# Set CHAIN_START_FULL_DEPOSIT_THRESHOLD to different threshold t
|
||||
tester):
|
||||
registration_code = get_deposit_contract_code()
|
||||
t = str(chain_start_full_deposit_thresholds[request.param])
|
||||
modified_registration_code = re.sub(
|
||||
r'CHAIN_START_FULL_DEPOSIT_THRESHOLD: constant\(uint256\) = [0-9]+',
|
||||
'CHAIN_START_FULL_DEPOSIT_THRESHOLD: constant(uint256) = ' + t,
|
||||
registration_code,
|
||||
)
|
||||
assert modified_registration_code != registration_code
|
||||
contract_bytecode = compiler.compile_code(modified_registration_code)['bytecode']
|
||||
contract_abi = compiler.mk_full_signature(modified_registration_code)
|
||||
contract_bytecode = compiler.compile_code(registration_code)['bytecode']
|
||||
contract_abi = compiler.mk_full_signature(registration_code)
|
||||
registration = w3.eth.contract(
|
||||
abi=contract_abi,
|
||||
bytecode=contract_bytecode)
|
||||
|
@ -94,11 +79,6 @@ def modified_registration_contract(
|
|||
address=tx_receipt.contractAddress,
|
||||
abi=contract_abi
|
||||
)
|
||||
setattr(
|
||||
registration_deployed,
|
||||
'chain_start_full_deposit_threshold',
|
||||
chain_start_full_deposit_thresholds[request.param]
|
||||
)
|
||||
return registration_deployed
|
||||
|
||||
|
||||
|
|
|
@ -184,53 +184,3 @@ def test_deposit_tree(registration_contract, w3, assert_tx_failed, deposit_input
|
|||
leaf_nodes.append(hash_tree_root_result)
|
||||
root = compute_merkle_root(leaf_nodes)
|
||||
assert root == registration_contract.functions.get_deposit_root().call()
|
||||
|
||||
|
||||
def test_chain_start(modified_registration_contract, w3, assert_tx_failed, deposit_input):
|
||||
t = getattr(modified_registration_contract, 'chain_start_full_deposit_threshold')
|
||||
# CHAIN_START_FULL_DEPOSIT_THRESHOLD is set to t
|
||||
min_deposit_amount = MIN_DEPOSIT_AMOUNT * eth_utils.denoms.gwei # in wei
|
||||
full_deposit_amount = FULL_DEPOSIT_AMOUNT * eth_utils.denoms.gwei
|
||||
log_filter = modified_registration_contract.events.Eth2Genesis.createFilter(
|
||||
fromBlock='latest',
|
||||
)
|
||||
|
||||
index_not_full_deposit = randint(0, t - 1)
|
||||
for i in range(t):
|
||||
if i == index_not_full_deposit:
|
||||
# Deposit with value below FULL_DEPOSIT_AMOUNT
|
||||
modified_registration_contract.functions.deposit(
|
||||
*deposit_input,
|
||||
).transact({"value": min_deposit_amount})
|
||||
logs = log_filter.get_new_entries()
|
||||
# Eth2Genesis event should not be triggered
|
||||
assert len(logs) == 0
|
||||
else:
|
||||
# Deposit with value FULL_DEPOSIT_AMOUNT
|
||||
modified_registration_contract.functions.deposit(
|
||||
*deposit_input,
|
||||
).transact({"value": full_deposit_amount})
|
||||
logs = log_filter.get_new_entries()
|
||||
# Eth2Genesis event should not be triggered
|
||||
assert len(logs) == 0
|
||||
|
||||
# Make 1 more deposit with value FULL_DEPOSIT_AMOUNT to trigger Eth2Genesis event
|
||||
modified_registration_contract.functions.deposit(
|
||||
*deposit_input,
|
||||
).transact({"value": full_deposit_amount})
|
||||
logs = log_filter.get_new_entries()
|
||||
assert len(logs) == 1
|
||||
timestamp = int(w3.eth.getBlock(w3.eth.blockNumber)['timestamp'])
|
||||
timestamp_day_boundary = timestamp + (86400 - timestamp % 86400) + 86400
|
||||
log = logs[0]['args']
|
||||
assert log['deposit_root'] == modified_registration_contract.functions.get_deposit_root().call()
|
||||
assert int.from_bytes(log['time'], byteorder='little') == timestamp_day_boundary
|
||||
assert modified_registration_contract.functions.chainStarted().call() is True
|
||||
|
||||
# Make 1 deposit with value FULL_DEPOSIT_AMOUNT and
|
||||
# check that Eth2Genesis event is not triggered
|
||||
modified_registration_contract.functions.deposit(
|
||||
*deposit_input,
|
||||
).transact({"value": full_deposit_amount})
|
||||
logs = log_filter.get_new_entries()
|
||||
assert len(logs) == 0
|
||||
|
|
|
@ -95,7 +95,7 @@
|
|||
- [`initiate_validator_exit`](#initiate_validator_exit)
|
||||
- [`slash_validator`](#slash_validator)
|
||||
- [Genesis](#genesis)
|
||||
- [`Eth2Genesis`](#eth2genesis)
|
||||
- [Genesis trigger](#genesis-trigger)
|
||||
- [Genesis state](#genesis-state)
|
||||
- [Genesis block](#genesis-block)
|
||||
- [Beacon chain state transition function](#beacon-chain-state-transition-function)
|
||||
|
@ -370,12 +370,12 @@ class PendingAttestation(Container):
|
|||
|
||||
```python
|
||||
class Eth1Data(Container):
|
||||
# Block hash
|
||||
block_hash: Bytes32
|
||||
# Root of the deposit tree
|
||||
deposit_root: Bytes32
|
||||
# Total number of deposits
|
||||
deposit_count: uint64
|
||||
# Block hash
|
||||
block_hash: Bytes32
|
||||
```
|
||||
|
||||
#### `HistoricalBatch`
|
||||
|
@ -1156,20 +1156,45 @@ def slash_validator(state: BeaconState,
|
|||
|
||||
## Genesis
|
||||
|
||||
### `Eth2Genesis`
|
||||
### Genesis trigger
|
||||
|
||||
When enough deposits of size `MAX_EFFECTIVE_BALANCE` have been made to the deposit contract an `Eth2Genesis` log is emitted triggering the genesis of the beacon chain. Let:
|
||||
Whenever the deposit contract emits a `Deposit` log call the function `is_genesis_trigger(deposits: List[Deposit], timestamp: uint64) -> bool` where:
|
||||
|
||||
* `eth2genesis` be the object corresponding to `Eth2Genesis`
|
||||
* `genesis_eth1_data` be object of type `Eth1Data` where
|
||||
* `genesis_eth1_data.deposit_root = eth2genesis.deposit_root`
|
||||
* `genesis_eth1_data.deposit_count = eth2genesis.deposit_count`
|
||||
* `genesis_eth1_data.block_hash` is the hash of the Ethereum 1.0 block that emitted the `Eth2Genesis` log
|
||||
* `genesis_deposits` be the object of type `List[Deposit]` with deposits ordered chronologically up to and including the deposit that triggered the `Eth2Genesis` log
|
||||
* `deposits` is the list of all deposits, ordered chronologically, up to and including the deposit triggering the latest `Deposit` log
|
||||
* `timestamp` is the Unix timestamp in the Ethereum 1.0 block that emitted the latest `Deposit` log
|
||||
|
||||
When `is_genesis_trigger(deposits, timestamp) == True` for the first time let:
|
||||
|
||||
* `genesis_deposits = deposits`
|
||||
* `genesis_time = timestamp % SECONDS_PER_DAY + 2 * SECONDS_PER_DAY` where `SECONDS_PER_DAY = 86400`
|
||||
* `genesis_eth1_data` be the object of type `Eth1Data` where:
|
||||
* `genesis_eth1_data.block_hash` is the block hash corresponding to `deposits`
|
||||
* `genesis_eth1_data.deposit_root` is the deposit root corresponding to `deposits`
|
||||
* `genesis_eth1_data.deposit_count = len(genesis_deposits)`
|
||||
|
||||
*Note*: The function `is_genesis_trigger` has yet to be agreed by the community, and can be updated as necessary. We define the following testing placeholder:
|
||||
|
||||
```python
|
||||
def is_genesis_trigger(deposits: List[Deposit], timestamp: uint64) -> bool:
|
||||
# Process deposits
|
||||
state = BeaconState()
|
||||
for deposit in deposits:
|
||||
process_deposit(state, deposit)
|
||||
|
||||
# Count active validators at genesis
|
||||
active_validator_count = 0
|
||||
for validator in state.validator_registry:
|
||||
if validator.effective_balance >= MAX_EFFECTIVE_BALANCE:
|
||||
active_validator_count += 1
|
||||
|
||||
# Check effective balance to trigger genesis
|
||||
GENESIS_EFFECTIVE_BALANCE = 2**21
|
||||
return active_validator_count * MAX_EFFECTIVE_BALANCE == GENESIS_EFFECTIVE_BALANCE
|
||||
```
|
||||
|
||||
### Genesis state
|
||||
|
||||
Let `genesis_state = get_genesis_beacon_state(genesis_deposits, eth2genesis.genesis_time, genesis_eth1_data)`.
|
||||
Let `genesis_state = get_genesis_beacon_state(genesis_deposits, genesis_time, genesis_eth1_data)`.
|
||||
|
||||
```python
|
||||
def get_genesis_beacon_state(deposits: List[Deposit], genesis_time: int, genesis_eth1_data: Eth1Data) -> BeaconState:
|
||||
|
@ -1246,7 +1271,7 @@ def process_slot(state: BeaconState) -> None:
|
|||
|
||||
### Epoch processing
|
||||
|
||||
Note: the `# @LabelHere` lines below are placeholders to show that code will be inserted here in a future phase.
|
||||
*Note*: the `# @LabelHere` lines below are placeholders to show that code will be inserted here in a future phase.
|
||||
|
||||
```python
|
||||
def process_epoch(state: BeaconState) -> None:
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
- [Table of contents](#table-of-contents)
|
||||
- [Introduction](#introduction)
|
||||
- [Constants](#constants)
|
||||
- [Gwei values](#gwei-values)
|
||||
- [Contract](#contract)
|
||||
- [Ethereum 1.0 deposit contract](#ethereum-10-deposit-contract)
|
||||
- [Arguments](#arguments)
|
||||
|
@ -17,7 +16,6 @@
|
|||
- [Amount](#amount)
|
||||
- [Event logs](#event-logs)
|
||||
- [`Deposit` logs](#deposit-logs)
|
||||
- [`Eth2Genesis` log](#eth2genesis-log)
|
||||
- [Vyper code](#vyper-code)
|
||||
|
||||
<!-- /TOC -->
|
||||
|
@ -28,19 +26,12 @@ This document represents the specification for the beacon chain deposit contract
|
|||
|
||||
## Constants
|
||||
|
||||
### Gwei values
|
||||
|
||||
| Name | Value | Unit |
|
||||
| - | - | - |
|
||||
| `FULL_DEPOSIT_AMOUNT` | `32 * 10**9` | Gwei |
|
||||
|
||||
### Contract
|
||||
|
||||
| Name | Value |
|
||||
| - | - |
|
||||
| `DEPOSIT_CONTRACT_ADDRESS` | **TBD** |
|
||||
| `DEPOSIT_CONTRACT_TREE_DEPTH` | `2**5` (= 32) |
|
||||
| `CHAIN_START_FULL_DEPOSIT_THRESHOLD` | `2**16` (= 65,536) |
|
||||
|
||||
## Ethereum 1.0 deposit contract
|
||||
|
||||
|
@ -62,7 +53,6 @@ The private key corresponding to `withdrawal_pubkey` will be required to initiat
|
|||
#### Amount
|
||||
|
||||
* A valid deposit amount should be at least `MIN_DEPOSIT_AMOUNT` in Gwei.
|
||||
* A deposit with an amount greater than or equal to `FULL_DEPOSIT_AMOUNT` in Gwei is considered as a full deposit.
|
||||
|
||||
## Event logs
|
||||
|
||||
|
@ -70,16 +60,6 @@ The private key corresponding to `withdrawal_pubkey` will be required to initiat
|
|||
|
||||
Every Ethereum 1.0 deposit, of size at least `MIN_DEPOSIT_AMOUNT`, emits a `Deposit` log for consumption by the beacon chain. The deposit contract does little validation, pushing most of the validator onboarding logic to the beacon chain. In particular, the proof of possession (a BLS12-381 signature) is not verified by the deposit contract.
|
||||
|
||||
### `Eth2Genesis` log
|
||||
|
||||
When `CHAIN_START_FULL_DEPOSIT_THRESHOLD` of full deposits have been made, the deposit contract emits the `Eth2Genesis` log. The beacon chain state may then be initialized by calling the `get_genesis_beacon_state` function (defined [here](./0_beacon-chain.md#genesis-state)) where:
|
||||
|
||||
* `genesis_time` equals `time` in the `Eth2Genesis` log
|
||||
* `latest_eth1_data.deposit_root` equals `deposit_root` in the `Eth2Genesis` log
|
||||
* `latest_eth1_data.deposit_count` equals `deposit_count` in the `Eth2Genesis` log
|
||||
* `latest_eth1_data.block_hash` equals the hash of the block that included the log
|
||||
* `genesis_validator_deposits` is a list of `Deposit` objects built according to the `Deposit` logs up to the deposit that triggered the `Eth2Genesis` log, processed in the order in which they were emitted (oldest to newest)
|
||||
|
||||
## Vyper code
|
||||
|
||||
The source for the Vyper contract lives in a [separate repository](https://github.com/ethereum/deposit_contract) at [https://github.com/ethereum/deposit_contract/blob/master/deposit_contract/contracts/validator_registration.v.py](https://github.com/ethereum/deposit_contract/blob/master/deposit_contract/contracts/validator_registration.v.py).
|
||||
|
|
Loading…
Reference in New Issue