Skip to content

Commit

Permalink
Merge pull request #1466 from ethereum/decoy-flip-flop
Browse files Browse the repository at this point in the history
Decoy flip flop resistance
  • Loading branch information
djrtwo authored Nov 7, 2019
2 parents f331b55 + 9b21c0d commit e7f7188
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 5 deletions.
5 changes: 5 additions & 0 deletions specs/core/0_fork-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,11 @@ def on_block(store: Store, block: BeaconBlock) -> None:
def on_attestation(store: Store, attestation: Attestation) -> None:
target = attestation.data.target

# Attestations must be from the current or previous epoch
current_epoch = compute_epoch_at_slot(get_current_slot(store))
# Use GENESIS_EPOCH for previous when genesis to avoid underflow
previous_epoch = current_epoch - 1 if current_epoch > GENESIS_EPOCH else GENESIS_EPOCH
assert target.epoch in [current_epoch, previous_epoch]
# Cannot calculate the current shuffling if have not seen the target
assert target.root in store.blocks

Expand Down
2 changes: 2 additions & 0 deletions specs/validator/0_beacon-chain-validator.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@ A validator is expected to create, sign, and broadcast an attestation during eac

A validator should create and broadcast the `attestation` to the associated attestation subnet one-third of the way through the `slot` during which the validator is assigned―that is, `SECONDS_PER_SLOT / 3` seconds after the start of `slot`.

*Note*: Although attestations during `GENESIS_EPOCH` do not count toward FFG finality, these initial attestations do give weight to the fork choice, are rewarded fork, and should be made.

#### Attestation data

First, the validator should construct `attestation_data`, an [`AttestationData`](../core/0_beacon-chain.md#attestationdata) object based upon the state at the assigned slot.
Expand Down
52 changes: 47 additions & 5 deletions test_libs/pyspec/eth2spec/test/fork_choice/test_on_attestation.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@ def run_on_attestation(spec, state, store, attestation, valid=True):

@with_all_phases
@spec_state_test
def test_on_attestation(spec, state):
def test_on_attestation_current_epoch(spec, state):
store = spec.get_genesis_store(state)
time = 100
spec.on_tick(store, time)
spec.on_tick(store, store.time + spec.SECONDS_PER_SLOT * 2)

block = build_empty_block_for_next_slot(spec, state)
state_transition_and_sign_block(spec, state, block)
Expand All @@ -39,9 +38,53 @@ def test_on_attestation(spec, state):
spec.on_block(store, block)

attestation = get_valid_attestation(spec, state, slot=block.slot)
assert attestation.data.target.epoch == spec.GENESIS_EPOCH
assert spec.compute_epoch_at_slot(spec.get_current_slot(store)) == spec.GENESIS_EPOCH

run_on_attestation(spec, state, store, attestation)


@with_all_phases
@spec_state_test
def test_on_attestation_previous_epoch(spec, state):
store = spec.get_genesis_store(state)
spec.on_tick(store, store.time + spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH)

block = build_empty_block_for_next_slot(spec, state)
state_transition_and_sign_block(spec, state, block)

# store block in store
spec.on_block(store, block)

attestation = get_valid_attestation(spec, state, slot=block.slot)
assert attestation.data.target.epoch == spec.GENESIS_EPOCH
assert spec.compute_epoch_at_slot(spec.get_current_slot(store)) == spec.GENESIS_EPOCH + 1

run_on_attestation(spec, state, store, attestation)


@with_all_phases
@spec_state_test
def test_on_attestation_past_epoch(spec, state):
store = spec.get_genesis_store(state)

# move time forward 2 epochs
time = store.time + 2 * spec.SECONDS_PER_SLOT * spec.SLOTS_PER_EPOCH
spec.on_tick(store, time)

# create and store block from 3 epochs ago
block = build_empty_block_for_next_slot(spec, state)
state_transition_and_sign_block(spec, state, block)
spec.on_block(store, block)

# create attestation for past block
attestation = get_valid_attestation(spec, state, slot=state.slot)
assert attestation.data.target.epoch == spec.GENESIS_EPOCH
assert spec.compute_epoch_at_slot(spec.get_current_slot(store)) == spec.GENESIS_EPOCH + 2

run_on_attestation(spec, state, store, attestation, False)


@with_all_phases
@spec_state_test
def test_on_attestation_target_not_in_store(spec, state):
Expand Down Expand Up @@ -75,8 +118,7 @@ def test_on_attestation_future_epoch(spec, state):
spec.on_block(store, block)

# move state forward but not store
attestation_slot = block.slot + spec.SLOTS_PER_EPOCH
state.slot = attestation_slot
state.slot = block.slot + spec.SLOTS_PER_EPOCH

attestation = get_valid_attestation(spec, state, slot=state.slot)
run_on_attestation(spec, state, store, attestation, False)
Expand Down

0 comments on commit e7f7188

Please sign in to comment.