Chain initialization and main chain block inclusion

This commit is contained in:
vbuterin 2018-10-31 03:44:18 -04:00 committed by GitHub
parent e9719195ef
commit 2fedaf0824
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 64 additions and 3 deletions

View File

@ -35,7 +35,7 @@ The primary source of load on the beacon chain are "attestations". Attestations
| `MIN_ONLINE_DEPOSIT_SIZE` | 2**4 (= 16) | ETH |
| `GWEI_PER_ETH` | 10**9 | Gwei/ETH |
| `MIN_COMMITTEE_SIZE` | 2**7 (= 128) | validators |
| `GENESIS_TIME` | **TBD** | seconds |
| `DEPOSIT_CONTRACT_ADDRESS` | **TBD** | - |
| `SLOT_DURATION` | 2**4 (= 16) | seconds |
| `CYCLE_LENGTH` | 2**6 (= 64) | slots | ~17 minutes |
| `MIN_VALIDATOR_SET_CHANGE_INTERVAL` | 2**8 (= 256) | slots | ~1.1 hours |
@ -44,6 +44,7 @@ The primary source of load on the beacon chain are "attestations". Attestations
| `WITHDRAWAL_PERIOD` | 2**19 (= 524,288) | slots | ~97 days |
| `BASE_REWARD_QUOTIENT` | 2**15 (= 32,768) | — |
| `MAX_VALIDATOR_CHURN_QUOTIENT` | 2**5 (= 32) | — |
| `POW_HASH_VOTING_PERIOD` | 2**10 (=1024) | - |
| `LOGOUT_MESSAGE` | `"LOGOUT"` | — |
| `INITIAL_FORK_VERSION` | 0 | — |
@ -98,7 +99,7 @@ A `BeaconBlock` has the following fields:
# Proposer RANDAO reveal
'randao_reveal': 'hash32',
# Recent PoW chain reference (block hash)
'pow_chain_reference': 'hash32',
'candidate_pow_hash_chain_tip': 'hash32',
# 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
'ancestor_hashes': ['hash32'],
@ -209,6 +210,13 @@ The `CrystallizedState` has the following fields:
'deposits_penalized_in_period': ['uint32'],
# Hash chain of validator set changes (for light clients to easily track deltas)
'validator_set_delta_hash_chain': 'hash32'
# Genesis time
'genesis_time': 'hash32',
# PoW chain reference
'known_pow_hash_chain_tip': 'hash32',
'processed_pow_hash_chain_tip': 'hash32',
'candidate_pow_hash_chain_tip': 'hash32',
'candidate_pow_hash_chain_tip_votes': 'uint64',
# Parameters relevant to hard forks / versioning.
# Should be updated only by hard forks.
'pre_fork_version': 'uint32',
@ -485,13 +493,51 @@ def int_sqrt(n: int) -> int:
return x
```
### PoW chain contract
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
HashChainValue: event({prev_tip: bytes32, data: bytes[2048], value: wei_value, total_deposit_count: int128})
ChainStart: event({hash_chain_tip: bytes32, time: timestamp})
hash_chain_tip: public(bytes32)
total_deposit_count: int128
@payable
@public
def deposit(data: bytes[2048]):
log.HashChainValue(self.hash_chain_tip, data, msg.value, self.total_deposit_count)
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:
log.ChainStart(self.hash_chain_tip, block.timestamp)
```
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:
```python
{
'pubkey': 'int256',
'proof_of_possession': ['int256'],
'withdrawal_shard': 'int64',
'withdrawal_address`: 'bytes20',
'randao_commitment`: 'hash32',
}
```
If they wish to deposit more than 32 ETH, they would need to make multiple calls. When the contract publishes a `ChainStart` log, this initializes the chain, calling `on_startup` with:
* `initial_validator_entries` equal to the list of data records published as HashChainValue logs so far, in the order in which they were published (oldest to newest).
* `genesis_time` equal to the `time` value published in the log
* `pow_hash_chain_tip` equal to the `hash_chain_tip` value published in the log
### On startup
Run the following code:
```python
def on_startup(initial_validator_entries: List[Any]) -> Tuple[CrystallizedState, ActiveState]:
def on_startup(initial_validator_entries: List[Any], genesis_time: uint64, pow_hash_chain_tip: Hash32) -> Tuple[CrystallizedState, ActiveState]:
# Induct validators
validators = []
for pubkey, proof_of_possession, withdrawal_shard, withdrawal_address, \
@ -527,6 +573,11 @@ def on_startup(initial_validator_entries: List[Any]) -> Tuple[CrystallizedState,
shard_and_committee_for_slots=x + x,
deposits_penalized_in_period=[],
validator_set_delta_hash_chain=bytes([0] * 32), # stub
genesis_time=genesis_time,
known_pow_hash_chain_tip=pow_hash_chain_tip,
processed_pow_hash_chain_tip=pow_hash_chain_tip,
candidate_pow_hash_chain_tip=bytes([0] * 32),
candidate_pow_hash_chain_tip_votes=0,
pre_fork_version=INITIAL_FORK_VERSION,
post_fork_version=INITIAL_FORK_VERSION,
fork_slot_number=0
@ -739,6 +790,16 @@ For each `SpecialRecord` `obj` in `active_state.pending_specials`:
* Set `active_state.recent_block_hashes = active_state.recent_block_hashes[CYCLE_LENGTH:]`
* Set `shard_and_committee_for_slots[:CYCLE_LENGTH] = shard_and_committee_for_slots[CYCLE_LENGTH:]`
### PoW chain related rules
If `block.slot % POW_HASH_VOTING_PERIOD == 0`, then:
* If `crystallized_state.candidate_hash_chain_tip_votes * 3 >= POW_HASH_VOTING_PERIOD * 2`, set `crystallized_state.hash_chain_tip = crystallized_state.candidate_hash_chain_tip`
* Set `crystallized_state.candidate_hash_chain_tip = block.candidate_pow_hash_chain_tip`
* Set `crystallized_state.candidate_hash_chain_tip_votes = 0`
Otherwise, if `block.candidate_pow_hash_chain_tip = crystallized_state.candidate_pow_hash_chain_tip`, set `crystallized_state.candidate_hash_chain_tip_votes += 1`.
### Validator set change
A validator set change can happen after a state recalculation if all of the following criteria are satisfied: