Merge pull request #1228 from ethereum/cov-hunt-fix-ish

Some fixes to finality tests
This commit is contained in:
Diederik Loerakker 2019-06-29 18:18:53 +02:00 committed by GitHub
commit b0510fe5e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 79 additions and 72 deletions

View File

@ -1,4 +1,3 @@
import math
from eth2spec.test.context import spec_state_test, with_all_phases
from eth2spec.test.phase_0.epoch_processing.run_epoch_process_base import (
run_epoch_processing_with
@ -17,15 +16,7 @@ def get_shards_for_slot(spec, state, slot):
return [shard + i for i in range(committees_per_slot)]
def get_committee_size(spec, epoch_start_shard, shard, committee_count, indices):
committee_index = (shard + spec.SHARD_COUNT - epoch_start_shard) % spec.SHARD_COUNT
start = (len(indices) * committee_index) // committee_count
end = (len(indices) * (committee_index + 1)) // committee_count
size = end - start
return size
def add_mock_attestations(spec, state, epoch, att_ratio, source, target):
def add_mock_attestations(spec, state, epoch, source, target, sufficient_support=False):
# we must be at the end of the epoch
assert (state.slot + 1) % spec.SLOTS_PER_EPOCH == 0
@ -39,31 +30,46 @@ def add_mock_attestations(spec, state, epoch, att_ratio, source, target):
else:
raise Exception(f"cannot include attestations in epoch ${epoch} from epoch ${current_epoch}")
committee_count = spec.get_epoch_committee_count(state, epoch)
indices = spec.get_active_validator_indices(state, epoch)
epoch_start_shard = spec.get_epoch_start_shard(state, epoch)
total_balance = spec.get_total_active_balance(state)
remaining_balance = total_balance * 2 // 3
epoch_start_slot = spec.get_epoch_start_slot(epoch)
for slot in range(epoch_start_slot, epoch_start_slot + spec.SLOTS_PER_EPOCH):
for shard in get_shards_for_slot(spec, state, slot):
size = get_committee_size(spec, epoch_start_shard, shard, committee_count, indices)
# Check if we already have had sufficient balance. (and undone if we don't want it).
# If so, do not create more attestations. (we do not have empty pending attestations normally anyway)
if remaining_balance < 0:
return
committee = spec.get_crosslink_committee(state, spec.slot_to_epoch(slot), shard)
# Create a bitfield filled with the given count per attestation,
# exactly on the right-most part of the committee field.
attesting_count = math.ceil(size * att_ratio)
aggregation_bitfield = ((1 << attesting_count) - 1).to_bytes(length=((size + 7) // 8), byteorder='big')
aggregation_bits = [0] * len(committee)
for v in range(len(committee) * 2 // 3 + 1):
if remaining_balance > 0:
remaining_balance -= state.validators[v].effective_balance
aggregation_bits[v] = 1
else:
break
# remove just one attester to make the marginal support insufficient
if not sufficient_support:
aggregation_bits[aggregation_bits.index(1)] = 0
attestations.append(spec.PendingAttestation(
aggregation_bitfield=aggregation_bitfield,
aggregation_bits=aggregation_bits,
data=spec.AttestationData(
beacon_block_root=b'\xaa' * 32,
source=source,
target=source,
crosslink=spec.Crosslink()
target=target,
crosslink=spec.Crosslink(shard=shard)
),
inclusion_delay=1,
))
def finalize_on_234(spec, state, epoch, support):
def finalize_on_234(spec, state, epoch, sufficient_support):
assert epoch > 4
state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch
@ -74,143 +80,147 @@ def finalize_on_234(spec, state, epoch, support):
c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32)
c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32)
c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32)
# c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xcc' * 32)
state.block_roots[spec.get_epoch_start_slot(c4.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c4.root
state.block_roots[spec.get_epoch_start_slot(c3.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c3.root
state.block_roots[spec.get_epoch_start_slot(c2.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c2.root
old_finalized = state.finalized_checkpoint
state.previous_justified_checkpoint = c4
state.current_justified_checkpoint = c3
bits = state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]()
bits[3:4] = [1, 1] # mock 3rd and 4th latest epochs as justified
state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]()
state.justification_bits[1:3] = [1, 1] # mock 3rd and 4th latest epochs as justified (indices are pre-shift)
# mock the 2nd latest epoch as justifiable, with 4th as source
add_mock_attestations(spec, state,
epoch=epoch - 2,
att_ratio=support,
source=c4,
target=c2)
target=c2,
sufficient_support=sufficient_support)
# process!
yield from run_process_just_and_fin(spec, state)
if support >= (2 / 3):
assert state.previous_justified_checkpoint == c3 # changed to old current
if sufficient_support:
assert state.current_justified_checkpoint == c2 # changed to 2nd latest
assert state.finalized_checkpoint == c4 # finalized old previous justified epoch
else:
assert state.previous_justified_checkpoint == c3 # changed to old current
assert state.current_justified_checkpoint == c3 # still old current
assert state.finalized_checkpoint == old_finalized # no new finalized
def finalize_on_23(spec, state, epoch, support):
def finalize_on_23(spec, state, epoch, sufficient_support):
assert epoch > 3
state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch
# 43210 -- epochs ago
# 3210x -- justification bitfield indices
# 210xx -- justification bitfield indices (pre shift)
# 3210x -- justification bitfield indices (post shift)
# 01*0. -- justification bitfield contents, . = this epoch, * is being justified now
# checkpoints for the epochs ago:
# c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32)
c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32)
c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32)
# c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xcc' * 32)
state.block_roots[spec.get_epoch_start_slot(c3.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c3.root
state.block_roots[spec.get_epoch_start_slot(c2.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c2.root
old_finalized = state.finalized_checkpoint
state.previous_justified_checkpoint = c3
state.current_justified_checkpoint = c3
bits = state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]()
bits[2] = 1 # mock 3rd latest epoch as justified
state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]()
state.justification_bits[1] = 1 # mock 3rd latest epoch as justified (indices are pre-shift)
# mock the 2nd latest epoch as justifiable, with 3rd as source
add_mock_attestations(spec, state,
epoch=epoch - 2,
att_ratio=support,
source=c3,
target=c2)
target=c2,
sufficient_support=sufficient_support)
# process!
yield from run_process_just_and_fin(spec, state)
if support >= (2 / 3):
assert state.previous_justified_checkpoint == c3 # changed to old current
if sufficient_support:
assert state.current_justified_checkpoint == c2 # changed to 2nd latest
assert state.finalized_checkpoint == c3 # finalized old previous justified epoch
else:
assert state.previous_justified_checkpoint == c3 # changed to old current
assert state.current_justified_checkpoint == c3 # still old current
assert state.finalized_checkpoint == old_finalized # no new finalized
def finalize_on_123(spec, state, epoch, support):
def finalize_on_123(spec, state, epoch, sufficient_support):
assert epoch > 3
state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch
# 43210 -- epochs ago
# 3210x -- justification bitfield indices
# 210xx -- justification bitfield indices (pre shift)
# 3210x -- justification bitfield indices (post shift)
# 011*. -- justification bitfield contents, . = this epoch, * is being justified now
# checkpoints for the epochs ago:
# c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32)
c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32)
c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32)
c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32)
c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xcc' * 32)
state.block_roots[spec.get_epoch_start_slot(c3.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c3.root
state.block_roots[spec.get_epoch_start_slot(c2.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c2.root
state.block_roots[spec.get_epoch_start_slot(c1.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c1.root
old_finalized = state.finalized_checkpoint
state.previous_justified_checkpoint = c3
state.previous_justified_checkpoint = c4 # not c3, otherwise finalize 23 would trigger.
state.current_justified_checkpoint = c2
bits = state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]()
bits[1:2] = [1, 1] # mock 2rd and 3th latest epochs as justified
state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]()
state.justification_bits[0:2] = [1, 1] # mock 2nd and 3rd latest epochs as justified (indices are pre-shift)
# mock the 1st latest epoch as justifiable, with 3rd as source
add_mock_attestations(spec, state,
epoch=epoch - 1,
att_ratio=support,
source=c3,
target=c1)
target=c1,
sufficient_support=sufficient_support)
# process!
yield from run_process_just_and_fin(spec, state)
if support >= (2 / 3):
assert state.previous_justified_checkpoint == c2 # changed to old current
if sufficient_support:
assert state.current_justified_checkpoint == c1 # changed to 1st latest
assert state.finalized_checkpoint == c2 # finalized old current
else:
assert state.previous_justified_checkpoint == c2 # changed to old current
assert state.current_justified_checkpoint == c2 # still old current
assert state.finalized_checkpoint == old_finalized # no new finalized
def finalize_on_12(spec, state, epoch, support):
def finalize_on_12(spec, state, epoch, sufficient_support):
assert epoch > 2
state.slot = (spec.SLOTS_PER_EPOCH * epoch) - 1 # skip ahead to just before epoch
# 43210 -- epochs ago
# 3210 -- justification bitfield indices
# 210xx -- justification bitfield indices (pre shift)
# 3210x -- justification bitfield indices (post shift)
# 001*. -- justification bitfield contents, . = this epoch, * is being justified now
# checkpoints for the epochs ago:
# c4 = spec.Checkpoint(epoch=epoch - 4, root=b'\xaa' * 32)
# c3 = spec.Checkpoint(epoch=epoch - 3, root=b'\xaa' * 32)
c2 = spec.Checkpoint(epoch=epoch - 2, root=b'\xbb' * 32)
c1 = spec.Checkpoint(epoch=epoch - 1, root=b'\xcc' * 32)
state.block_roots[spec.get_epoch_start_slot(c2.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c2.root
state.block_roots[spec.get_epoch_start_slot(c1.epoch) % spec.SLOTS_PER_HISTORICAL_ROOT] = c1.root
old_finalized = state.finalized_checkpoint
state.previous_justified_checkpoint = c2
state.current_justified_checkpoint = c2
bits = state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]()
bits[3] = 1 # mock 3rd latest epoch as justified
state.justification_bits = spec.Bitvector[spec.JUSTIFICATION_BITS_LENGTH]()
state.justification_bits[0] = 1 # mock 2nd latest epoch as justified (this is pre-shift)
# mock the 1st latest epoch as justifiable, with 2nd as source
add_mock_attestations(spec, state,
epoch=epoch - 1,
att_ratio=support,
source=c2,
target=c1)
target=c1,
sufficient_support=sufficient_support)
# process!
yield from run_process_just_and_fin(spec, state)
if support >= (2 / 3):
assert state.previous_justified_checkpoint == c2 # changed to old current
if sufficient_support:
assert state.current_justified_checkpoint == c1 # changed to 1st latest
assert state.finalized_checkpoint == c2 # finalized previous justified epoch
else:
assert state.previous_justified_checkpoint == c2 # changed to old current
assert state.current_justified_checkpoint == c2 # still old current
assert state.finalized_checkpoint == old_finalized # no new finalized
@ -218,49 +228,46 @@ def finalize_on_12(spec, state, epoch, support):
@with_all_phases
@spec_state_test
def test_234_ok_support(spec, state):
yield from finalize_on_234(spec, state, 5, 1.0)
yield from finalize_on_234(spec, state, 5, True)
@with_all_phases
@spec_state_test
def test_234_poor_support(spec, state):
yield from finalize_on_234(spec, state, 5, 0.6)
yield from finalize_on_234(spec, state, 5, False)
@with_all_phases
@spec_state_test
def test_23_ok_support(spec, state):
yield from finalize_on_23(spec, state, 4, 1.0)
yield from finalize_on_23(spec, state, 4, True)
@with_all_phases
@spec_state_test
def test_23_poor_support(spec, state):
yield from finalize_on_23(spec, state, 4, 0.6)
yield from finalize_on_23(spec, state, 4, False)
@with_all_phases
@spec_state_test
def test_123_ok_support(spec, state):
yield from finalize_on_123(spec, state, 4, 1.0)
yield from finalize_on_123(spec, state, 4, True)
@with_all_phases
@spec_state_test
def test_123_poor_support(spec, state):
yield from finalize_on_123(spec, state, 4, 0.6)
yield from finalize_on_123(spec, state, 4, False)
@with_all_phases
@spec_state_test
def test_12_ok_support(spec, state):
yield from finalize_on_12(spec, state, 3, 1.0)
yield from finalize_on_12(spec, state, 3, True)
@with_all_phases
@spec_state_test
def test_12_poor_support(spec, state):
yield from finalize_on_12(spec, state, 3, 0.6)
# TODO: bring ratios closer to 2/3 for edge case testing.
yield from finalize_on_12(spec, state, 3, False)