Merge pull request #758 from ethereum/vbuterin-patch-11
Mandatory deposits
This commit is contained in:
commit
251f4ba0f9
|
@ -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)`.
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
#
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue