Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ensure can't undo progress with eth1data voting #1836

Merged
merged 2 commits into from
May 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,10 @@ def get_eth1_data(block: Eth1Block) -> Eth1Data:
"""
A stub function return mocking Eth1Data.
"""
return Eth1Data(block_hash=hash_tree_root(block))
return Eth1Data(
deposit_root=block.deposit_root,
deposit_count=block.deposit_count,
block_hash=hash_tree_root(block))


def hash(x: bytes) -> Bytes32: # type: ignore
Expand Down
14 changes: 11 additions & 3 deletions specs/phase0/validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,13 @@ The `block.body.eth1_data` field is for block proposers to vote on recent Eth1 d

###### `Eth1Block`

Let `Eth1Block` be an abstract object representing Eth1 blocks with the `timestamp` field available.
Let `Eth1Block` be an abstract object representing Eth1 blocks with the `timestamp` and depost contract data available.

```python
class Eth1Block(Container):
timestamp: uint64
deposit_root: Root
deposit_count: uint64
# All other eth1 block fields
```

Expand Down Expand Up @@ -289,8 +291,14 @@ def is_candidate_block(block: Eth1Block, period_start: uint64) -> bool:
def get_eth1_vote(state: BeaconState, eth1_chain: Sequence[Eth1Block]) -> Eth1Data:
period_start = voting_period_start_time(state)
# `eth1_chain` abstractly represents all blocks in the eth1 chain sorted by ascending block height
votes_to_consider = [get_eth1_data(block) for block in eth1_chain if
is_candidate_block(block, period_start)]
votes_to_consider = [
get_eth1_data(block) for block in eth1_chain
if (
is_candidate_block(block, period_start)
# Ensure cannot move back to earlier deposit contract states
and get_eth1_data(block).deposit_count >= state.eth1_data.deposit_count
)
]

# Valid votes already cast during this period
valid_votes = [vote for vote in state.eth1_data_votes if vote in votes_to_consider]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,16 @@ def test_get_eth1_vote_consensus_vote(spec, state):
assert votes_length >= 3 # We need to have the majority vote
state.eth1_data_votes = ()

block_1 = spec.Eth1Block(timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE - 1)
block_2 = spec.Eth1Block(timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE)
block_1 = spec.Eth1Block(
timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE - 1,
deposit_count=state.eth1_data.deposit_count,
deposit_root=b'\x04' * 32,
)
block_2 = spec.Eth1Block(
timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE,
deposit_count=state.eth1_data.deposit_count + 1,
deposit_root=b'\x05' * 32,
)
eth1_chain = [block_1, block_2]
eth1_data_votes = []

Expand All @@ -218,8 +226,16 @@ def test_get_eth1_vote_tie(spec, state):
assert votes_length > 0 and votes_length % 2 == 0

state.eth1_data_votes = ()
block_1 = spec.Eth1Block(timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE - 1)
block_2 = spec.Eth1Block(timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE)
block_1 = spec.Eth1Block(
timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE - 1,
deposit_count=state.eth1_data.deposit_count,
deposit_root=b'\x04' * 32,
)
block_2 = spec.Eth1Block(
timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE,
deposit_count=state.eth1_data.deposit_count + 1,
deposit_root=b'\x05' * 32,
)
eth1_chain = [block_1, block_2]
eth1_data_votes = []
# Half votes are for block_1, another half votes are for block_2
Expand All @@ -237,6 +253,33 @@ def test_get_eth1_vote_tie(spec, state):
assert eth1_data.block_hash == eth1_chain[0].hash_tree_root()


@with_all_phases
@spec_state_test
def test_get_eth1_vote_chain_in_past(spec, state):
min_new_period_epochs = get_min_new_period_epochs(spec)
for _ in range(min_new_period_epochs + 1):
next_epoch(spec, state)

period_start = spec.voting_period_start_time(state)
votes_length = spec.get_current_epoch(state) % spec.EPOCHS_PER_ETH1_VOTING_PERIOD
assert votes_length > 0 and votes_length % 2 == 0

state.eth1_data_votes = ()
block_1 = spec.Eth1Block(
timestamp=period_start - spec.SECONDS_PER_ETH1_BLOCK * spec.ETH1_FOLLOW_DISTANCE,
deposit_count=state.eth1_data.deposit_count - 1, # Chain prior to current eth1data
deposit_root=b'\x42' * 32,
)
eth1_chain = [block_1]
eth1_data_votes = []

state.eth1_data_votes = eth1_data_votes
eth1_data = spec.get_eth1_vote(state, eth1_chain)

# Should be default vote
assert eth1_data == state.eth1_data


@with_all_phases
@spec_state_test
def test_compute_new_state_root(spec, state):
Expand Down