Merge pull request #758 from ethereum/vbuterin-patch-11

Mandatory deposits
This commit is contained in:
Danny Ryan 2019-03-19 17:12:19 -06:00 committed by GitHub
commit 251f4ba0f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 186 additions and 2 deletions

View File

@ -315,6 +315,8 @@ The types are defined topologically to aid in facilitating an executable version
{
# Root of the deposit tree
'deposit_root': 'bytes32',
# Total number of deposits
'deposit_count': 'uint64',
# Block hash
'block_hash': 'bytes32',
}
@ -1435,6 +1437,7 @@ When sufficiently many full deposits have been made the deposit contract emits t
* `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)
@ -1458,6 +1461,7 @@ When enough full deposits have been made to the deposit contract, an `Eth2Genesi
* Let `genesis_time` be the timestamp specified in the `Eth2Genesis` log.
* Let `genesis_eth1_data` be the `Eth1Data` object where:
* `genesis_eth1_data.deposit_root` is the `deposit_root` contained in the `Eth2Genesis` log.
* `genesis_eth1_data.deposit_count` is the `deposit_count` contained in the `Eth2Genesis` log.
* `genesis_eth1_data.block_hash` is the hash of the Ethereum 1.0 block that emitted the `Eth2Genesis` log.
* Let `genesis_state = get_genesis_beacon_state(genesis_validator_deposits, genesis_time, genesis_eth1_data)`.
* Let `genesis_block = get_empty_block()`.
@ -1476,6 +1480,7 @@ def get_empty_block() -> BeaconBlock:
randao_reveal=EMPTY_SIGNATURE,
eth1_data=Eth1Data(
deposit_root=ZERO_HASH,
deposit_count=0,
block_hash=ZERO_HASH,
),
proposer_slashings=[],
@ -2414,7 +2419,7 @@ def process_attestation(state: BeaconState, attestation: Attestation) -> None:
##### Deposits
Verify that `len(block.body.deposits) <= MAX_DEPOSITS`.
Verify that `len(block.body.deposits) == min(MAX_DEPOSITS, latest_eth1_data.deposit_count - state.deposit_index)`.
For each `deposit` in `block.body.deposits`, run `process_deposit(state, deposit)`.

View File

@ -0,0 +1,132 @@
from copy import deepcopy
import pytest
import build.phase0.spec as spec
from build.phase0.spec import (
Deposit,
process_deposit,
)
from tests.phase0.helpers import (
build_deposit,
)
# mark entire file as 'voluntary_exits'
pytestmark = pytest.mark.voluntary_exits
def test_success(state, deposit_data_leaves, pubkeys, privkeys):
pre_state = deepcopy(state)
index = len(deposit_data_leaves)
pubkey = pubkeys[index]
privkey = privkeys[index]
deposit, root, deposit_data_leaves = build_deposit(
pre_state,
deposit_data_leaves,
pubkey,
privkey,
spec.MAX_DEPOSIT_AMOUNT,
)
pre_state.latest_eth1_data.deposit_root = root
pre_state.latest_eth1_data.deposit_count = len(deposit_data_leaves)
post_state = deepcopy(pre_state)
process_deposit(post_state, deposit)
assert len(post_state.validator_registry) == len(state.validator_registry) + 1
assert len(post_state.validator_balances) == len(state.validator_balances) + 1
assert post_state.validator_registry[index].pubkey == pubkeys[index]
assert post_state.deposit_index == post_state.latest_eth1_data.deposit_count
return pre_state, deposit, post_state
def test_success_top_up(state, deposit_data_leaves, pubkeys, privkeys):
pre_state = deepcopy(state)
validator_index = 0
amount = spec.MAX_DEPOSIT_AMOUNT // 4
pubkey = pubkeys[validator_index]
privkey = privkeys[validator_index]
deposit, root, deposit_data_leaves = build_deposit(
pre_state,
deposit_data_leaves,
pubkey,
privkey,
amount,
)
pre_state.latest_eth1_data.deposit_root = root
pre_state.latest_eth1_data.deposit_count = len(deposit_data_leaves)
pre_balance = pre_state.validator_balances[validator_index]
post_state = deepcopy(pre_state)
process_deposit(post_state, deposit)
assert len(post_state.validator_registry) == len(state.validator_registry)
assert len(post_state.validator_balances) == len(state.validator_balances)
assert post_state.deposit_index == post_state.latest_eth1_data.deposit_count
assert post_state.validator_balances[validator_index] == pre_balance + amount
return pre_state, deposit, post_state
def test_wrong_index(state, deposit_data_leaves, pubkeys, privkeys):
pre_state = deepcopy(state)
index = len(deposit_data_leaves)
pubkey = pubkeys[index]
privkey = privkeys[index]
deposit, root, deposit_data_leaves = build_deposit(
pre_state,
deposit_data_leaves,
pubkey,
privkey,
spec.MAX_DEPOSIT_AMOUNT,
)
# mess up deposit_index
deposit.index = pre_state.deposit_index + 1
pre_state.latest_eth1_data.deposit_root = root
pre_state.latest_eth1_data.deposit_count = len(deposit_data_leaves)
post_state = deepcopy(pre_state)
with pytest.raises(AssertionError):
process_deposit(post_state, deposit)
return pre_state, deposit, None
def test_bad_merkle_proof(state, deposit_data_leaves, pubkeys, privkeys):
pre_state = deepcopy(state)
index = len(deposit_data_leaves)
pubkey = pubkeys[index]
privkey = privkeys[index]
deposit, root, deposit_data_leaves = build_deposit(
pre_state,
deposit_data_leaves,
pubkey,
privkey,
spec.MAX_DEPOSIT_AMOUNT,
)
# mess up merkle branch
deposit.proof[-1] = spec.ZERO_HASH
pre_state.latest_eth1_data.deposit_root = root
pre_state.latest_eth1_data.deposit_count = len(deposit_data_leaves)
post_state = deepcopy(pre_state)
with pytest.raises(AssertionError):
process_deposit(post_state, deposit)
return pre_state, deposit, None

View File

@ -13,6 +13,10 @@ from tests.phase0.helpers import (
)
# mark entire file as 'voluntary_exits'
pytestmark = pytest.mark.voluntary_exits
def test_success(state, pub_to_priv):
pre_state = deepcopy(state)
#

View File

@ -72,12 +72,16 @@ def create_mock_genesis_validator_deposits(num_validators, deposit_data_leaves):
def create_genesis_state(num_validators, deposit_data_leaves):
initial_deposits, deposit_root = create_mock_genesis_validator_deposits(num_validators, deposit_data_leaves)
initial_deposits, deposit_root = create_mock_genesis_validator_deposits(
num_validators,
deposit_data_leaves,
)
return get_genesis_beacon_state(
initial_deposits,
genesis_time=0,
genesis_eth1_data=Eth1Data(
deposit_root=deposit_root,
deposit_count=len(initial_deposits),
block_hash=spec.ZERO_HASH,
),
)
@ -171,3 +175,27 @@ def build_voluntary_exit(state, epoch, validator_index, privkey):
)
return voluntary_exit
def build_deposit(state,
deposit_data_leaves,
pubkey,
privkey,
amount):
deposit_data = build_deposit_data(state, pubkey, privkey, amount)
item = hash(deposit_data.serialize())
index = len(deposit_data_leaves)
deposit_data_leaves.append(item)
tree = calc_merkle_tree_from_leaves(tuple(deposit_data_leaves))
root = get_merkle_root((tuple(deposit_data_leaves)))
proof = list(get_merkle_proof(tree, item_index=index))
assert verify_merkle_branch(item, proof, spec.DEPOSIT_CONTRACT_TREE_DEPTH, index, root)
deposit = Deposit(
proof=list(proof),
index=index,
deposit_data=deposit_data,
)
return deposit, root, deposit_data_leaves

View File

@ -196,6 +196,7 @@ def test_deposit_in_block(state, deposit_data_leaves, pubkeys, privkeys):
)
pre_state.latest_eth1_data.deposit_root = root
pre_state.latest_eth1_data.deposit_count = len(test_deposit_data_leaves)
post_state = deepcopy(pre_state)
block = build_empty_block_for_next_slot(post_state)
block.body.deposits.append(deposit)
@ -233,6 +234,7 @@ def test_deposit_top_up(state, pubkeys, privkeys, deposit_data_leaves):
)
pre_state.latest_eth1_data.deposit_root = root
pre_state.latest_eth1_data.deposit_count = len(test_deposit_data_leaves)
block = build_empty_block_for_next_slot(pre_state)
block.body.deposits.append(deposit)

View File

@ -15,6 +15,13 @@ from .spec import (
)
def expected_deposit_count(state: BeaconState) -> int:
return min(
spec.MAX_DEPOSITS,
state.latest_eth1_data.deposit_count - state.deposit_index
)
def process_transaction_type(state: BeaconState,
transactions: List[Any],
max_transactions: int,
@ -31,30 +38,36 @@ def process_transactions(state: BeaconState, block: BeaconBlock) -> None:
spec.MAX_PROPOSER_SLASHINGS,
spec.process_proposer_slashing,
)
process_transaction_type(
state,
block.body.attester_slashings,
spec.MAX_ATTESTER_SLASHINGS,
spec.process_attester_slashing,
)
process_transaction_type(
state,
block.body.attestations,
spec.MAX_ATTESTATIONS,
spec.process_attestation,
)
assert len(block.body.deposits) == expected_deposit_count(state)
process_transaction_type(
state,
block.body.deposits,
spec.MAX_DEPOSITS,
spec.process_deposit,
)
process_transaction_type(
state,
block.body.voluntary_exits,
spec.MAX_VOLUNTARY_EXITS,
spec.process_voluntary_exit,
)
assert len(block.body.transfers) == len(set(block.body.transfers))
process_transaction_type(
state,